Sua dose diária de programação

Conceito, 3 exemplos e 3 exercícios: uma pequena conquista de cada vez.

✦   Lição

Decisões com condicionais

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.

C++ Fundamentos Iniciante 3 exemplos + 3 exercícios
42 lições publicadas 10 linguagens novas lições todo dia útil
C++ / Fundamentos

Decisões com condicionais

por Callahan Whitmore
Iniciante

Entenda 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.

↳ Pontos-chave
  • 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 a x e é sempre verdadeiro. Compile com -Wall para 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, cada case precisa de break para não cair no seguinte; o ternário cond ? a : b dentro de std::cout exige parênteses.

Do conceito à prática

3 exemplos para ver a ideia funcionando.

01Porções da lasanha com if e else

porcoes.cpp
// 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.cpp
// 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.cpp
// 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).

↳ Requisitos
  • Guardar o título, o prazo e os dias com o livro em variáveis.
  • Usar um if/else comparando 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.
código inicial
#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;
}
saída esperada
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

  1. As três variáveis guardam os dados do empréstimo: o título em std::string e os dias em int, porque são contagens inteiras.
  2. As duas primeiras linhas de saída mostram o livro e os dias, antes de qualquer decisão.
  3. if (diasComLivro > prazoDias) compara os dois inteiros; o resultado é um bool, e o bloco só roda se ele for true.
  4. Dentro do if, (diasComLivro - prazoDias) calcula os dias de atraso (17 - 14 = 3) na própria linha de saída.
  5. O else cobre todos os outros casos, inclusive a devolução no último dia do prazo, e mostra quantos dias ainda restam.
  6. 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 o if ali mesmo, com um corpo vazio, e o bloco seguinte roda sempre. Com o else logo depois, nem compila. Não coloque ; depois dos parênteses da condição.
  • Usar >= em vez de >: diasComLivro >= prazoDias acusaria 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 - diasComLivro dentro do if imprime -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.

↳ Requisitos
  • Usar uma única cadeia if / else if / else para 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::string e imprimi-la depois da cadeia.
  • Reproduzir exatamente a saída esperada.
código inicial
#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;
}
saída esperada
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

  1. media e frequencia são int: a média vai de 0 a 100 e a frequência é uma porcentagem inteira.
  2. std::string situacao; começa vazia e recebe o texto certo em um dos quatro ramos.
  3. 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.
  4. 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.
  5. else if (media >= 50) não precisa repetir media < 70: se o programa chegou aqui, o teste anterior já falhou. Com 65, este ramo é o escolhido.
  6. O else final pega o que sobrou (frequência ok e média abaixo de 50).
  7. 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 if soltos: trocar os else if por if independentes faz mais de um ramo rodar; com média 85, a variável receberia "aprovado" e depois "recuperação". Use else if para 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.

↳ Requisitos
  • Calcular a pontuação de cada jogador com if / else if / else, usando && para reconhecer a dupla de 6 antes das outras duplas.
  • Mostrar sim ou não na indicação de dupla com o operador ternário dentro do std::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.
código inicial
#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;
}
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)
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

  1. Os quatro dados ficam em variáveis int, dois para cada jogador; trocar os valores muda a rodada inteira sem mexer na lógica.
  2. 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: se j1a == j1b fosse testado antes, o par 6 e 6 valeria 24 em vez de 30.
  3. j1a == 6 && j1b == 6 usa &&: os dois dados precisam ser 6. Basta um deles ser diferente para a condição inteira ser falsa.
  4. 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.
  5. (j1a == j1b ? "sim" : "não") é o operador ternário: devolve um texto ou outro conforme a condição, sem precisar de um if/else com duas instruções de saída.
  6. 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.
  7. A decisão final tem três ramos; o else só roda quando nenhum dos dois é maior, ou seja, no empate.
  8. 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 de j1b a j1a e a condição vira verdadeira para qualquer valor diferente de zero. Compare com == e compile com -Wall para o compilador avisar.
  • Esquecer o empate: com só if (pontos1 > pontos2) ... else ..., um empate é anunciado como vitória do jogador 2. Use else if para o segundo jogador e deixe o else para 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)

Últimas lições

Ver o arquivo completo →