Carregando
Todos os artigos
Programação 26 min de leitura

O Comando If: Um Guia Visual e Prático das Decisões no Código

Aprenda o comando if de forma visual: if, else, else if, && e ||, curto-circuito, os bugs clássicos (inclusive o goto fail da Apple), cláusulas de guarda, switch e ?:, medições reais de previsão de desvios e exercícios com respostas.

nbkhope
Nesta página

Todo programa útil toma decisões. Um jogo verifica se você acertou o inimigo. Uma loja virtual verifica se o produto tem em estoque. O seu celular verifica se a senha está certa. Por trás de tudo isso está a ferramenta mais humilde e mais importante da programação: o comando if (também chamado de estrutura condicional).

Um if deixa o seu programa chegar a uma bifurcação na estrada e escolher um caminho. Neste guia você vai ver como ele funciona passo a passo, encadear decisões, combinar condições, evitar os bugs que pegaram até a Apple e terminar com exercícios para praticar.

Os exemplos estão em C++, mas o mesmo formato if (...) { ... } else { ... } funciona quase sem mudanças em C, Java, C#, JavaScript, Go, PHP e muitas outras linguagens. Perto do fim, você vai vê-lo em Python e JavaScript também.

Uma bifurcação na estrada

Um if faz uma pergunta de sim ou não, chamada de condição. Se a resposta for true (verdadeiro), o código dentro das chaves roda. Se for false (falso), esse código é pulado. Acrescente um else ("senão") e o programa segue outro caminho em vez de pular:

Um if é uma bifurcação na estrada, em dois fluxogramas. À esquerda, if: faz ou pula. A condição temperatura < 15 é verificada: se true, leve um casaco e depois tenha um bom dia; se false, vai direto para tenha um bom dia. À direita, if/else: escolhe um de dois caminhos. A condição numero % 2 == 0 é verificada: se true, diz par; se false, diz ímpar; os dois caminhos depois continuam. Toda condição vira true ou false. True segue um galho; false segue o outro, ou pula o bloco

Só if: faz ou pula

1#include <iostream>
2
3int main() {
4    int temperatura;
5    std::cout << "Temperatura lá fora (C): ";
6    std::cin >> temperatura;
7
8    if (temperatura < 15) {
9        std::cout << "Brrr! Leve um casaco.\n";
10    }
11
12    std::cout << "Tenha um bom dia!\n";
13}

Duas execuções de exemplo. Num dia frio:

Temperatura lá fora (C): 10
Brrr! Leve um casaco.
Tenha um bom dia!

Num dia quente, a linha do casaco é pulada, mas o "Tenha um bom dia!" roda sempre, porque está fora das chaves:

Temperatura lá fora (C): 22
Tenha um bom dia!

if / else: um de dois caminhos

1#include <iostream>
2
3int main() {
4    int numero;
5    std::cout << "Escolha um número inteiro: ";
6    std::cin >> numero;
7
8    if (numero % 2 == 0) {
9        std::cout << numero << " é par.\n";
10    } else {
11        std::cout << numero << " é ímpar.\n";
12    }
13}
Escolha um número inteiro: 7
7 é ímpar.
Escolha um número inteiro: 42
42 é par.

O % dá o resto de uma divisão, então numero % 2 == 0 quer dizer "dividido por 2 não sobra nada". Exatamente um dos dois blocos roda, todas as vezes. Nunca os dois, nunca nenhum.

Condições: perguntas com resposta verdadeiro ou falso

Uma condição é qualquer expressão que acaba virando true ou false. A maioria é feita com operadores de comparação:

OperadorQuer dizerExemploCom idade = 15
==igual aidade == 15true
!=diferente deidade != 15false
<menor queidade < 13false
<=menor ou igual aidade <= 15true
>maior queidade > 18false
>=maior ou igual aidade >= 13true

else if: escolhendo entre muitos caminhos

