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.

Você vai aprender
  • 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 if e vários if separados.
  • 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", &nota) != 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 if quiser.
} 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 escreveO 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.

Regra da ordem

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 … elseVários if separados
Quantos blocos rodamNo máximo um (exatamente um, se houver else)Zero, um ou vários
Perguntas feitasSó até a primeira que der simTodas, sempre
Use quandoAs opções se excluem: um conceito, uma sala, um descontoAs 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:

  1. 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).
  2. 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çãoFormaPor quê
Faixas de um número (notas, idade, preço)if … else if … elseCada 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 ifO switch fica mais limpo para "é igual a 1? a 2? a 3?". Para faixas (>=), só o else if serve.
Perguntas independentesvários ifMais de um bloco pode rodar, de propósito.
Escolher entre dois valoresternário ? : (aula Operador Ternário)Cabe numa linha.
Condições dentro de condiçõesif dentro de if, com chavesOu junte as perguntas com &&, que costuma ficar mais simples.

Quando dá errado

Uma faixa nunca é alcançada (sem aviso nenhum)

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.

Aparecem várias respostas para um valor só

O que significa: você usou ifs separados em vez de else if.

Como consertar: troque os if do meio por else if.

O valor da fronteira cai na faixa errada

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

EstruturaComportamento
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 ifSem limite. São testados de cima para baixo, até o primeiro verdadeiro.
else finalOpcional; pega o que sobrou.
Faixas com >=Da maior para a menor.
Faixas com <=Da menor para a maior.
else sem chaves com if aninhadoPertence 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":

if (x > 0) { printf("positivo\n"); } (x < 0) { printf("negativo\n"); } else { printf("zero\n"); }

2. A fronteira

A regra é "a partir de 18 anos". Complete o operador:

if (idade 18) {

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 … else escolhe um entre vários caminhos. As perguntas são feitas de cima para baixo e param na primeira que der sim.
  • else if é só um else seguido de outro if; pode haver quantos você quiser. O else final 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 if separados 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 else vai para o if mais próximo (-Wdangling-else). Chaves sempre.