Decisões com condicionais
por Callahan WhitmoreEntenda o conceito
Até aqui, os programas executavam todas as linhas de cima para baixo. Com uma condicional, o programa passa a escolher o que fazer: if (estoque < 5) { ... } só executa o bloco entre chaves quando a condição entre parênteses é verdadeira. Com else, você define o que acontece no caso contrário.
A condição é sempre uma expressão que vale true ou false. Ela costuma vir dos operadores de comparação (==, !=, <, <=, >, >=) e pode ser combinada com os operadores lógicos && (e), || (ou) e ! (não). Cuidado com o = sozinho: ele atribui, não compara.
Quando há várias faixas, como as ligas de um ranking, encadeie if / else if / else. As condições são testadas em ordem e só o primeiro ramo verdadeiro é executado, por isso a ordem dos testes faz parte da regra.
Para comparar um inteiro ou char com valores fixos, o switch organiza os casos com case, break e default. Já o operador ternário condicao ? a : b escolhe entre dois valores numa única expressão, ideal para decisões pequenas.
if (condicao) { ... } else { ... }executa um bloco ou o outro, nunca os dois; a condição sempre fica entre parênteses.- Compare com
==;if (x = 5)atribui 5 axe é sempre verdadeiro. Compile com-Wallpara o compilador avisar desse engano. &&exige as duas condições,||aceita qualquer uma e!inverte o resultado.- Numa cadeia
if / else if / else, só o primeiro ramo verdadeiro roda: teste primeiro os casos mais específicos ou as faixas maiores. - No
switch, cadacaseprecisa debreakpara não cair no seguinte; o ternáriocond ? a : bdentro destd::coutexige parênteses.
Do conceito à prática
3 exemplos para ver a ideia funcionando.
01Porções da lasanha com if e else
// Receita de lasanha: há porções para todos os convidados?
#include <iostream>
int main() {
int porcoes = 8; // a receita rende 8 porções
int convidados = 11; // pessoas confirmadas
std::cout << "Porções: " << porcoes << '\n';
std::cout << "Convidados: " << convidados << '\n';
// if executa o bloco só quando a condição é verdadeira
if (porcoes >= convidados) {
std::cout << "Dá para servir todo mundo.\n";
} else {
// else cobre o caso contrário
int faltam = convidados - porcoes;
std::cout << "Faltam " << faltam << " porções.\n";
}
// Uma comparação produz um bool, que pode ser guardado
bool sobraComida = porcoes > convidados;
if (!sobraComida) {
std::cout << "Não vai sobrar para o dia seguinte.\n";
}
// Igualdade usa ==; um único = seria atribuição
if (convidados % 2 == 0) {
std::cout << "Mesa com número par de lugares.\n";
} else {
std::cout << "Mesa com número ímpar de lugares.\n";
}
return 0;
}
O primeiro if compara porções e convidados: como 8 não é maior ou igual a 11, o programa pula o bloco do if e executa o else, que calcula e mostra as 3 porções que faltam. A variável faltam só existe dentro do bloco do else, onde foi declarada.
O segundo teste mostra que uma comparação é um bool como outro qualquer: ela pode ser guardada em sobraComida e invertida com !. O último usa % e == para descobrir se o número de convidados é par; repare que a igualdade tem dois sinais.
02Liga do ranking com else if e operadores lógicos
// Ranking de jogo: else if, operadores lógicos e ordem das condições
#include <iostream>
#include <string>
int main() {
int pontos = 1350;
int vitorias = 4;
int derrotas = 0;
// Testadas de cima para baixo: vale a primeira condição verdadeira
std::string liga;
if (pontos >= 2000) {
liga = "Diamante";
} else if (pontos >= 1000) {
liga = "Ouro";
} else if (pontos >= 500) {
liga = "Prata";
} else {
liga = "Bronze";
}
std::cout << "Liga: " << liga << '\n';
// && exige as duas condições; || aceita qualquer uma delas
bool invicto = vitorias >= 3 && derrotas == 0;
if (invicto || pontos >= 5000) {
std::cout << "Ganhou o selo de destaque!\n";
}
// ! inverte o resultado da condição
if (!invicto) {
std::cout << "Continue jogando para ficar invicto.\n";
} else {
std::cout << "Sequência invicta: " << vitorias << " vitórias\n";
}
return 0;
}
A cadeia if / else if / else classifica os 1350 pontos: o teste de 2000 falha, o de 1000 passa e os demais nem são avaliados, então a liga é Ouro. Se a ordem fosse invertida, começando por pontos >= 500, todo jogador com mais de 500 pontos cairia em Prata.
Em seguida, && e || combinam condições: o jogador é invicto quando tem 3 ou mais vitórias e nenhuma derrota, e ganha o selo se for invicto ou tiver 5000 pontos. O !invicto no último if mostra a negação.
03Caixa da loja com switch e operador ternário
// Caixa da loja: switch, operador ternário e if com inicializador
#include <iostream>
int main() {
int total = 240; // valor da compra em reais inteiros
char pagamento = 'p'; // 'd' dinheiro, 'p' pix, 'c' cartão
// switch compara um valor inteiro (ou char) com cada case
int descontoPercentual = 0;
switch (pagamento) {
case 'd':
case 'p': // dois case seguidos compartilham o mesmo código
descontoPercentual = 5;
break; // sem break, a execução "cai" no case seguinte
case 'c':
descontoPercentual = 0;
break;
default: // nenhum case combinou
std::cout << "Forma de pagamento inválida\n";
return 1;
}
int aPagar = total - total * descontoPercentual / 100;
std::cout << "Desconto: " << descontoPercentual << "%\n";
std::cout << "A pagar: R$ " << aPagar << '\n';
// Ternário: condição ? valor_se_verdadeiro : valor_se_falso
int parcelas = (pagamento == 'c' && aPagar >= 200) ? 3 : 1;
std::cout << "Parcelas: " << parcelas << '\n';
// if com inicializador (C++17): brindes só existe dentro do if/else
if (int brindes = aPagar / 100; brindes > 0) {
std::cout << "Brindes ganhos: " << brindes << '\n';
} else {
std::cout << "Sem brinde desta vez\n";
}
return 0;
}
O switch compara o char do pagamento com cada case. Dinheiro e pix compartilham o mesmo desconto porque os dois case estão empilhados, e o break impede que a execução continue no case 'c'. O default trata qualquer letra inesperada e encerra o programa com código 1.
O ternário escolhe o número de parcelas numa linha só: 3 no cartão acima de R$ 200, senão 1. Por fim, o if com inicializador (C++17) declara brindes dentro da própria condição, e a variável deixa de existir depois do if/else, sem poluir o resto do main.
Agora é com você
Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.
01Prazo de devolução do livroFácil
Um leitor está com o livro Dom Casmurro há 17 dias, e o prazo da biblioteca é de 14 dias. Mostre o livro, os dias com ele e se a devolução está atrasada (e em quantos dias) ou dentro do prazo (e quantos dias faltam).
- Guardar o título, o prazo e os dias com o livro em variáveis.
- Usar um
if/elsecomparando os dias com o livro e o prazo, de modo que devolver no último dia não conte como atraso. - Calcular os dias de atraso ou os dias restantes com uma subtração, sem digitar o resultado.
- Reproduzir exatamente a saída esperada.
#include <iostream>
#include <string>
int main() {
std::string livro = "Dom Casmurro";
int prazoDias = 14;
int diasComLivro = 17;
// Mostre o livro e os dias, depois decida com if/else
return 0;
}
Livro: Dom Casmurro
Dias com o livro: 17
Devolução atrasada em 3 dias
Ver dica
Pense em qual comparação é verdadeira só quando o leitor passou do prazo, e não no próprio dia 14.
Ver resposta
#include <iostream>
#include <string>
int main() {
std::string livro = "Dom Casmurro";
int prazoDias = 14; // prazo de empréstimo da biblioteca
int diasComLivro = 17; // dias desde a retirada
std::cout << "Livro: " << livro << '\n';
std::cout << "Dias com o livro: " << diasComLivro << '\n';
// Uma única decisão com dois caminhos: atrasado ou não
if (diasComLivro > prazoDias) {
std::cout << "Devolução atrasada em " << (diasComLivro - prazoDias) << " dias\n";
} else {
std::cout << "Dentro do prazo: faltam " << (prazoDias - diasComLivro) << " dias\n";
}
return 0;
}
Passo a passo
- As três variáveis guardam os dados do empréstimo: o título em
std::stringe os dias emint, porque são contagens inteiras. - As duas primeiras linhas de saída mostram o livro e os dias, antes de qualquer decisão.
if (diasComLivro > prazoDias)compara os dois inteiros; o resultado é umbool, e o bloco só roda se ele fortrue.- Dentro do
if,(diasComLivro - prazoDias)calcula os dias de atraso (17 - 14 = 3) na própria linha de saída. - O
elsecobre todos os outros casos, inclusive a devolução no último dia do prazo, e mostra quantos dias ainda restam. - Como só um dos dois blocos é executado, o programa imprime exatamente uma linha de situação.
Por que funciona
O if/else divide o programa em dois caminhos que se excluem: ou a condição é verdadeira e o primeiro bloco roda, ou é falsa e roda o else. Com 17 dias para um prazo de 14, a comparação 17 > 14 é verdadeira, então o programa entra no primeiro bloco e informa o atraso.
Se diasComLivro mudar para 10, a mesma comparação vira false e a saída passa a ser "Dentro do prazo: faltam 4 dias", sem mexer em mais nada.
Erros comuns
- Ponto e vírgula depois do
if:if (diasComLivro > prazoDias);encerra oifali mesmo, com um corpo vazio, e o bloco seguinte roda sempre. Com oelselogo depois, nem compila. Não coloque;depois dos parênteses da condição. - Usar
>=em vez de>:diasComLivro >= prazoDiasacusaria atraso no último dia do prazo. Devolver no 14º dia ainda está dentro da regra, por isso a comparação é estrita. - Inverter a subtração:
prazoDias - diasComLivrodentro doifimprime-3. No atraso, subtraia o prazo dos dias com o livro.
Outra forma de resolver
Dá para tratar o último dia à parte com um else if (diasComLivro == prazoDias) e a mensagem "Devolver hoje". Vale a pena quando o sistema precisa avisar o leitor no dia do vencimento; para o enunciado, um if/else basta.
Saída esperada
Livro: Dom Casmurro
Dias com o livro: 17
Devolução atrasada em 3 dias
02Situação no boletimMédio
Defina a situação de um aluno com média 65 (de 0 a 100) e frequência de 80%. Com frequência abaixo de 75% ele é reprovado por falta; caso contrário, média 70 ou mais aprova, de 50 a 69 vai para recuperação e abaixo de 50 reprova por nota.
- Usar uma única cadeia
if / else if / elsepara escolher a situação. - Testar a frequência antes das faixas de média, para que a falta reprove mesmo com nota alta.
- Guardar a situação numa variável
std::stringe imprimi-la depois da cadeia. - Reproduzir exatamente a saída esperada.
#include <iostream>
#include <string>
int main() {
int media = 65;
int frequencia = 80;
std::string situacao;
// Escolha a situação com if / else if / else
// Mostre média, frequência e situação
return 0;
}
Média: 65
Frequência: 80%
Situação: recuperação
Ver dica
Quando um else if é avaliado, todos os testes acima dele já deram falso; use isso para não repetir condições.
Ver resposta
#include <iostream>
#include <string>
int main() {
int media = 65; // de 0 a 100
int frequencia = 80; // em porcentagem
std::string situacao;
// A frequência vem primeiro: falta reprova mesmo com média alta
if (frequencia < 75) {
situacao = "reprovado por falta";
} else if (media >= 70) {
situacao = "aprovado";
} else if (media >= 50) { // aqui já se sabe que media < 70
situacao = "recuperação";
} else {
situacao = "reprovado por nota";
}
std::cout << "Média: " << media << '\n';
std::cout << "Frequência: " << frequencia << "%\n";
std::cout << "Situação: " << situacao << '\n';
return 0;
}
Passo a passo
mediaefrequenciasãoint: a média vai de 0 a 100 e a frequência é uma porcentagem inteira.std::string situacao;começa vazia e recebe o texto certo em um dos quatro ramos.- O primeiro teste é
frequencia < 75, porque a regra da falta vale para qualquer média; se ele viesse depois, um aluno com média 90 e frequência 60 sairia aprovado. else if (media >= 70)só é avaliado quando a frequência está ok; com 65, a condição é falsa e o programa segue para o próximo teste.else if (media >= 50)não precisa repetirmedia < 70: se o programa chegou aqui, o teste anterior já falhou. Com 65, este ramo é o escolhido.- O
elsefinal pega o que sobrou (frequência ok e média abaixo de 50). - As três linhas de saída mostram os dados e a situação calculada.
Por que funciona
Numa cadeia if / else if / else, as condições são testadas em ordem e só o primeiro ramo verdadeiro é executado; os demais são pulados. Por isso a ordem dos testes é parte da regra: primeiro o critério que vence todos os outros (a falta), depois as faixas de nota da maior para a menor.
Com frequência 80, o primeiro teste falha; com média 65, o segundo também falha e o terceiro é verdadeiro, então a situação é "recuperação".
Erros comuns
- Testar a nota antes da falta: com
if (media >= 70)no topo, um aluno com média 90 e 60% de frequência sai aprovado. Coloque a regra da frequência primeiro. - Faixas fora de ordem:
if (media >= 50) ... else if (media >= 70)faz uma média 85 cair em "recuperação", e o ramo de aprovação nunca roda. Teste da maior faixa para a menor. - Vários
ifsoltos: trocar oselse ifporifindependentes faz mais de um ramo rodar; com média 85, a variável receberia "aprovado" e depois "recuperação". Useelse ifpara que só um ramo valha.
Outra forma de resolver
Dá para escrever cada ramo com a condição completa, como else if (frequencia >= 75 && media >= 50 && media < 70). Assim cada linha pode ser lida isoladamente, o que ajuda quando as regras mudam com frequência, mas o código fica mais longo e repetitivo do que a cadeia que aproveita a ordem dos testes.
Saída esperada
Média: 65
Frequência: 80%
Situação: recuperação
03Duelo de dadosDesafio
Dois jogadores lançam dois dados cada: o jogador 1 tirou 4 e 6, e o jogador 2 tirou 5 e 5. Uma dupla de 6 vale 30 pontos, qualquer outra dupla vale o dobro da soma e o resto vale a soma; mostre os lances, a pontuação final e o vencedor com a diferença, ou empate.
- Calcular a pontuação de cada jogador com
if / else if / else, usando&¶ reconhecer a dupla de 6 antes das outras duplas. - Mostrar
simounãona indicação de dupla com o operador ternário dentro dostd::cout. - Decidir entre vitória do jogador 1, vitória do jogador 2 e empate, mostrando a diferença de pontos do vencedor.
- Reproduzir exatamente a saída esperada.
#include <iostream>
int main() {
int j1a = 4;
int j1b = 6;
int j2a = 5;
int j2b = 5;
// Pontuação de cada jogador
// Lances (com o ternário para a dupla) e placar
// Vencedor ou empate
return 0;
}
Jogador 1: 4 + 6 = 10 (dupla: não)
Jogador 2: 5 + 5 = 10 (dupla: sim)
Pontuação final: 10 x 20
Vencedor: Jogador 2 (por 10 pontos)
Ver dica
A dupla de 6 também é uma dupla; pense em qual dos dois testes precisa vir primeiro para que ela valha 30.
Ver resposta
#include <iostream>
int main() {
// Valores tirados nos dados nesta rodada
int j1a = 4;
int j1b = 6;
int j2a = 5;
int j2b = 5;
// Regras: dupla de 6 vale 30; outra dupla dobra a soma; senão, vale a soma
int pontos1 = 0;
if (j1a == 6 && j1b == 6) {
pontos1 = 30;
} else if (j1a == j1b) {
pontos1 = (j1a + j1b) * 2;
} else {
pontos1 = j1a + j1b;
}
int pontos2 = 0;
if (j2a == 6 && j2b == 6) {
pontos2 = 30;
} else if (j2a == j2b) {
pontos2 = (j2a + j2b) * 2;
} else {
pontos2 = j2a + j2b;
}
// O ternário escolhe o texto; os parênteses são obrigatórios dentro do <<
std::cout << "Jogador 1: " << j1a << " + " << j1b << " = " << (j1a + j1b)
<< " (dupla: " << (j1a == j1b ? "sim" : "não") << ")\n";
std::cout << "Jogador 2: " << j2a << " + " << j2b << " = " << (j2a + j2b)
<< " (dupla: " << (j2a == j2b ? "sim" : "não") << ")\n";
std::cout << "Pontuação final: " << pontos1 << " x " << pontos2 << '\n';
// Três resultados possíveis: vitória de um, vitória do outro ou empate
if (pontos1 > pontos2) {
std::cout << "Vencedor: Jogador 1 (por " << (pontos1 - pontos2) << " pontos)\n";
} else if (pontos2 > pontos1) {
std::cout << "Vencedor: Jogador 2 (por " << (pontos2 - pontos1) << " pontos)\n";
} else {
std::cout << "Empate!\n";
}
return 0;
}
Passo a passo
- Os quatro dados ficam em variáveis
int, dois para cada jogador; trocar os valores muda a rodada inteira sem mexer na lógica. - A pontuação de cada jogador sai de uma cadeia
if / else if / else. A dupla de 6 vem primeiro porque também é uma dupla: sej1a == j1bfosse testado antes, o par 6 e 6 valeria 24 em vez de 30. j1a == 6 && j1b == 6usa&&: os dois dados precisam ser 6. Basta um deles ser diferente para a condição inteira ser falsa.- No jogador 1, 4 e 6 não formam dupla, então ele fica com a soma, 10. No jogador 2, 5 e 5 formam dupla (não de 6), e a soma 10 é dobrada para 20.
(j1a == j1b ? "sim" : "não")é o operador ternário: devolve um texto ou outro conforme a condição, sem precisar de umif/elsecom duas instruções de saída.- Os parênteses em volta do ternário são obrigatórios, porque
<<tem precedência maior que==e que?:; nas somas eles são opcionais (+vem antes de<<) e só deixam a linha mais clara. - A decisão final tem três ramos; o
elsesó roda quando nenhum dos dois é maior, ou seja, no empate. - A diferença é calculada no ramo do vencedor, sempre do maior para o menor, para nunca sair negativa.
Por que funciona
Cada regra do jogo virou uma condição, na ordem em que deve ser aplicada: o caso mais específico (dupla de 6) antes do caso geral (qualquer dupla), e o caso geral antes do padrão (a soma). Como a cadeia executa só o primeiro ramo verdadeiro, cada jogador recebe exatamente uma pontuação.
O ternário resolve as decisões pequenas, que só escolhem um valor, e o if/else cuida das decisões que executam instruções diferentes. Repare que a soma mostrada na linha do jogador (10 para os dois) é diferente da pontuação final (10 x 20): a regra da dupla é o que decide a partida.
Erros comuns
- Ternário sem parênteses no
<<:std::cout << j1a == j1b ? "sim" : "não";é lido como(std::cout << j1a) == j1b ...e não compila. Envolva o ternário inteiro em parênteses. - Dupla genérica antes da dupla de 6: com
else if (j1a == j1b)no topo, o par 6 e 6 cai nesse ramo e vale 24. Teste o caso mais específico primeiro. =no lugar de==:if (j1a = j1b)atribui o valor dej1baj1ae a condição vira verdadeira para qualquer valor diferente de zero. Compare com==e compile com-Wallpara o compilador avisar.- Esquecer o empate: com só
if (pontos1 > pontos2) ... else ..., um empate é anunciado como vitória do jogador 2. Useelse ifpara o segundo jogador e deixe oelsepara o empate.
Outra forma de resolver
A pontuação também cabe em ternários encadeados: int pontos1 = (j1a == 6 && j1b == 6) ? 30 : (j1a == j1b) ? (j1a + j1b) * 2 : j1a + j1b;. Fica mais curto, mas fica difícil de ler a partir da terceira condição; o if / else if é preferível sempre que houver mais de duas regras. Quando você aprender funções, o cálculo repetido dos dois jogadores vira uma função pontuar(a, b) chamada duas vezes.
Saída esperada
Jogador 1: 4 + 6 = 10 (dupla: não)
Jogador 2: 5 + 5 = 10 (dupla: sim)
Pontuação final: 10 x 20
Vencedor: Jogador 2 (por 10 pontos)