Quando existem mais de duas possibilidades, encadeie condições com else if. O programa as verifica de cima para baixo e roda o bloco da primeira que for verdadeira. Tudo o que vem depois é pulado:

else if: a primeira condição verdadeira ganha, o resto é pulado. Com nota = 83, a cadeia verifica primeiro nota >= 90: false. Depois nota >= 80: true, então devolve B. As verificações de 70 e 60 e o else final, que dá F, são pulados. Só um galho roda. Para 83, duas condições são verificadas e os outros três galhos nem chegam a ser olhados

Aqui está o exemplo original deste artigo, agora como um programa completo:

1#include <iostream>
2
3int main() {
4    int numero;
5    std::cout << "Digite um número entre 1 e 100: ";
6    std::cin >> numero;
7
8    if (numero < 1) {
9        std::cout << "Seu número é pequeno demais.\n";
10    } else if (numero > 100) {
11        std::cout << "Seu número é grande demais.\n";
12    } else {
13        // As duas verificações falharam, então o número está entre 1 e 100
14        std::cout << "Você está na faixa certa!\n";
15    }
16}

Três execuções de exemplo, uma para cada caminho:

Digite um número entre 1 e 100: -5
Seu número é pequeno demais.
Digite um número entre 1 e 100: 150
Seu número é grande demais.
Digite um número entre 1 e 100: 42
Você está na faixa certa!

Repare que o else do fim não tem condição. Ele não precisa: se o número não é menor que 1 e não é maior que 100, só sobra uma possibilidade. O else é o último recurso, o caminho tomado quando todas as outras portas estão fechadas.

Uma escada de notas

Converter uma nota numérica em conceito é a escada de else-if clássica:

1#include <iostream>
2
3char conceito(int nota) {
4    if (nota >= 90) {
5        return 'A';
6    } else if (nota >= 80) {
7        return 'B';
8    } else if (nota >= 70) {
9        return 'C';
10    } else if (nota >= 60) {
11        return 'D';
12    } else {
13        return 'F';
14    }
15}
16
17int main() {
18    int notas[] = {95, 83, 71, 64, 42, 90, 89};
19    for (int nota : notas) {
20        std::cout << nota << " -> " << conceito(nota) << "\n";
21    }
22}
195 -> A
283 -> B
371 -> C
464 -> D
542 -> F
690 -> A
789 -> B

Por que o 95 não ganha também um B, já que 95 também é >= 80? Porque a cadeia para na primeira condição verdadeira. É também por isso que a ordem das verificações importa tanto.

A ordem importa

Veja o que acontece quando os mesmos cinco testes são escritos na ordem contrária:

1#include <iostream>
2
3char conceito(int nota) {
4    if (nota >= 60) {          // Ops: o teste mais fácil vem primeiro
5        return 'D';
6    } else if (nota >= 70) {
7        return 'C';
8    } else if (nota >= 80) {
9        return 'B';
10    } else if (nota >= 90) {
11        return 'A';
12    } else {
13        return 'F';
14    }
15}
16
17int main() {
18    int notas[] = {95, 83, 71, 64, 42};
19    for (int nota : notas) {
20        std::cout << nota << " -> " << conceito(nota) << "\n";
21    }
22}
195 -> D
283 -> D
371 -> D
464 -> D
542 -> F
Os mesmos testes na ordem errada: todo mundo tira D. Com o teste mais exigente primeiro, 95 tira A, 83 tira B, 71 tira C, 64 tira D e 42 tira F. Com o teste mais fácil, >= 60, primeiro, 95, 83, 71 e 64 tiram D, e só o 42 tira F. O 95 passa no >= 60 logo de cara, então a cadeia para ali. Com faixas que se sobrepõem, coloque o teste mais exigente primeiro

Compila sem um único aviso. O computador fez exatamente o que mandaram. Isso é um erro de lógica, o tipo mais difícil de perceber, e é por isso que testar com várias entradas de exemplo faz diferença.

