Comandos Da Linguagem C - Listas de Comandos da Linguagem C com suas traduções | C (Linguagem de ...
Listas de Comandos da Linguagem C com suas traduções | C (Linguagem de ...

O básico que todo mundo ensina (e o que funciona na prática)

Se você está chegando agora em C, a primeira coisa que encontra é uma lista gigante de comandos. scanf, printf, if, for, while, malloc, fclose, e por aí vai. A questão é que saber o que cada um significa é só o começo. O problema real aparece quando você tenta juntar tudo num programa que funciona de verdade. Acho que a maioria das pessoas subestima como o comportamento de alguns comandos depende do compilador e do sistema operacional. Eu já perdi um dia inteiro caçando um bug que só acontecia no Linux e não no Windows. Era um simples uso de strlen com ponteiro não inicializado. O GCC deixava passar, o clang dava warning, mas só rodando no servidor é que o processo quebrava mesmo.

comandos da linguagem c que realmente importam

Vou separar por categorias pra facilitar, mas sem a intenção de ser exaustivo. O que segue são os que você realmente vai usar no dia a dia.

Entrada e saída de dados

printf e scanf são os mais óbvios. O primeiro imprime na tela, o segundo lê do teclado. A pegadinha é que scanf tem um comportamento que muita gente não espera. Quando você faz scanf("%d", &var), o caractere de nova linha que você aperta depois do número fica bufado no stream de entrada. Se na sequência você tentar ler uma string com fgets ou gets, ele vai consumir esse newline e pular a leitura. Uma workaround simples é colocar um espaço antes do especificador no scanf: scanf(" %c", &ch). O espaço faz com que ele consuma todos os caracteres em branco até encontrar algo útil. Parece besteira, mas já vi muita gente perdendo horas por causa disso.

Para saída mais complexa, fprintf escreve em arquivos e fscanf lê de arquivos. A sintaxe é idêntica, só muda o primeiro argumento, que passa a ser um ponteiro para FILE. Também existe puts, que imprime uma string seguida de newline automaticamente, e gets, que é obsoleto e não deve ser usado nunca. Sim, o gets ainda existe em algumas bases legadas. Evite.

Controle de fluxo

if, else if, else — não tem muito segredo aqui. O que as pessoas esquecem é que expressões em C avaliam para zero (falso) ou diferente de zero (verdadeiro). Isso significa que strcmp, por exemplo, retorna zero quando as strings são iguais. Se você escrever if(strcmp(a, b)), está dizendo "se as strings forem iguais, execute", o que é exatamente o oposto do que a maioria espera. Para loops, for é o mais comum, mas o while e o do...while têm seus usos. O do...while executa pelo menos uma vez, o que pode ser útil quando você precisa validar entrada do usuário e quer mostrar o prompt antes de checar a condição.

break e continue controlam a execução dentro de loops. Break sai do loop completamente. Continue pula para a próxima iteração. Tem gente que usa break como forma de sair de condições aninhadas, mas isso fica ilegível rápido. Prefira funções menores. Um ponto que pouca gente menciona: o operador switch em C não faz fall-through automático se você esquecer o break. Na verdade, o fall-through é o comportamento padrão. Se você colocar case 1: e não tiver break, o código continua executando no case 2 mesmo que a condição original fosse 1. Isso foi feito propositalmente no design da linguagem. Serve para casos como categorias que compartilham o mesmo tratamento. Mas a maioria dos bugs de switch vem de gente esquecendo o break.

Alocação dinâmica de memória

Aqui é onde o bicho pega de verdade. malloc, calloc, realloc e free são os comandos paraGerenciar memória no heap. malloc(size) aloca um bloco de 'size' bytes. calloc(n, size) aloca n elementos de size bytes cada e já zera a memória. realloc(ptr, newSize) redimensiona um bloco existente. free(ptr) devolve a memória ao sistema.

O problema é que malloc pode retornar NULL se não houver memória suficiente. Se você não verificar o retorno, vai ter um segmentation fault na primeira operação com esse ponteiro. Eu costumo colocar uma verificação logo após cada chamada. Gasta duas linhas a mais, mas economiza horas de debug. Um detalhe importante: free não zera o ponteiro. Depois de free(ptr), ptr ainda aponta para o mesmo endereço de memória, só que esse espaço agora é inválido. Se você acessar ptr depois do free, está fazendo uso de memória desalocada, o que é undefined behavior. O compilador não vai te avisar. O programa pode até funcionar às vezes, porque o conteúdo ainda está lá fisicamente, só que outro trecho do código pode ter sobrescrito.

Eu já me deparei com um caso em que um vetornão inicializado causava problemas só em produção. Em desenvolvimento, com debug builds, o compilador preenchia a memória com zeros. Em release, não. A solução foi inicializar tudo explicitamente e parar de confiar no comportamento do runtime.

Ponteiros e arrays

Ponteiros em C não são um comando, mas dominar eles é obrigatório. Um ponteiro armazena o endereço de outra variável. O operador & retorna o endereço. O operador * dereferenceia. Arrays em C são essencialmente ponteiros constantes. Quando você declara int arr[10], o nome arr é um ponteiro para o primeiro elemento. Isso significa que arr[5] é exatamente o mesmo que *(arr + 5). A diferença é que você não pode fazer arr++ porque arr é constante. Um ponteiro normal, sim.

👉 Clique no botão abaixo para saber mais sobre o assunto!

Passar arrays para funções é sempre por referência. A função recebe o ponteiro, não uma cópia. Isso é eficiente, mas perigoso se você não tiver cuidado. Modificar o array dentro da função modifica o original. Se quiser evitar isso, copie os dados antes de passar.

Estruturas de dados

struct permite agrupar dados de tipos diferentes. typedef cria um alias para um tipo, o que facilita muito a leitura do código. Combinados, ficam algo como typedef struct { ... } Nome; Um erro comum é tentar comparar structs inteiras com ==. Em C, isso compara os endereços, não o conteúdo. Para comparar structs, você precisa escrever uma função que compare campo por campo, ou usar memcpy e memcmp com cuidado.

Vetores dinâmicos não existem nativamente em C. Se você precisa de uma lista que cresce, tem que implementar usando realloc. Eu tenho uma função utilitária minha que redimensiona arrays com crescimento geométrico (dobra o tamanho). Funciona bem para a maioria dos casos, mas em cenários com milhões de inserções o custo do realloc pode ser significativo. Aí vale a pena pré-alocar com um tamanho estimado.

Arquivos

fopen, fclose, fread, fwrite, fgets, fputs — o conjunto completo para manipulação de arquivos. O modo de abertura do fopen é crítico. "r" só lê, "w" sobrescreve, "a" adiciona ao final, "r+" lê e escreve, "w+" lê e escreve mas sobrescreve. Um erro comum é abrir um arquivo com "w" achando que está apenas lendo, e na verdade está zerando o conteúdo antes de começar.

Sempre feche os arquivos. Esquecer um fclose vaza recursos do sistema operacional. Em programas pequenos isso não importa muito, mas em servidores que processam milhares de arquivos por dia, os descritores de arquivo se esgotam.

Preprocessador

#include, #define, #ifdef, #ifndef — são diretivas que o preprocessador processa antes da compilação. Eles não são comandos executáveis, mas sem eles nada funciona. #define é muitas vezes usado para constantes, mas typedef é preferível para tipos. #define não respeita escopo e pode causar conflitos. Já vi macros com o mesmo nome em headers diferentes que entravam em conflito durante o build, gerando erros confusos que levavam horas pra rastrear.

#ifdef é útil para conditional compilation. Muito usado em cross-platform development. Se seu código roda em Linux e Windows, você pode isolar trechos específicos de cada plataforma com macros de preprocessador.

O que a maioria dos tutoriais não conta

Primeiro: C não tem exceções. Se algo der errado, você lida com retornos de erro manualmente. Funções que podem falhar geralmente retornam -1 ou NULL. Verificar cada retorno é tedioso mas necessário. Segundo: o padrão da linguagem muda. C89, C99, C11, C17, C23. Cada versão adiciona recursos novos. printf com especificadores de precisão variável, bool, _Static_assert, e outras coisas só estão disponíveis em versões mais recentes. Se você escreve código portável, precisa decidir qual padrão vai targetear e garantir que o compilador suporte.

Terceiro: o comportamento de alguns comandos é indefinido em certas circunstâncias. Acesso fora dos limites de um array, divisão por zero, ponteiro null dereferenciado, integer overflow com signed types. O compilador não vai te proteger. O programa simplesmente faz algo imprevisível. Ferramentas como AddressSanitizer e Valgrind ajudam a detectar essas situações, mas elas não são padrão do dia a dia da maioria dos desenvolvedores. Se você está começando agora, comece com os básicos: scanf, printf, if, for, while, arrays, ponteiros simples, structs básicas. Não tente pular para alocação dinâmica antes de dominar ponteiros. A maioria dos problemas que iniciantes têm vem de não entender bem como endereços e memória funcionam.

Compiladores gratuitos: GCC para Linux e macOS, MinGW para Windows, Clang também funciona em várias plataformas. A maioria dos IDEs modernos tem suporte integrado. O código-fonte dos comandos não precisa ser baixado — eles fazem parte da linguagem e da biblioteca padrão. Se quiser algo mais moderno que C mas com controle similar de memória, considere Rust. Mas se o objetivo é aprender os fundamentos de como computadores realmente funcionam, C continua sendo a melhor escolha.