C else if
O if com else escolhe entre dois caminhos. Mas muitas decisões têm mais opções: a nota vira conceito A, B, C ou D; a velocidade está dentro do limite, dá multa leve ou multa grave; o desconto é de 5, 10 ou 15%. Para isso, você encadeia perguntas com else if ("senão, se"). Nesta aula você vai montar essas cadeias, descobrir por que a ordem das perguntas muda o resultado e conhecer o famoso else pendurado.
- Como escolher entre vários caminhos com
if…else if…else. - Por que só um bloco roda, e por que a ordem das perguntas importa.
- A diferença entre uma cadeia de
else ife váriosifseparados. - Como acertar as fronteiras das faixas (
>ou>=?) e tratar os valores inválidos primeiro. - O que é o else pendurado e o aviso
-Wdangling-else.
Todos os programas desta aula foram compilados com o gcc 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/c, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -o programa.
A ideia: a triagem do pronto-socorro
No pronto-socorro, a enfermeira faz perguntas em ordem: "Está inconsciente?" Se sim, sala vermelha, e acabou. Senão: "Está sangrando muito?" Se sim, sala laranja, e acabou. Senão: "Tem febre alta?" Se sim, sala amarela. Senão: sala verde.
Duas coisas importam nessa fila de perguntas:
- Assim que uma resposta é "sim", as outras perguntas nem são feitas. Cada paciente vai para uma sala só.
- A ordem importa: as perguntas mais graves vêm primeiro.
A cadeia de else if funciona exatamente assim.
1. O boletim: conceitos A, B, C e D
A escola da Ana transforma a nota em conceito: 9 ou mais é A; 7 ou mais, B; 5 ou mais, C; abaixo disso, D.
#include <stdio.h>
int main(void) {
double nota = 0;
printf("Nota: ");
if (scanf("%lf", ¬a) != 1) {
return 1;
}
if (nota >= 9) {
printf("Conceito A\n");
} else if (nota >= 7) {
printf("Conceito B\n");
} else if (nota >= 5) {
printf("Conceito C\n");
} else {
printf("Conceito D\n");
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra conceito.c -o conceito $ ./conceito Nota: 9.5 Conceito A « a primeira pergunta já deu sim $ ./conceito Nota: 7 Conceito B « 7 >= 9? não. 7 >= 7? sim $ ./conceito Nota: 6.9 Conceito C $ ./conceito Nota: 3 Conceito D « nenhuma pergunta deu sim: rodou o else
- if (nota >= 9)
- A primeira pergunta. Se der sim, mostra "A" e pula todo o resto da cadeia.
- } else if (nota >= 7) {
- "Senão, se…": só é perguntado se a anterior deu não. Repare que não precisa escrever
nota < 9 && nota >= 7: se o programa chegou aqui, já sabe que a nota é menor que 9. - } else if (nota >= 5) {
- Você pode encadear quantos
else ifquiser. - } else {
- O "senão" final, sem condição: pega tudo o que sobrou. É opcional, mas quase sempre útil.
Siga a nota 6.9 pela cadeia: 6.9 >= 9? Não. 6.9 >= 7? Não. 6.9 >= 5? Sim: mostra "C" e sai. O else do fim nem é olhado.
else if não é uma palavra nova
O C não tem uma palavra elseif. O else if é só um else cujo bloco é outro if. As duas formas abaixo são iguais; a da direita, com chaves e recuo "de verdade", vai ficando cada vez mais torta para a direita, e por isso todo mundo escreve a da esquerda:
| Como se escreve | O que o C entende |
|---|---|
if (nota >= 9) {
printf("A\n");
} else if (nota >= 7) {
printf("B\n");
} else {
printf("C\n");
} | if (nota >= 9) {
printf("A\n");
} else {
if (nota >= 7) {
printf("B\n");
} else {
printf("C\n");
}
} |
Experimente: o radar da avenida (limite de 60 km/h) lê a velocidade do carro. Mude a entrada para −5, 60, 61, 72 e 73 e veja qual mensagem aparece. Depois acrescente uma faixa nova, "Multa gravíssima", para mais de 90 km/h. (Pense: onde ela entra na cadeia?)
#include <stdio.h>
int main(void) {
int velocidade = 0;
if (scanf("%d", &velocidade) != 1) {
return 1;
}
if (velocidade < 0) {
printf("Velocidade inválida\n");
} else if (velocidade <= 60) {
printf("Dentro do limite\n");
} else if (velocidade <= 72) {
printf("Multa leve\n");
} else {
printf("Multa grave\n");
}
return 0;
}
2. A ordem importa
A Ana escreveu as mesmas perguntas em outra ordem, começando pela mais fácil:
#include <stdio.h>
int main(void) {
double nota = 9.5;
if (nota >= 5) {
printf("Conceito C\n");
} else if (nota >= 7) {
printf("Conceito B\n");
} else if (nota >= 9) {
printf("Conceito A\n");
} else {
printf("Conceito D\n");
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra ordem.c -o ordem $ ./ordem Conceito C « 9.5 merecia A!
Nenhum aviso, e o resultado está errado. 9.5 >= 5 é verdade, então a primeira pergunta já "captura" a nota e as outras nem são feitas. Pior: os blocos de "B" e "A" nunca vão rodar, para nota nenhuma, porque toda nota maior ou igual a 7 também é maior ou igual a 5.
Com >=, comece pela faixa mais alta e desça. Com < ou <=, comece pela mais baixa e suba (como no radar: <= 60, depois <= 72). Em geral: a pergunta mais "exigente" vem primeiro.
Missão: reorganize as perguntas da Ana (sem mudar a nota) para que 9.5 receba o conceito certo:
Conceito A
#include <stdio.h>
int main(void) {
double nota = 9.5;
if (nota >= 5) {
printf("Conceito C\n");
} else if (nota >= 7) {
printf("Conceito B\n");
} else if (nota >= 9) {
printf("Conceito A\n");
} else {
printf("Conceito D\n");
}
return 0;
}
#include <stdio.h>
int main(void) {
double nota = 9.5;
if (nota >= 9) {
printf("Conceito A\n");
} else if (nota >= 7) {
printf("Conceito B\n");
} else if (nota >= 5) {
printf("Conceito C\n");
} else {
printf("Conceito D\n");
}
return 0;
}
3. else if × vários if
E se a Ana tirasse os else e deixasse só ifs separados?
#include <stdio.h>
int main(void) {
double nota = 9.5;
if (nota >= 9) {
printf("Conceito A\n");
}
if (nota >= 7) {
printf("Conceito B\n");
}
if (nota >= 5) {
printf("Conceito C\n");
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra variosif.c -o variosif $ ./variosif Conceito A Conceito B « três conceitos para a mesma nota! Conceito C
Cada if separado é uma pergunta independente, feita sempre. 9.5 é maior que 9, que 7 e que 5, então os três blocos rodaram.
if … else if … else | Vários if separados | |
|---|---|---|
| Quantos blocos rodam | No máximo um (exatamente um, se houver else) | Zero, um ou vários |
| Perguntas feitas | Só até a primeira que der sim | Todas, sempre |
| Use quando | As opções se excluem: um conceito, uma sala, um desconto | As perguntas são independentes: "tem bebida?", "tem sobremesa?", "é para viagem?" |
4. Fronteiras: > ou >=?
A maioria dos erros de faixa está nos números da fronteira. A regra do radar diz: "até 60 km/h, tudo bem; de 61 a 72, multa leve; acima de 72, multa grave". O programa da seção 1 usa <= 60 e <= 72. Testando exatamente nas fronteiras:
$ gcc -std=c23 -Wall -Wextra velocidade.c -o velocidade $ for v in -5 60 61 72 73; do echo $v | ./velocidade; done Velocidade inválida Dentro do limite « 60: exatamente no limite, sem multa Multa leve « 61 Multa leve « 72: ainda leve Multa grave « 73
O comando for v in …; do echo $v | ./velocidade; done é do terminal (bash, não C): ele roda o programa uma vez para cada número, entregando o número como se você o tivesse digitado. É um jeito rápido de testar vários casos.
Se a Ana tivesse escrito < 60, o motorista a exatamente 60 km/h levaria multa. Os dois programas compilam sem aviso; só o teste mostra a diferença. Para acertar:
- Leia a regra com atenção: "até 60" inclui o 60 (
<= 60); "acima de 72" não inclui o 72 (> 72); "9 ou mais" inclui o 9 (>= 9). - Teste cada fronteira e o número logo depois dela: 60 e 61, 72 e 73.
5. Primeiro os inválidos; e o else final
No radar, a primeira pergunta é velocidade < 0. Sem ela, um sensor com defeito que mandasse −5 diria "Dentro do limite", porque −5 é menor que 60. É uma boa prática: trate os valores impossíveis no começo da cadeia. Para as notas, que vão de 0 a 10:
if (nota < 0 || nota > 10) {
printf("Nota inválida\n");
} else if (nota >= 9) {
printf("Conceito A\n");
} else if (nota >= 7) {
...
E o else final? Sem ele, se nenhuma pergunta der sim, nada acontece. Às vezes é isso que você quer, mas, na dúvida, coloque um else que pegue "todo o resto". Assim nenhum valor passa sem resposta.
6. O else pendurado
Quando há um if dentro de outro e as chaves foram esquecidas, de qual if é o else? A Ana quis dizer: "menores de 18 só entram acompanhados; os outros entram sozinhos":
#include <stdio.h>
int main(void) {
int idade = 15;
int com_pais = 0;
if (idade < 18)
if (com_pais)
printf("Pode entrar acompanhado.\n");
else
printf("Pode entrar sozinho.\n");
return 0;
}
$ gcc -std=c23 -Wall -Wextra pendurado.c -o pendurado
pendurado.c: In function ‘main’:
pendurado.c:6:8: warning: suggest explicit braces to avoid ambiguous ‘else’ [-Wdangling-else]
6 | if (idade < 18)
| ^
$ ./pendurado
Pode entrar sozinho. « um menor de 15 anos, sem os pais?!
O recuo diz que o else pertence ao if (idade < 18). Mas a regra do C é outra: o else pertence ao if mais próximo que ainda não tem else, não importa o recuo. Então o C entendeu assim:
if (idade < 18) {
if (com_pais) {
printf("Pode entrar acompanhado.\n");
} else {
printf("Pode entrar sozinho.\n"); // menor E sem os pais!
}
}
Esse problema tem nome: else pendurado (dangling else). O aviso diz "sugiro chaves explícitas para evitar um else ambíguo"; no Clang, add explicit braces to avoid dangling else. Os dois vêm com o -Wall. A solução é a mesma regra de sempre: chaves em todo if e else. Com chaves, não existe ambiguidade:
if (idade < 18) {
if (com_pais) {
printf("Pode entrar acompanhado.\n");
}
} else {
printf("Pode entrar sozinho.\n");
}
Formas diferentes + qual usar
| Situação | Forma | Por quê |
|---|---|---|
| Faixas de um número (notas, idade, preço) | if … else if … else | Cada pergunta aproveita as anteriores; só um bloco roda. |
| Um valor inteiro ou caractere comparado com várias constantes (menu: 1, 2, 3…; letras 's'/'n') | switch (aula switch) ou else if | O switch fica mais limpo para "é igual a 1? a 2? a 3?". Para faixas (>=), só o else if serve. |
| Perguntas independentes | vários if | Mais de um bloco pode rodar, de propósito. |
| Escolher entre dois valores | ternário ? : (aula Operador Ternário) | Cabe numa linha. |
| Condições dentro de condições | if dentro de if, com chaves | Ou junte as perguntas com &&, que costuma ficar mais simples. |
Quando dá errado
O que significa: uma pergunta anterior, mais "larga", já captura todos os valores dessa faixa. Exemplo: nota >= 5 antes de nota >= 9.
Como consertar: com >=, ordene da faixa mais alta para a mais baixa; com <=, da mais baixa para a mais alta. Teste um valor de cada faixa.
O que significa: você usou ifs separados em vez de else if.
Como consertar: troque os if do meio por else if.
O que significa: < no lugar de <= (ou o contrário).
Como consertar: releia a regra ("até", "a partir de", "mais de") e teste exatamente o número da fronteira e o seguinte.
warning: suggest explicit braces to avoid ambiguous ‘else’ [-Wdangling-else]
O que significa: um if sem chaves dentro de outro if sem chaves, seguido de um else. O else vai para o if mais próximo, que pode não ser o que você queria.
Como consertar: coloque chaves em todos os if e else.
error: ‘else’ without a previous ‘if’
O que significa: há algo entre o fim do bloco de um if e o else if seguinte: um ; depois do ), uma linha solta ou uma chave fechando no lugar errado.
Como consertar: cada else deve vir logo depois de }: } else if (…) {. Veja também if e else.
Referência rápida
| Estrutura | Comportamento |
|---|---|
if (a) { … } else if (b) { … } else { … } | Testa a; se não, testa b; se nenhum, roda o else. Só um bloco roda. |
Vários else if | Sem limite. São testados de cima para baixo, até o primeiro verdadeiro. |
else final | Opcional; pega o que sobrou. |
Faixas com >= | Da maior para a menor. |
Faixas com <= | Da menor para a maior. |
else sem chaves com if aninhado | Pertence ao if mais próximo (-Wdangling-else). |
Exercícios
1. Complete a cadeia
Complete com as duas palavras que fazem a segunda pergunta só quando a primeira der "não":
2. A fronteira
A regra é "a partir de 18 anos". Complete o operador:
3. Com int n = 15;, o que este trecho mostra? if (n > 10) { printf("A"); } else if (n > 5) { printf("B"); } else { printf("C"); }
4. E se fossem três if separados? if (n > 10) { printf("A"); } if (n > 5) { printf("B"); } if (n > 0) { printf("C"); } (com n = 15)
5. Num else sem chaves, depois de dois if aninhados sem chaves, a qual if ele pertence?
Missão final: o desconto da lojinha
Missão: a lojinha da Ana dá desconto por faixa de compra: 500 reais ou mais, 15%; 200 ou mais, 10%; 100 ou mais, 5%; abaixo de 100, nada. O programa lê o valor (a entrada preparada é 250). Escreva a cadeia de if / else if / else que dá o valor certo à variável desconto. Sem avisos. Com 250, a saída deve ser:
Desconto: 10% Total: R$ 225.00
#include <stdio.h>
int main(void) {
double compra = 0;
if (scanf("%lf", &compra) != 1) {
return 1;
}
int desconto = 0; // em porcentagem
// escreva a cadeia aqui
double total = compra - compra * desconto / 100;
printf("Desconto: %d%%\n", desconto);
printf("Total: R$ %.2f\n", total);
return 0;
}
#include <stdio.h>
int main(void) {
double compra = 0;
if (scanf("%lf", &compra) != 1) {
return 1;
}
int desconto = 0; // em porcentagem
if (compra >= 500) {
desconto = 15;
} else if (compra >= 200) {
desconto = 10;
} else if (compra >= 100) {
desconto = 5;
} else {
desconto = 0;
}
double total = compra - compra * desconto / 100;
printf("Desconto: %d%%\n", desconto);
printf("Total: R$ %.2f\n", total);
return 0;
}
O %% no printf mostra um % de verdade (aula Formatos do printf). Teste as fronteiras: 500, 499.99, 200, 100 e 99.99.
Resumo
if…else if…elseescolhe um entre vários caminhos. As perguntas são feitas de cima para baixo e param na primeira que der sim.else ifé só umelseseguido de outroif; pode haver quantos você quiser. Oelsefinal pega o resto.- A ordem importa: com
>=, da faixa mais alta para a mais baixa. Uma faixa na ordem errada nunca é alcançada, e não há aviso. - Vários
ifseparados são perguntas independentes: vários blocos podem rodar. - Teste as fronteiras (
>×>=) e trate os valores inválidos no começo. - Else pendurado: sem chaves, o
elsevai para oifmais próximo (-Wdangling-else). Chaves sempre.