Combinando condições: &&, || e !

Decisões de verdade muitas vezes dependem de mais de uma coisa. O C++ tem três operadores lógicos para combinar condições:

OperadorNomeVerdadeiro quando…Exemplo
&&eos dois lados são verdadeirosidade >= 13 && temPermissao
||oupelo menos um lado é verdadeiroehFimDeSemana || ehFeriado
!nãoa condição é falsa!estaLogado

A tabela-verdade completa, com todas as combinações:

aba && ba || b!a
truetruetruetruefalse
truefalsefalsetruefalse
falsetruefalsetruetrue
falsefalsefalsefalsetrue

Exemplo: é ano bissexto?

A regra do ano bissexto é um ótimo treino de operadores lógicos. Um ano é bissexto se for divisível por 4, exceto os divisíveis por 100, a não ser que também sejam divisíveis por 400:

É ano bissexto? Uma árvore de decisão. Divisível por 400? Se sim, ano bissexto, como 2000. Se não: divisível por 100? Se sim, não é bissexto, como 1900 e 2100. Se não: divisível por 4? Se sim, ano bissexto, como 2024. Se não, não é bissexto, como 2023. Numa linha de código: (ano % 4 == 0 && ano % 100 != 0) || ano % 400 == 0
1#include <iostream>
2
3int main() {
4    int anos[] = {2023, 2024, 1900, 2000, 2100};
5    for (int ano : anos) {
6        bool ehBissexto = (ano % 4 == 0 && ano % 100 != 0) || ano % 400 == 0;
7        std::cout << ano << (ehBissexto ? " é" : " não é") << " bissexto\n";
8    }
9}
12023 não é bissexto
22024 é bissexto
31900 não é bissexto
42000 é bissexto
52100 não é bissexto

Curto-circuito: o lado direito pode nunca rodar

O && e o || são preguiçosos, no bom sentido. Eles avaliam primeiro o lado esquerdo e, se isso já decide a resposta, pulam o lado direito por completo:

Curto-circuito: && e || param assim que a resposta é conhecida. Em partidas > 0 && totalDePontos / partidas > 10, o lado esquerdo é false, então o lado direito nunca é avaliado: false && qualquer coisa é false, e não há divisão por zero. Em ehAdmin || temPermissao(usuario), o lado esquerdo é true, então o lado direito nunca é avaliado: true || qualquer coisa é true. Ponha a verificação barata ou protetora à esquerda. Ela protege a cara ou arriscada, à direita

Isso é muito útil para se proteger de erros:

1#include <iostream>
2
3int main() {
4    int totalDePontos = 120;
5    int partidas = 0;
6
7    // O && para no primeiro false: a divisão nunca acontece quando partidas é 0
8    if (partidas > 0 && totalDePontos / partidas > 10) {
9        std::cout << "Grande pontuador!\n";
10    } else {
11        std::cout << "Ainda não há partidas suficientes.\n";
12    }
13}
Ainda não há partidas suficientes.

Troque os dois lados de lugar e o programa dividiria por zero, o que em C++ é comportamento indefinido e, na maioria dos computadores, derruba o programa. As mesmas condições, outra ordem, resultado completamente diferente.

Os bugs clássicos do if

Estes três erros já custaram horas e horas aos programadores. Aprenda a reconhecê-los agora e poupe-se do problema.

Bug 1: = em vez de ==

1#include <iostream>
2
3int main() {
4    int vidas = 3;
5    if (vidas = 0) {
6        std::cout << "Fim de jogo\n";
7    }
8    std::cout << "Vidas restantes: " << vidas << "\n";
9}
Vidas restantes: 0

vidas = 0 não compara nada. Ele guarda 0 em vidas, e a expressão inteira vale 0, que conta como false. Então o jogador perde todas as vidas em silêncio e a mensagem de fim de jogo nunca aparece. Felizmente, com os avisos ligados (g++ -Wall), o GCC 14 percebe:

