C++ if e else
Até aqui, seus programas executavam todas as linhas, de cima para baixo, sempre do mesmo jeito. Mas a vida é cheia de decisões: se a nota for 7 ou mais, a aluna passou; senão, vai para a recuperação. Nesta aula você vai ensinar o programa a decidir com if ("se") e else ("senão"), entender por que as chaves { } importam tanto e conhecer três armadilhas clássicas que o compilador ajuda a pegar.
- Como escrever um
if: a condição entre parênteses e o bloco entre chaves. - Como dar um caminho alternativo com
else. - O que pode ser uma condição (comparações,
bool, até números). - O bug do
ifsem chaves com duas linhas, e o aviso que o g++ dá. - Por que
if (x = 5)está errado, e o ponto e vírgula que "desliga" oif. - O
ifcom inicializador:if (int n = …; n > 0)C++17.
Todos os programas desta aula foram compilados com o g++ 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), com g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa. Os avisos que aparecem aqui só são mostrados por causa do -Wall -Wextra (aula Avisos): nunca compile sem eles.
A ideia: a bifurcação na estrada
Imagine a Ana dirigindo até chegar a uma bifurcação com uma placa: "Se estiver chovendo, pegue a estrada coberta. Senão, pegue a estrada da praia". Ela olha para o céu (a condição), e a resposta só pode ser sim ou não. Conforme a resposta, ela segue por um caminho ou pelo outro. Depois, os dois caminhos voltam a se encontrar e a viagem continua.
| Na estrada | No C++ |
|---|---|
| "Se estiver chovendo" | if (chovendo) |
| O caminho do "sim" | o bloco { … } logo depois do if |
| "Senão" | else |
| O caminho do "não" | o bloco { … } logo depois do else |
| Os caminhos se juntam | a primeira linha depois do if/else |
1. O if sozinho
#include <iostream>
int main() {
double nota = 8.5;
if (nota >= 7) {
std::cout << "Aprovada!\n";
}
std::cout << "Fim do boletim.\n";
}
- if
- "Se". Palavra reservada do C++: não pode ser nome de variável.
- (nota >= 7)
- A condição, sempre entre parênteses. Ela é uma pergunta de sim ou não: "a nota é maior ou igual a 7?". A resposta é um
bool:true(verdadeiro) oufalse(falso) (aulas Booleanos e Operadores de Comparação). - { … }
- O bloco: as linhas que só rodam se a condição for verdadeira. Pode ter quantas linhas você quiser.
- Sem
;depois do) - A linha do
ifnão termina com ponto e vírgula. As linhas dentro do bloco, sim. (O que acontece se você puser um;ali está na seção 5.) - Os 4 espaços
- O recuo (a indentação) mostra a quem lê o que está dentro do bloco. O compilador não liga para os espaços, só para as chaves; mas sem recuo o código fica ilegível.
$ g++ -std=c++23 -Wall -Wextra nota.cpp -o nota $ ./nota Aprovada! Fim do boletim. « esta linha está fora do if: roda sempre
Troque a nota para 5.5, compile e rode de novo: só aparece Fim do boletim.. O bloco foi pulado.
As condições mais comuns
| Condição | Lê-se | Exemplo |
|---|---|---|
a == b | a é igual a b (dois sinais de igual!) | if (senha == 1234) |
a != b | a é diferente de b | if (resposta != 'S') |
a < b, a > b | menor, maior | if (idade < 18) |
a <= b, a >= b | menor ou igual, maior ou igual | if (nota >= 7) |
c1 && c2 | c1 e c2 | if (nota >= 7 && faltas < 10) |
c1 || c2 | c1 ou c2 | if (dia == 6 || dia == 7) |
!c | não c | if (!pagou) |
Os operadores &&, || e ! têm aula própria: Operadores Lógicos.
2. O caminho alternativo: else
O else ("senão") vem logo depois do bloco do if e diz o que fazer quando a condição é falsa. Um dos dois blocos sempre roda, nunca os dois:
#include <iostream>
int main() {
double nota = 5.5;
if (nota >= 7) {
std::cout << "Aprovada!\n";
std::cout << "Parabéns!\n";
} else {
std::cout << "Recuperação.\n";
std::cout << "A prova é dia 10.\n";
}
std::cout << "Fim do boletim.\n";
}
$ ./nota2 Recuperação. « 5.5 >= 7 é falso: rodou o bloco do else A prova é dia 10. Fim do boletim.
- O programa calcula a condição
nota >= 7→5.5 >= 7→false. - Como é falsa, pula o bloco do
ifinteiro (as duas linhas). - Roda o bloco do
else(as duas linhas). - Segue para a linha depois do
else:Fim do boletim..
O else não tem condição: ele é simplesmente "todos os outros casos". Se você precisa de mais de dois caminhos (A, B ou C), use else if, a próxima aula.
Missão: com a nota 5.5, este programa não mostra nada sobre a aluna. Acrescente um else que mostre Recuperação quando a nota for menor que 7. Depois, teste com outras notas.
#include <iostream>
int main() {
double nota = 5.5;
if (nota >= 7) {
std::cout << "Aprovada\n";
}
}
#include <iostream>
int main() {
double nota = 5.5;
if (nota >= 7) {
std::cout << "Aprovada\n";
} else {
std::cout << "Recuperação\n";
}
}
Decidir com o que o usuário digitou
A decisão fica mais interessante quando o valor vem do teclado, com std::cin (aula Entrada com cin):
#include <iostream>
int main() {
int idade = 0;
std::cout << "Sua idade: ";
std::cin >> idade;
if (idade >= 18) {
std::cout << "Pode tirar a carteira de motorista.\n";
} else {
std::cout << "Faltam " << 18 - idade << " anos.\n";
}
}
$ ./cin Sua idade: 15 « a Ana digitou 15 e Enter Faltam 3 anos. $ ./cin Sua idade: 30 Pode tirar a carteira de motorista.
3. O que pode ser uma condição
A condição precisa resultar em true ou false. Além das comparações, valem:
- Uma variável
bool:bool pagou = true; if (pagou) { … }. Não precisa escreverif (pagou == true). - Um número: o C++ converte
0emfalsee qualquer outro número emtrue. Herança da linguagem C.
#include <iostream>
int main() {
int estoque = 0;
if (estoque) {
std::cout << "Tem no estoque\n";
} else {
std::cout << "Esgotado\n";
}
}
$ ./numero Esgotado « 0 conta como false
Funciona, mas if (estoque > 0) diz a mesma coisa de um jeito que qualquer pessoa entende. Prefira a comparação explícita com números; deixe o if (x) para variáveis bool.
4. Chaves: com e sem { }
Quando o bloco tem uma linha só, o C++ deixa você omitir as chaves:
if (nota >= 7)
std::cout << "Aprovada!\n";
else
std::cout << "Recuperação.\n";
Sem chaves, o if controla só a próxima instrução, até o primeiro ;. O problema aparece quando alguém, depois, acrescenta uma segunda linha achando que ela também fica "dentro":
#include <iostream>
int main() {
double nota = 5.5;
if (nota >= 7)
std::cout << "Aprovada!\n";
std::cout << "Parabéns!\n";
std::cout << "Fim do boletim.\n";
}
$ g++ -std=c++23 -Wall -Wextra semchaves.cpp -o semchaves
semchaves.cpp: In function ‘int main()’:
semchaves.cpp:6:5: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
6 | if (nota >= 7)
| ^~
semchaves.cpp:8:9: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
8 | std::cout << "Parabéns!\n";
| ^~~
$ ./semchaves
Parabéns! « nota 5.5, e mesmo assim deu parabéns!
Fim do boletim.
A linha 8 está recuada como se fosse do if, mas para o compilador ela está fora: roda sempre. O aviso diz exatamente isso: "esta cláusula if não protege… esta instrução, mas a última está recuada de um jeito enganoso, como se fosse protegida pelo if". Misleading indentation = "indentação enganosa".
Use { } mesmo com uma linha só. Custa dois caracteres e elimina esse bug. Em 2014, um erro desse tipo (uma linha duplicada depois de um if sem chaves) desligou uma verificação de segurança do sistema da Apple: o famoso bug "goto fail". Sem o -Wall, o g++ nem teria avisado.
Experimente: rode e veja o aviso e o "Parabéns!" indevido. Depois coloque chaves em volta das duas linhas do if e rode de novo.
#include <iostream>
int main() {
double nota = 5.5;
if (nota >= 7)
std::cout << "Aprovada!\n";
std::cout << "Parabéns!\n";
std::cout << "Fim do boletim.\n";
}
Onde pôr as chaves
Há dois estilos populares, e os dois são corretos. Escolha um e use sempre o mesmo:
| Chave na mesma linha (usado neste guia) | Chave na linha de baixo |
|---|---|
if (nota >= 7) {
std::cout << "Sim\n";
} else {
std::cout << "Não\n";
} | if (nota >= 7)
{
std::cout << "Sim\n";
}
else
{
std::cout << "Não\n";
} |
5. Duas armadilhas: = no lugar de ==, e o ; depois do if
if (x = 5): atribuição em vez de comparação
Um = é atribuição ("x recebe 5"); dois, ==, é comparação ("x é igual a 5?"). Trocar um pelo outro dentro do if compila, mas faz outra coisa:
#include <iostream>
int main() {
int x = 3;
if (x = 5) {
std::cout << "x vale 5\n";
}
std::cout << "x agora é " << x << "\n";
}
$ g++ -std=c++23 -Wall -Wextra atrib.cpp -o atrib
atrib.cpp: In function ‘int main()’:
atrib.cpp:5:11: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
5 | if (x = 5) {
| ~~^~~
$ ./atrib
x vale 5 « x valia 3, mas o if "deu certo"
x agora é 5 « e ainda estragou o valor de x
O que aconteceu: x = 5 guardou 5 em x e "devolveu" 5. Como 5 não é zero, contou como true. O aviso diz: "sugiro parênteses em volta de uma atribuição usada como valor verdade". Em português claro: "você quis mesmo atribuir aqui? Se foi engano, use ==".
Conserto: if (x == 5).
if (…);: o ponto e vírgula que desliga o if
#include <iostream>
int main() {
double nota = 4.0;
if (nota >= 7);
{
std::cout << "Aprovada!\n";
}
}
$ g++ -std=c++23 -Wall -Wextra pontovirgula.cpp -o pontovirgula
pontovirgula.cpp: In function ‘int main()’:
pontovirgula.cpp:5:19: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body]
5 | if (nota >= 7);
| ^
pontovirgula.cpp:5:5: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
5 | if (nota >= 7);
| ^~
pontovirgula.cpp:6:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’
6 | {
| ^
$ ./pontovirgula
Aprovada! « com nota 4!
Aquele ; sozinho é uma instrução vazia, e é ela que o if controla. O bloco { … } logo abaixo virou um bloco comum, que roda sempre. O primeiro aviso, do -Wextra, diz: "sugiro chaves em volta do corpo vazio de um if". O segundo é o mesmo da seção 4.
Conserto: apague o ; do fim da linha do if.
6. if com inicializador C++17
Às vezes você calcula um valor só para testá-lo no if e usá-lo dentro dele. Desde o C++17, dá para criar essa variável dentro dos parênteses do if, antes da condição, separada por ;:
#include <iostream>
int main() {
int pontos = 4;
if (int falta = 10 - pontos; falta > 0) {
std::cout << "Faltam " << falta << " pontos para o prêmio.\n";
} else {
std::cout << "Prêmio liberado! Sobraram " << -falta << " pontos.\n";
}
}
- int falta = 10 - pontos;
- O inicializador: cria a variável
falta(aqui,6). Termina com;. - falta > 0
- A condição de sempre, que já pode usar
falta. - Dentro do if e do else
faltaexiste nos dois blocos.- Depois do if
faltadeixa de existir. Esse é o objetivo: a variável só vive onde é útil, e não "polui" o resto do programa (aula Escopo).
$ g++ -std=c++23 -Wall -Wextra inicial.cpp -o inicial $ ./inicial Faltam 6 pontos para o prêmio.
Tentar usar falta depois do if dá erro:
$ g++ -std=c++23 -Wall -Wextra inicial2.cpp -o inicial2 « std::cout << falta; depois do if
inicial2.cpp: In function ‘int main()’:
inicial2.cpp:9:18: error: ‘falta’ was not declared in this scope
9 | std::cout << falta << "\n";
| ^~~~~
"falta não foi declarada neste escopo": para o compilador, fora do if ela nunca existiu. Com um padrão antigo, como -std=c++14, o g++ aceita mas avisa: warning: init-statement in selection statements only available with ‘-std=c++17’ or ‘-std=gnu++17’ [-Wc++17-extensions]. O jeito antigo era declarar a variável na linha de cima do if; também funciona, mas ela continua existindo até o fim do bloco de fora.
Formas diferentes + qual usar
| Forma | Exemplo | Quando usar |
|---|---|---|
if com chaves | if (c) { … } | Sempre. É o padrão deste guia. |
if sem chaves | if (c) x = 0; | Só uma instrução, na mesma linha. Evite: convida ao bug da seção 4. |
if / else | if (c) { … } else { … } | Dois caminhos. |
else if | if (…) {…} else if (…) {…} else {…} | Três ou mais caminhos. Aula else if. |
| Ternário | c ? a : b | Escolher entre dois valores numa linha. Aula Operador Ternário. |
switch | switch (opcao) { case 1: … } | Comparar uma variável com uma lista de valores fixos. Aula switch. |
if com inicializador | if (int r = f(); r > 0) | Quando a variável só é útil para o if. |
Quando dá errado
warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]
O que significa: o if não tem chaves, e uma linha recuada como se estivesse dentro dele, na verdade, está fora. Ou há um ; logo depois do ).
Como consertar: ponha chaves em volta de todas as linhas que devem depender da condição, e confira se não há ; depois do ).
warning: suggest parentheses around assignment used as truth value [-Wparentheses]
O que significa: há um = (atribuição) dentro da condição. Quase sempre, você queria ==.
Como consertar: troque por ==.
error: ‘else’ without a previous ‘if’
if (nota >= 7);
std::cout << "Aprovada!\n";
else
std::cout << "Recuperação.\n";
$ g++ -std=c++23 -Wall -Wextra elsesolto.cpp -o elsesolto
…(os dois avisos de -Wempty-body e -Wmisleading-indentation)…
elsesolto.cpp:7:5: error: ‘else’ without a previous ‘if’
7 | else
| ^~~~
O que significa: "else sem um if antes". Um else precisa vir imediatamente depois da instrução (ou do bloco) do if. Aqui, o if terminou no ;, depois veio o cout (fora do if), e o else ficou sem par. O mesmo erro aparece quando há duas linhas entre um if sem chaves e o else.
Como consertar: tire o ; depois do ) e use chaves nos dois blocos.
error: ‘falta’ was not declared in this scope
O que significa: você usou fora do if (ou fora das chaves) uma variável criada dentro dele.
Como consertar: se precisa do valor depois, declare a variável antes do if.
double com == dá "falso" quando deveria dar "verdadeiro"
O que significa: 0.1 + 0.2 == 0.3 é false, porque os números com vírgula são guardados com pequenos erros (aula float e double).
Como consertar: com double, prefira <, >= etc. Para "igual", compare a diferença com uma margem: if (std::abs(a - b) < 0.0001) (veja Matemática).
Referência rápida
| Escrita | O que faz |
|---|---|
if (cond) { … } | Roda o bloco só se cond for verdadeira |
if (cond) { … } else { … } | Um bloco ou o outro, nunca os dois |
if (int v = …; cond) { … } | Cria v só para o if/else (C++17) |
== / = | Compara / atribui. No if, quase sempre == |
if (x) com número | 0 é falso; qualquer outro, verdadeiro |
-Wall -Wextra | Liga os avisos -Wmisleading-indentation, -Wparentheses e -Wempty-body |
Exercícios
1. Complete o if
Complete para mostrar "Pode votar" se a idade for 16 ou mais:
2. Senão
Complete com a palavra que dá o caminho alternativo:
3. Com int x = 0;, o que mostra if (x = 1) { std::cout << "A"; } else { std::cout << "B"; }?
4. Com nota 3, o que este código mostra? if (nota >= 7) std::cout << "A"; std::cout << "B";
5. Em if (int r = 10 % 3; r == 1) { … }, onde a variável r pode ser usada?
Missão final: o frete grátis
Missão: a lojinha da Ana dá frete grátis em compras de R$ 100 ou mais. Usando um if com inicializador (if (double falta = …; …)), mostre Faltam R$ 17.50 para o frete grátis. quando faltar dinheiro, e Frete grátis! no else. Depois, mude o total para 120 e confira o outro caminho. Para as duas casas, use std::println com {:.2f} (aula std::format e std::print).
#include <print>
int main() {
double total = 82.5;
// escreva o if aqui
}
#include <print>
int main() {
double total = 82.5;
if (double falta = 100 - total; falta > 0) {
std::println("Faltam R$ {:.2f} para o frete grátis.", falta);
} else {
std::println("Frete grátis!");
}
}
Resumo
if (condição) { … }roda o bloco só se a condição for verdadeira.else { … }roda no caso contrário.- A condição vai entre parênteses e resulta em
true/false. Números também servem (0 = falso), mas prefira comparações explícitas. - Use sempre chaves: sem elas, o
ifcontrola uma linha só, e a segunda linha roda sempre (-Wmisleading-indentation). if (x = 5)atribui em vez de comparar (-Wparentheses).if (…);desliga oif(-Wempty-body).if (int v = …; v > 0)C++17 cria uma variável que só existe dentro doif/else.- Compile sempre com
-Wall -Wextra: os três avisos desta aula pegam bugs reais.