Publicidade

🔦 Aula 12: Travado? dê printf em toda variável

Transforme o tempo que você gasta olhando o código em tempo vendo os valores das variáveis. A habilidade de depuração mais prática para iniciantes.

📖 O que aprender nesta página
✅ Essencial saber
  • Não entender = não ver os valores
  • Na dúvida: printf("x=%d\n", x);
  • Coloque dentro de laços, na entrada/saída de funções
⭐ Leia se tiver tempo
  • Marque linhas de debug com [DEBUG] para dar grep depois
  • Cuidado com buffering de saída (sempre \n)
  • Evolua para gdb / lldb / depuradores de IDE quando ficar fluente

Por que depuração com printf é a ferramenta mais forte — 90% dos iniciantes empacam aqui

Este é o padrão que derruba a maioria dos iniciantes:
ficar olhando o código e tentar executá-lo na cabeça, e depois travar quando não consegue descobrir.
🔴 Abordagem errada
A falha fatal: nenhum cérebro humano consegue acompanhar cinco ou seis variáveis ao mesmo tempo. Adicione um laço ou desvio e tudo desmorona. Olhar para o código = desistir.
✅ Abordagem certa
Deixe o computador te mostrar os valores. Só isso.
// Coloque printfs em qualquer lugar suspeito.
printf("[DEBUG] i=%d, sum=%d\n", i, sum);
Dez printfs levam três minutos. Esses três minutos te dão a mesma informação que uma hora olhando a tela. Essa é a maior diferença entre iniciantes e profissionais.
🎯 Profissionais fazem o mesmo: engenheiros seniores usam depuradores de IDE ou gdb, mas a atividade central — "observar valores de variáveis ao vivo" — é idêntica. printf é só a forma mais amigável de começar.

Onde colocar printfs — os três padrões de ouro

Padrão ①: dentro de laços — imprima a cada iteração
for (int i = 0; i < 5; i++) {
    sum = sum + arr[i];
    printf("[DEBUG] i=%d, arr[i]=%d, sum=%d\n", i, arr[i], sum);  // ← isso
}
Laços são onde as coisas saem dos trilhos. Imprimir o estado a cada iteração identifica exatamente qual passagem quebrou.
Padrão ②: entrada e saída de função
int calc(int a, int b) {
    printf("[DEBUG] entrada calc: a=%d, b=%d\n", a, b);
    int result = a * 2 + b;
    printf("[DEBUG] saida calc: result=%d\n", result);
    return result;
}
Veja o que entrou e o que sai. Isso te diz na hora se o bug mora dentro da função ou no chamador.
Padrão ③: ao redor de ramos if
printf("[DEBUG] antes do teste: score=%d\n", score);
if (score >= 60) {
    printf("[DEBUG] ramo aprovado\n");
    printf("Aprovado\n");
} else {
    printf("[DEBUG] ramo reprovado\n");
    printf("Reprovado\n");
}
99% dos bugs "por que meu ramo não está sendo executado?" se resumem a a variável da condição não estar com o valor que você achava. Imprima ela logo antes do teste.
💡 Na dúvida: dê printf em toda variável que pode estar errada. Exagero está OK — você vai deletar depois.

Antes / Depois — mesmo bug, sofrimento bem diferente

Um bug clássico: "somar de 1 a 10 deveria dar 55, mas estou tendo 45." Vamos comparar as duas abordagens de depuração.
😩 Antes: sem printfs
int sum = 0;
for (int i = 1; i < 10; i++) {
    sum = sum + i;
}
printf("Soma = %d\n", sum);
// Saida: Soma = 45
// "Ué, nao deveria ser 55?"
// ...encara o codigo por 10 minutos...
// ...ainda sem entender...
Tempo perdido: 10–60 min
😌 Depois: adicione printfs
int sum = 0;
for (int i = 1; i < 10; i++) {
    sum = sum + i;
    printf("[D] i=%d sum=%d\n", i, sum);
}
printf("Soma = %d\n", sum);
// Saida:
// [D] i=1 sum=1
// [D] i=2 sum=3
// ...
// [D] i=9 sum=45    ← i para em 9, nao 10!
// Soma = 45
Tempo gasto: 30 seg → mudar i<10 para i<=10
A diferença: printfs te dão o fato concreto "i foi até 9". Sem eles, a distinção entre i < 10 e i <= 10 fica nebulosa na cabeça, e o bug nunca é corrigido.