1vidas.cpp: In function 'int main()':
2vidas.cpp:5:15: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
3    5 |     if (vidas = 0) {
4      |         ~~~~~~^~~

("Sugiro parênteses em volta de uma atribuição usada como valor verdadeiro ou falso.")

Bug 2: chaves faltando

Sem chaves, um if controla só a próxima instrução, não importa como o código esteja recuado:

1#include <iostream>
2
3int main() {
4    int saldo = 50;
5    int preco = 80;
6    if (saldo < preco)
7        std::cout << "Dinheiro insuficiente.\n";
8        std::cout << "Compra cancelada.\n";
9    std::cout << "Obrigado pela compra!\n";
10}

Parece certo. Agora imagine que o saldo fosse 100: "Compra cancelada." continuaria aparecendo, porque não faz parte do if. O recuo mente. O GCC avisa disso também:

1saldo.cpp: In function 'int main()':
2saldo.cpp:6:5: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
3    6 |     if (saldo < preco)
4      |     ^~
5saldo.cpp:8:9: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
6    8 |         std::cout << "Compra cancelada.\n";
7      |         ^~~

("Esta cláusula if não protege esta instrução, mas ela está recuada de um jeito enganoso, como se estivesse protegida pelo if.")

A versão do mundo real: o "goto fail" da Apple

Em fevereiro de 2014, a Apple lançou uma atualização de segurança urgente para iPhones, iPads e Macs. A causa era uma única linha duplicada no código que verifica conexões seguras (HTTPS):

Uma linha a mais: o bug goto fail da Apple, em 2014. Uma série de comandos if verifica cada etapa de uma conexão segura e, em caso de erro, faz goto fail. Cada linha goto fail é protegida pelo if de cima, exceto uma linha goto fail duplicada que NÃO é protegida e roda sempre. A verificação final, depois dela, nunca é alcançada. Sem chaves, um if protege só a instrução seguinte. A linha duplicada sempre pulava a verificação final, então iPhones e Macs aceitavam conexões seguras falsificadas até a correção, em fevereiro de 2014

O segundo goto fail; não é controlado por nenhum if, então ele roda sempre, pulando a verificação final da assinatura. O resultado: os aparelhos podiam ser enganados e confiar num site falso. É exatamente o Bug 2, num software usado por centenas de milhões de pessoas.

Bug 3: ordem errada numa cadeia de else-if

Você já conheceu este: a escada de notas em que "todo mundo tira D", lá em cima. Quando as faixas se sobrepõem, o teste mais exigente vai primeiro.

Decisões mais limpas

Cláusulas de guarda em vez de aninhamento profundo

Ifs dentro de ifs dentro de ifs escorregam rapidinho para a direita da tela, um formato que os programadores chamam de código flecha. Uma cláusula de guarda resolve cada problema logo no começo e sai cedo:

Aninhamento profundo vs. cláusulas de guarda. À esquerda, código aninhado: se logado, se há itens no carrinho, se tem endereço, faz o pedido, cada um com o seu else, formando uma flecha que escorrega para a direita. À direita, cláusulas de guarda: se não está logado, retorna pedindo login; se o carrinho está vazio, retorna mostrando o carrinho vazio; se não tem endereço, retorna pedindo o endereço; e então faz o pedido, sem recuo, no fim. Os dois fazem a mesma coisa. As cláusulas de guarda resolvem cada problema e saem cedo, então a ação principal fica no fim, sem recuo
1#include <iostream>
2#include <string>
3
4std::string finalizaCompra(bool logado, int itensNoCarrinho, bool temEndereco) {
5    if (!logado) return "Faça login primeiro.";
6    if (itensNoCarrinho == 0) return "Seu carrinho está vazio.";
7    if (!temEndereco) return "Cadastre um endereço de entrega.";
8    return "Pedido feito!";
9}
10
11int main() {
12    std::cout << finalizaCompra(false, 2, true) << "\n";
13    std::cout << finalizaCompra(true, 0, true) << "\n";
14    std::cout << finalizaCompra(true, 2, false) << "\n";
15    std::cout << finalizaCompra(true, 2, true) << "\n";
16}
1Faça login primeiro.
2Seu carrinho está vazio.
3Cadastre um endereço de entrega.
4Pedido feito!

Cada linha se lê como uma regra, e o caminho feliz, "Pedido feito!", fica no fim, onde você espera encontrá-lo.

O operador ternário ? :

Quando tudo o que você precisa é escolher um de dois valores, o operador condicional (ternário) é um if/else compacto:

1#include <iostream>
2#include <string>
3
4int main() {
5    for (int quantidade = 0; quantidade <= 2; quantidade++) {
6        std::string palavra = (quantidade == 1) ? "item" : "itens";
7        std::cout << "Você tem " << quantidade << " " << palavra << " no carrinho\n";
8    }
9}
Você tem 0 itens no carrinho
Você tem 1 item no carrinho
Você tem 2 itens no carrinho

Leia condicao ? a : b como "se a condição, então a, senão b". Guarde-o para escolhas curtas; ternários aninhados ficam ilegíveis rapidinho.

switch: uma variável, muitos valores fixos

Quando você compara uma variável com uma lista de valores específicos, o switch pode ficar mais arrumado que uma cadeia longa de else-if:

1#include <iostream>
2
3int main() {
4    for (int dia = 1; dia <= 7; dia++) {
5        std::cout << "Dia " << dia << ": ";
6        switch (dia) {
7            case 6:
8            case 7:
9                std::cout << "fim de semana!\n";
10                break;
11            case 5:
12                std::cout << "quase lá\n";
13                break;
14            default:
15                std::cout << "dia de aula\n";
16        }
17    }
18}
1Dia 1: dia de aula
2Dia 2: dia de aula
3Dia 3: dia de aula
4Dia 4: dia de aula
5Dia 5: quase lá
6Dia 6: fim de semana!
7Dia 7: fim de semana!

O default faz o papel do else. Não esqueça o break: sem ele, a execução "cai" no próximo caso (que é exatamente o que o case 6: faz de propósito aqui, dividindo a mensagem de fim de semana com o case 7:).

Qual usar?

Qual ferramenta de decisão usar? if: faz algo, ou pula, como em if (chove) abreGuarda();. if/else: um de dois caminhos. else if: um entre vários, em ordem, como faixas de notas e intervalos. switch: uma variável comparada com valores fixos, como switch (dia). O ternário ? :: escolhe um de dois valores, como qtd == 1 ? item : itens. && e ||: combinam condições, como idade >= 13 && temPermissao

Por baixo do capô: por que o processador adivinha

Aqui vai algo que a maioria dos iniciantes nunca ouve falar. Os processadores modernos trabalham em várias instruções ao mesmo tempo, como numa linha de montagem. Quando chegam num if, eles não esperam para descobrir o caminho; eles chutam e continuam trabalhando. Um chute certo sai de graça. Um chute errado obriga a jogar fora o trabalho pela metade e recomeçar. Isso se chama previsão de desvios (branch prediction).

Medimos isso para este artigo. O programa soma todos os valores de 128 para cima entre 32 milhões de números aleatórios de 0 a 255. Depois, ordena os mesmos números e roda exatamente o mesmo if de novo:

O mesmo if, 11 vezes mais lento com dados aleatórios. Somando os valores >= 128 entre 32 milhões de números aleatórios de 0 a 255, embaralhados vs. ordenados, medido para este artigo com GCC 14.1, mediana de 7 execuções. Com um desvio de verdade, compilado com -O2 sem conversão de if: ordem aleatória 116,9 milissegundos, ordenados 10,4 milissegundos. Quando o compilador tirou o desvio, -O2 normal: ordem aleatória 17,6 milissegundos, ordenados 19,0 milissegundos. O processador tenta adivinhar para que lado cada if vai. Com dados ordenados, ele acerta quase sempre; com dados aleatórios, erra metade das vezes, e cada erro joga trabalho fora. Aqui o GCC normalmente troca o desvio por uma instrução sem desvio, e é por isso que o -O2 normal não liga para a ordem

Com um desvio de verdade, os dados aleatórios levaram 11 vezes mais tempo: os mesmos números, o mesmo if, a mesma resposta. Com dados ordenados, o if faz "não, não, não… sim, sim, sim", então os chutes do processador quase sempre acertam. Com dados aleatórios, é cara ou coroa.

Tem uma reviravolta: com a otimização normal, o GCC percebeu o padrão e trocou o if por uma instrução especial sem desvio (um movimento condicional), e a ordem deixou de importar. Os compiladores são espertos, mas nem sempre conseguem fazer isso, e é por isso que código rápido tenta deixar as suas decisões previsíveis.

Um hábito no mesmo espírito: casos comuns primeiro

Numa cadeia de else-if em que os casos não se sobrepõem, colocar o caso mais comum primeiro quer dizer menos verificações no total. Contamos as verificações para um milhão de mensagens de chat simuladas:

Ordene os else-ifs pela frequência com que acontecem. 1.000.000 de mensagens de chat: 80% texto, 12% foto, 5% vídeo, 3% áudio. Média de condições verificadas por mensagem, contada por um programa em C++. Mais comum primeiro, verificando texto, foto, vídeo e else áudio: 1,28 verificação. Mais raro primeiro, verificando áudio, vídeo, foto e else texto: 2,89 verificações. As mesmas respostas, 2,3 vezes mais verificações. Raramente faz diferença na velocidade, mas é um bom hábito, e é exatamente o raciocínio por trás do gráfico de previsão de desvios acima

A mesma ideia em outras linguagens

O comando if é quase universal. Aqui está a verificação de faixa em outras duas linguagens populares.

Python usa elif, dois-pontos e recuo em vez de chaves:

1numero = 42
2if numero < 1:
3    print("Seu número é pequeno demais.")
4elif numero > 100:
5    print("Seu número é grande demais.")
6else:
7    print("Você está na faixa certa!")

JavaScript é quase idêntico ao C++:

1const numero = 42;
2if (numero < 1) {
3  console.log("Seu número é pequeno demais.");
4} else if (numero > 100) {
5  console.log("Seu número é grande demais.");
6} else {
7  console.log("Você está na faixa certa!");
8}

Os dois imprimem Você está na faixa certa!.

C, C++, Java, C#JavaScriptPython
Senão-seelse ifelse ifelif
Bloco{ ... }{ ... }recuo
E / ou / não&& || !&& || !and or not
Igualdade===== (recomendado)==

Hora de praticar

Tente fazer estes antes de espiar as respostas. Copie cada programa num arquivo, compile com g++ -std=c++20 -Wall programa.cpp e rode.

Exercício 1: Adivinhe a saída (aquecimento). O que isto imprime?

1int moedas = 7;
2if (moedas > 10) {
3    std::cout << "rico ";
4} else if (moedas > 5) {
5    std::cout << "tranquilo ";
6} else if (moedas > 0) {
7    std::cout << "apertado ";
8}
9if (moedas % 2 == 1) {
10    std::cout << "ímpar";
11}
12std::cout << "\n";

Exercício 2: FizzBuzz. O aquecimento de entrevista de programação mais famoso do mundo. Para os números de 1 a 15, imprima Fizz para os múltiplos de 3, Buzz para os múltiplos de 5, FizzBuzz para os múltiplos dos dois e o próprio número nos outros casos. (Cuidado com a ordem das condições!)

Exercício 3: Ingressos de cinema. Escreva int precoDoIngresso(int idade, bool ehTerca): menores de 3 anos não pagam; crianças com menos de 12 e idosos com 65 ou mais pagam R$ 8; todo o resto paga R$ 10 nas terças e R$ 15 nos outros dias.

Exercício 4: Pedra, papel e tesoura. Escreva uma função que recebe duas jogadas ('P' para pedra, 'A' para papel ou 'T' para tesoura) e devolve "Empate", "Jogador 1 vence" ou "Jogador 2 vence". Tente fazer com uma única cadeia de || em vez de nove ifs separados.

Exercício 5: Detetive de triângulos (desafio). Dados três lados, imprima equilátero (todos iguais), isósceles (dois iguais), escaleno (todos diferentes) ou não é um triângulo (quando dois lados somados não passam do terceiro).

Quiz rápido

  1. Qual é a diferença entre x = 5 e x == 5?
  2. Numa cadeia if / else if / else, dois blocos podem rodar?
  3. Em if (b != 0 && a / b > 2), o que acontece quando b é 0?
  4. O que !(idade >= 18) quer dizer em português?
  5. Por que os guias de estilo insistem em chaves até em ifs de uma linha?

Respostas

Exercício 1: tranquilo ímpar. A cadeia de else-if para no moedas > 5. O segundo if é separado, não faz parte da cadeia, então também é verificado: 7 é ímpar.

Exercício 2: O caso "os dois" tem que vir primeiro; senão o 15 cairia no % 3 e imprimiria só Fizz.

1#include <iostream>
2
3int main() {
4    for (int numero = 1; numero <= 15; numero++) {
5        if (numero % 15 == 0) {
6            std::cout << "FizzBuzz\n";
7        } else if (numero % 3 == 0) {
8            std::cout << "Fizz\n";
9        } else if (numero % 5 == 0) {
10            std::cout << "Buzz\n";
11        } else {
12            std::cout << numero << "\n";
13        }
14    }
15}
11
22
3Fizz
44
5Buzz
6Fizz
77
88
9Fizz
10Buzz
1111
12Fizz
1313
1414
15FizzBuzz

Exercício 3: As cláusulas de guarda deixam tudo curto. Os bebês vêm primeiro, porque "menos de 12" também valeria para eles.

1#include <iostream>
2
3int precoDoIngresso(int idade, bool ehTerca) {
4    if (idade < 3) return 0;
5    if (idade < 12 || idade >= 65) return 8;
6    if (ehTerca) return 10;
7    return 15;
8}
9
10int main() {
11    std::cout << "Bebê, 2 anos:        R$ " << precoDoIngresso(2, false) << "\n";
12    std::cout << "Criança, 9 anos:     R$ " << precoDoIngresso(9, false) << "\n";
13    std::cout << "Adulto, terça:       R$ " << precoDoIngresso(30, true) << "\n";
14    std::cout << "Adulto, sábado:      R$ " << precoDoIngresso(30, false) << "\n";
15    std::cout << "Avó, 70 anos:        R$ " << precoDoIngresso(70, true) << "\n";
16}
1Bebê, 2 anos:        R$ 0
2Criança, 9 anos:     R$ 8
3Adulto, terça:       R$ 10
4Adulto, sábado:      R$ 15
5Avó, 70 anos:        R$ 8

Exercício 4: Trate o empate e depois liste os três jeitos de o jogador 1 vencer. Qualquer outra coisa quer dizer que o jogador 2 venceu.

1#include <iostream>
2#include <string>
3
4std::string vencedor(char primeiro, char segundo) {
5    if (primeiro == segundo) return "Empate";
6    if ((primeiro == 'P' && segundo == 'T') ||
7        (primeiro == 'T' && segundo == 'A') ||
8        (primeiro == 'A' && segundo == 'P')) {
9        return "Jogador 1 vence";
10    }
11    return "Jogador 2 vence";
12}
13
14int main() {
15    std::cout << "P vs T: " << vencedor('P', 'T') << "\n";
16    std::cout << "A vs T: " << vencedor('A', 'T') << "\n";
17    std::cout << "A vs A: " << vencedor('A', 'A') << "\n";
18}
P vs T: Jogador 1 vence
A vs T: Jogador 2 vence
A vs A: Empate

Exercício 5: Verifique primeiro os triângulos impossíveis, depois a forma mais exigente (os três iguais) antes da mais solta (dois iguais quaisquer).

1#include <iostream>
2#include <string>
3
4std::string tipoDeTriangulo(int primeiro, int segundo, int terceiro) {
5    if (primeiro + segundo <= terceiro || primeiro + terceiro <= segundo || segundo + terceiro <= primeiro) {
6        return "não é um triângulo";
7    }
8    if (primeiro == segundo && segundo == terceiro) return "equilátero";
9    if (primeiro == segundo || segundo == terceiro || primeiro == terceiro) return "isósceles";
10    return "escaleno";
11}
12
13int main() {
14    std::cout << "3 3 3: " << tipoDeTriangulo(3, 3, 3) << "\n";
15    std::cout << "5 5 8: " << tipoDeTriangulo(5, 5, 8) << "\n";
16    std::cout << "3 4 5: " << tipoDeTriangulo(3, 4, 5) << "\n";
17    std::cout << "1 2 10: " << tipoDeTriangulo(1, 2, 10) << "\n";
18}
13 3 3: equilátero
25 5 8: isósceles
33 4 5: escaleno
41 2 10: não é um triângulo

Quiz: (1) x = 5 guarda 5 em x; x == 5 pergunta se x é igual a 5. (2) Não: no máximo um bloco roda e, com um else final, exatamente um. (3) Nada de ruim: b != 0 é false, então o && faz curto-circuito e a divisão nunca acontece. (4) "Menor de 18". (5) Sem chaves, um if controla só a próxima instrução, e um recuo enganoso (como no "goto fail" da Apple) pode esconder isso.

Cola rápida

Eu quero…Escreva
Fazer algo só às vezesif (condicao) { ... }
Escolher entre dois caminhosif (condicao) { ... } else { ... }
Escolher entre muitos caminhosif (a) { ... } else if (b) { ... } else { ... }
Exigir as duas condiçõesa && b
Aceitar qualquer uma das condiçõesa || b
Inverter uma condição!a
Escolher um de dois valorescondicao ? valorSeVerdadeiro : valorSeFalso
Comparar uma variável com valores fixosswitch (variavel) { case 1: ... break; default: ... }
Sair cedoif (problema) return;
Dar nome a uma condição complicadabool ehBissexto = ...; if (ehBissexto) { ... }

Resumindo

O comando if é o jeito de um programa tomar decisões, e quase todo programa está cheio delas:

  • if roda um bloco só quando a condição é verdadeira; else dá o caminho alternativo.
  • else if verifica as condições de cima para baixo, e a primeira verdadeira ganha. A ordem importa.
  • &&, || e ! combinam condições e fazem curto-circuito, o que você pode usar para proteger verificações arriscadas.
  • Cuidado com os clássicos: = vs ==, chaves faltando (lembre do "goto fail") e condições que se sobrepõem na ordem errada. Os avisos do compilador pegam os dois primeiros.
  • Cláusulas de guarda, ? : e switch deixam o código de decisão plano e legível.
  • Decisões previsíveis são rápidas: no nosso teste, o mesmo if rodou 11 vezes mais rápido com dados ordenados.

Decisões mais repetição são o coração da programação. Veja como os ifs trabalham junto com os laços em O Laço For e Os Laços While e Do-While, conheça o primo do if em O Comando Switch (Case) e use tudo isso com dados de verdade em Arrays em C++.

Obrigado pela leitura!

Conhece alguém que vai gostar? Mande para essa pessoa.

Mais artigos

Leia a seguir

Comentários

Seja gentil e específico. Comentários com links de contas novas aparecem depois da análise de um moderador.