Por que programas precisam de ramos
Todo programa até aqui executou em linha reta: linha 1, linha 2, linha 3. Programas de verdade tomam decisões. A senha está correta? O número é negativo? O arquivo abriu? A instrução if é como C faz uma pergunta e executa código apenas quando a resposta é sim.
A condição temperature > 30 é testada uma vez. Ela vale, então a mensagem é impressa. A última linha está fora das chaves, então ela é impressa aconteça o que acontecer. Mude 31 para 18 e rode de novo - a primeira mensagem some e a segunda fica.
Sintaxe: parênteses, chaves e nenhum ponto e vírgula
Um if em C tem um formato fixo:
if (condition) {
// executa quando a condição é diferente de zero
}
Três regras que vale memorizar cedo. Os parênteses em volta da condição são obrigatórios. Não existe palavra-chave then. E não há ponto e vírgula depois do parêntese de fechamento - um ponto e vírgula perdido encerra a instrução bem ali:
// BUG: o if não faz nada; o printf sempre executa
if (x > 10);
{
printf("grande\n");
}
Isso compila limpo. O ; é uma instrução vazia que se torna o corpo do if, e as chaves abaixo são apenas um bloco autônomo que sempre executa. Compilar com gcc -Wall pega o problema.
As chaves em si são opcionais para uma única instrução, mas deixe-as. Um if sem chaves que depois ganha uma segunda linha é uma fonte clássica de bugs, porque a indentação não agrupa instruções em C.
else e else if
else fornece o outro caminho:
Para mais de dois resultados, encadeie com else if. C verifica cada condição em ordem e para na primeira que vale:
A ordem importa enormemente aqui. Como a cadeia para na primeira correspondência, o segundo teste só vê pontuações abaixo de 90 - e é por isso que score >= 80 não precisa dizer também && score < 90. Escreva a cadeia da condição mais restritiva para a menos restritiva, ou todo valor cai no primeiro ramo.
O else final é opcional. Inclua um sempre que a cadeia deva cobrir todos os casos; a ausência dele significa "se nada correspondeu, não faça nada", o que está tudo bem mas deve ser deliberado.
Veracidade: 0 é falso, todo o resto é verdadeiro
A linguagem básica de C não tem um tipo booleano separado nas condições. Um if simplesmente pergunta se a expressão é diferente de zero.
As duas últimas linhas mostram a outra metade da regra: operadores de comparação são expressões comuns que produzem 1 para verdadeiro e 0 para falso. É por isso que if (5 > 2) funciona - na verdade é if (1).
É também por isso que -3 é verdadeiro em C. A regra é diferente de zero, não positivo. Se você quer saber se um número é positivo, escreva if (n > 0), não if (n).
O C99 acrescentou <stdbool.h> com um tipo bool de verdade mais true e false, o que se lê melhor em código novo. Por baixo dos panos eles continuam sendo 1 e 0, então nada da regra acima muda - veja Booleanos em C.
Os operadores de comparação e lógicos que você vai usar em condições:
== igual a && E lógico (os dois lados verdadeiros)
!= diferente de || OU lógico (qualquer um dos lados)
< menor que ! NÃO lógico
> maior que
<= menor ou igual a
>= maior ou igual a
&& e || fazem curto-circuito: a && b nunca avalia b se a for falso, e a || b nunca avalia b se a for verdadeiro. Isso é uma garantia, não uma otimização, então é seguro escrever if (n != 0 && total / n > 5) - a divisão não pode executar quando n é zero.
O bug de = vs ==
Este é, isoladamente, o erro mais comum em condições em C:
// BUG: atribui 5 a x, depois testa 5 (diferente de zero), então isto SEMPRE executa
if (x = 5) {
printf("x e cinco\n");
}
C permite atribuição dentro de uma expressão, então a linha é legal. Ela guarda 5 em x, produz o valor 5, e 5 é diferente de zero - o ramo executa todas as vezes, e x foi sobrescrito silenciosamente.
Duas defesas. Primeiro, sempre compile com os avisos ligados:
gcc -Wall -Wextra program.c -o program
GCC e clang ambos sinalizam "suggest parentheses around assignment used as truth value". Segundo, alguns programadores escrevem a constante antes da variável - if (5 == x) - para que um if (5 = x) digitado por engano seja um erro de compilação duro em vez de um bug silencioso. Esse estilo é questão de gosto; ligar os avisos não é.
Aninhamento
Um if pode conter outro if. Aninhar expressa condições que só fazem sentido depois que uma anterior vale:
Dois níveis são legíveis. Quatro não são. Quando o aninhamento fica fundo, procure um jeito de achatá-lo - muitas vezes combinando condições com &&, ou tratando os casos de falha primeiro e retornando cedo:
// mais achatado: trate as exceções, depois siga com o trabalho
if (age < 18) { printf("Apenas para adultos.\n"); return 0; }
if (!hasTicket) { printf("Por favor, compre um ingresso.\n"); return 0; }
printf("Bem-vindo.\n");
O else pendurado
Quando um if sem chaves é aninhado dentro de outro, a qual if um else pertence? A regra de C: um else se liga ao if não pareado mais próximo, independentemente de como o código está indentado.
// O else pertence ao if INTERNO, apesar da indentação
if (a > 0)
if (b > 0)
printf("ambos positivos\n");
else
printf("a nao e positivo\n"); // ERRADO - executa quando a > 0 e b <= 0
A indentação diz que o else se emparelha com o if externo. O compilador o emparelha com o interno. As chaves removem a ambiguidade por completo, o que é o verdadeiro argumento para sempre usá-las:
if (a > 0) {
if (b > 0) {
printf("ambos positivos\n");
}
} else {
printf("a nao e positivo\n");
}
O operador ternário
Quando um ramo existe só para escolher um valor, o operador condicional ? : diz isso em uma expressão:
Leia cond ? x : y como "se cond então x senão y". Exatamente um dos dois ramos é avaliado, e o conjunto todo produz um valor - que é por que ele pode ser atribuído ou passado como argumento onde uma instrução não poderia.
Guarde-o para escolhas simples de valor. Ternários aninhados (a ? b : c ? d : e) são legais e quase sempre mais difíceis de ler do que a cadeia de else if que eles substituem.
Perguntas frequentes
Como se escreve uma instrução if else em C?
Coloque a condição entre parênteses e o código entre chaves: if (score >= 60) { printf("Passou\n"); } else { printf("Reprovou\n"); }. O bloco else executa apenas quando a condição é falsa, e não existe palavra-chave then em C.
O que conta como verdadeiro em um if em C?
Qualquer valor que não seja zero. C não tem um tipo booleano dedicado em sua sintaxe básica, então if (n) executa quando n é qualquer coisa exceto 0, e if (!n) executa apenas quando n é exatamente 0. Operadores de comparação como == e < produzem 1 para verdadeiro e 0 para falso.
Qual é a diferença entre = e == em C?
== compara, = atribui. Escrever if (x = 5) atribui 5 a x e então testa 5, que é diferente de zero, então o ramo sempre executa. Isso compila sem erro, e é por isso que é o bug de iniciante mais comum em condições em C - a maioria dos compiladores avisa sobre ele com -Wall.
Como funciona o operador ternário em C?
condição ? valorSeVerdadeiro : valorSeFalso é uma expressão que produz um de dois valores, então pode ficar dentro de uma atribuição ou de um argumento de printf: int max = a > b ? a : b;. Use-o para escolher um valor, e um if comum quando você precisa executar instruções.