Cheat sheet de especificadores de formato

Tipos diferentes precisam de especificadores diferentes. Copie daqui quando tiver dúvida.
📌 Na Aula 12, você só precisa dos dois primeiros (%d e %f).
char, strings, ponteiros e hex são cobertos em aulas posteriores (Strings, Ponteiros, Bit a bit etc.). Por ora, int → %d, double → %f é tudo que você precisa.
TipoEspecificadorExemploSaída
int ★ use agora%dprintf("%d", x)42
float / double ★ use agora%fprintf("%.2f", z)3.14
long%ldprintf("%ld", y)1234567890
char depois%cprintf("%c", c)A
char[] / string depois%sprintf("%s", s)Hello
ponteiro/endereço depois%pprintf("%p", p)0x7ffee...
hex depois%xprintf("%x", n)ff
💡 Template mais rápido: cole printf("[D] var1=%d var2=%d\n", var1, var2); onde precisar e troque pelos nomes das suas variáveis. Não esqueça do \n (veja a próxima seção).

Armadilhas e limpeza

🔴 Armadilha ①: um \n faltando atrasa sua saída
O printf faz buffering da saída por eficiência e só libera numa nova linha \n (line buffering).
printf("[D] cheguei aqui");   // ← sem \n → nao aparece nada na tela ainda!
// Se o programa crashar depois dessa linha, voce vai concluir
// "nunca chegamos nesse ponto" — mesmo tendo chegado.
Correção: sempre termine printfs de debug com \n, ou chame fflush(stdout); logo depois.
⚠️ Armadilha ②: o especificador errado imprime lixo
double x = 3.14;
printf("%d\n", x);    // ❌ %d eh para int — comportamento indefinido
Correção: confira a tabela acima, e compile com -Wall para o compilador avisar sobre incompatibilidades.
🧹 Limpeza — remova antes de commitar
Quando o bug for corrigido, remova todo printf de debug. Deixar eles atrasa a leitura do código e pode inundar logs em produção.
💡 Torne-os fáceis de achar: sempre marque prints de debug com [DEBUG] ou [D]. Assim um único grep por [D] encontra todos.
🚀 Próximo passo: quando ficar confortável com printf, passe para Técnicas de Depuração e o guia prático de gdb. Poder pausar e inspecionar variáveis interativamente dobra ou triplica sua velocidade.
Publicidade

Aulas Relacionadas

Introdução
printf e scanf
Uma revisão dos fundamentos dos especificadores.
Laços e arrays
Técnicas de Depuração
Estratégias mais profundas de depuração e padrões comuns de bugs.
Tópicos avançados
Guia prático do gdb
O próximo passo natural — inspeção interativa de variáveis.
← Anterior
Comparação e Lógicos
Próxima →
Instrução if

Teste de Revisão

Teste seu entendimento desta aula!

Q1. Qual especificador de formato imprime uma variável int em decimal?

%d
%f
%s

%d é para inteiros decimais, %f é para ponto flutuante, e %s é para strings.

Q2. Qual sequência de escape representa uma quebra de linha?

\n
/n
\r apenas

\n é nova linha, \t é tabulação e \\ é uma barra invertida literal.

Q3. Qual especificador de formato é apropriado para imprimir um endereço de ponteiro?

%p
%a
%d

%p formata um void * como hexadecimal com segurança. Usar %d é definido pela implementação e inseguro.