Decisões com condicionais
por Tatum WinslowEntenda o conceito
Condicionais fazem o programa escolher o que executar. O if avalia uma expressão entre parênteses e roda o bloco entre chaves só quando ela é verdadeira; o else dá o caminho alternativo, e else if encadeia novos testes. Numa cadeia, as condições são verificadas de cima para baixo e apenas o primeiro bloco verdadeiro é executado.
As condições usam operadores relacionais (==, !=, <, <=, >, >=) e lógicos: && (e), || (ou) e ! (não). O C não tinha um tipo booleano nas primeiras versões: uma comparação produz o int 1 ou 0, e qualquer valor diferente de zero conta como verdadeiro. Por isso if (ativo) funciona com um int, e por isso if (x = 0), com um = só, é um erro clássico que compila.
Quando um único valor inteiro, como um char, escolhe entre várias opções fixas, o switch organiza melhor: cada case é uma constante, o break encerra o bloco e o default cobre o resto. Para escolher entre dois valores numa expressão, há o operador ternário condição ? a : b.
- Numa cadeia
if/else if/else, só o primeiro bloco com condição verdadeira é executado; coloque os casos mais específicos primeiro. - Compare com
==; um=só faz atribuição, eif (x = 0)compila, muda a variável e nunca entra no bloco. - Em C,
0é falso e qualquer outro valor é verdadeiro; comparações produzem1ou0do tipoint. &&e||fazem curto-circuito: a segunda parte só é avaliada se a primeira não decidir o resultado.- No
switch, cadacaseaceita só constantes inteiras e precisa debreak; sem ele, a execução continua nocaseseguinte.
Do conceito à prática
3 exemplos para ver a ideia funcionando.
01Frete da loja com if, else if e else
/* frete.c: if, else if e else para escolher o frete */
#include <stdio.h>
int main(void)
{
int total = 180; /* valor do carrinho em reais */
int distancia = 35; /* km até o endereço de entrega */
int frete;
/* As condições são testadas de cima para baixo; vale a primeira verdadeira */
if (total >= 200) {
frete = 0;
} else if (distancia <= 10) {
frete = 8;
} else if (distancia <= 50) {
frete = 15;
} else {
frete = 30;
}
printf("Carrinho: R$ %d\n", total);
printf("Distância: %d km\n", distancia);
printf("Frete: R$ %d\n", frete);
/* if sozinho, sem else: o bloco só roda quando a condição é verdadeira */
if (frete == 0) {
puts("Frete grátis!");
}
if (total < 200) {
printf("Faltam R$ %d para o frete grátis.\n", 200 - total);
}
return 0;
}
A cadeia escolhe um único valor de frete: com total igual a 180, o primeiro teste falha; distancia <= 10 também falha; distancia <= 50 é verdadeiro, então o frete é 15 e os testes seguintes nem são avaliados. O else final cobre qualquer distância acima de 50 km.
Os dois if do fim são independentes, sem else: cada um decide sozinho se imprime algo. Aqui só o segundo é verdadeiro e o programa mostra que faltam R$ 20 para o frete grátis.
02Regras de empréstimo na biblioteca com &&, || e !
/* emprestimo.c: operadores relacionais e lógicos (&&, ||, !) */
#include <stdio.h>
int main(void)
{
int emprestados = 2;
int limite = 3;
int dias_em_atraso = 0;
int carteirinha_ativa = 1; /* em C, 0 é falso e qualquer outro valor é verdadeiro */
int reservado = 0;
/* && exige que todas as condições sejam verdadeiras */
if (carteirinha_ativa && emprestados < limite && dias_em_atraso == 0) {
puts("Empréstimo liberado.");
} else {
puts("Empréstimo bloqueado.");
}
/* || basta que uma seja verdadeira; ! inverte o valor lógico */
if (!carteirinha_ativa || dias_em_atraso > 0) {
puts("Procure o balcão para regularizar.");
} else {
puts("Cadastro em dia.");
}
/* Renova só se o livro não estiver reservado por outra pessoa */
if (!reservado) {
puts("Renovação disponível.");
}
/* Uma comparação produz um int: 1 (verdadeiro) ou 0 (falso) */
printf("emprestados < limite vale %d\n", emprestados < limite);
printf("dias_em_atraso > 0 vale %d\n", dias_em_atraso > 0);
return 0;
}
O empréstimo só é liberado se as três condições ligadas por && forem verdadeiras ao mesmo tempo. Já o aviso de regularização usa ||: basta a carteirinha estar inativa ou haver atraso. O ! inverte um valor lógico, então !reservado é verdadeiro quando reservado vale 0.
As duas últimas linhas mostram o que uma comparação devolve em C: um int que vale 1 quando é verdadeira e 0 quando é falsa. É por isso que variáveis int como carteirinha_ativa podem ser usadas direto como condição.
03Categoria do produto com switch e operador ternário
/* categoria.c: switch, break, casos agrupados e operador ternário */
#include <stdio.h>
int main(void)
{
char categoria = 'e'; /* L = livro, E = eletrônico, A = alimento */
int preco = 120;
int desconto_pct;
/* switch compara um valor inteiro (char também é) com constantes */
switch (categoria) {
case 'L':
case 'l': /* casos agrupados: maiúscula ou minúscula */
puts("Categoria: livro");
desconto_pct = 10;
break; /* sem break, a execução seguiria para o próximo case */
case 'E':
case 'e':
puts("Categoria: eletrônico");
desconto_pct = 5;
break;
case 'A':
case 'a':
puts("Categoria: alimento");
desconto_pct = 0;
break;
default: /* nenhum case combinou */
puts("Categoria desconhecida");
desconto_pct = 0;
break;
}
int desconto = preco * desconto_pct / 100;
int final = preco - desconto;
printf("Preço: R$ %d | Desconto: R$ %d\n", preco, desconto);
/* Ternário: condição ? valor_se_verdadeiro : valor_se_falso */
printf("Total: R$ %d (%s)\n", final, desconto > 0 ? "com desconto" : "preço cheio");
return 0;
}
O switch compara categoria com cada case e começa a executar no que combinar. Dois case seguidos sem código entre eles compartilham o mesmo bloco, o que aceita a letra maiúscula e a minúscula. O break encerra o switch; sem ele, a execução continuaria pelos blocos de baixo. Com 'e', o desconto é de 5%, ou R$ 6 sobre R$ 120.
Na última linha, o ternário desconto > 0 ? "com desconto" : "preço cheio" escolhe qual texto vai para o %s. Ele é uma expressão, não um comando, por isso cabe dentro do argumento do printf.
Agora é com você
Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.
01Situação de um produto no estoqueFácil
Uma caneca térmica tem 4 unidades em estoque e o mínimo aceitável é 5. Mostre os dados e classifique o produto como esgotado, com estoque baixo ou disponível.
- Guardar a quantidade e o mínimo em variáveis
int. - Usar uma única cadeia
if/else if/elsepara escolher a situação. - Considerar esgotado quando a quantidade for 0, estoque baixo quando for menor que o mínimo e disponível nos demais casos.
#include <stdio.h>
int main(void)
{
int quantidade = 4;
int minimo = 5;
puts("Produto: Caneca térmica");
/* Imprima a quantidade e o mínimo */
/* Escolha a situação com if, else if e else */
return 0;
}
Produto: Caneca térmica
Quantidade: 4
Mínimo: 5
Situação: estoque baixo
Ver dica
O valor 0 também é menor que o mínimo. Pense em qual teste precisa vir primeiro para ele não cair na faixa errada.
Ver resposta
#include <stdio.h>
int main(void)
{
int quantidade = 4;
int minimo = 5;
puts("Produto: Caneca térmica");
printf("Quantidade: %d\n", quantidade);
printf("Mínimo: %d\n", minimo);
/* O caso mais restrito vem primeiro */
if (quantidade == 0) {
puts("Situação: esgotado");
} else if (quantidade < minimo) { /* só chega aqui se não for 0 */
puts("Situação: estoque baixo");
} else {
puts("Situação: disponível");
}
return 0;
}
Passo a passo
quantidadeeminimosão contagens, então ficam emint; o programa imprime os dois antes de decidir, para a saída mostrar os dados usados.- O primeiro teste,
quantidade == 0, usa==(comparação), e não=(atribuição). Se for verdadeiro, imprime "esgotado" e pula o resto da cadeia. - O
else if (quantidade < minimo)só é avaliado quando o primeiro teste falhou, por isso não precisa repetirquantidade > 0. - Com
4 < 5verdadeiro, o programa imprime "estoque baixo" e não olha mais nada. - O
elsefinal não tem condição: ele cobre todos os casos que sobraram (quantidade maior ou igual ao mínimo).
Por que funciona
Uma cadeia if / else if / else executa um único bloco: o da primeira condição verdadeira, de cima para baixo. Colocando o caso mais específico (zero) antes do mais geral (abaixo do mínimo), cada faixa de valores cai em exatamente uma mensagem, sem sobreposição.
Erros comuns
=no lugar de==:if (quantidade = 0)atribui 0 à variável e a condição vale 0 (falso); o produto nunca aparece como esgotado e a quantidade é perdida. O GCC com-Wallavisa; use==.- Ordem invertida: testar
quantidade < minimoprimeiro faz o 0 cair em "estoque baixo", porque 0 também é menor que 5. Teste o zero antes. - Três
ifindependentes: sem oselse, um valor pode imprimir duas situações (0 é "esgotado" e também "estoque baixo"). Encadeie comelse if.
Outra forma de resolver
Dá para guardar o texto numa variável e imprimir uma vez só:
const char *situacao = "disponível";
if (quantidade == 0) {
situacao = "esgotado";
} else if (quantidade < minimo) {
situacao = "estoque baixo";
}
printf("Situação: %s\n", situacao);
É preferível quando a situação será usada em mais de um lugar, como num relatório e num alerta.
Saída esperada
Produto: Caneca térmica
Quantidade: 4
Mínimo: 5
Situação: estoque baixo
02Multa por atraso na bibliotecaMédio
Um livro foi devolvido com 9 dias de atraso por um assinante. Há 2 dias de carência; depois, a multa é de R$ 2 por dia, e assinantes pagam metade. Calcule a multa e diga se um novo empréstimo está liberado: ele é bloqueado com mais de 7 dias de atraso para quem não assina, ou com mais de 14 dias para qualquer leitor.
- Usar um
ifaninhado para aplicar o desconto do assinante só quando houver multa. - Mostrar
simounãopara o assinante com o operador ternário. - Escrever a regra de bloqueio numa única condição com
&&,||e!.
#include <stdio.h>
int main(void)
{
int dias_atraso = 9;
int assinante = 1; /* 1 = sim, 0 = não */
int multa = 0;
/* Calcule a multa com a carência e o desconto */
/* Imprima os dados e a situação do próximo empréstimo */
return 0;
}
Dias de atraso: 9
Assinante: sim
Multa: R$ 7
Novo empréstimo: liberado
Ver dica
Escreva a regra de bloqueio em português primeiro e troque cada "e", "ou" e "não" pelo operador correspondente; use parênteses para agrupar o "e".
Ver resposta
#include <stdio.h>
int main(void)
{
int dias_atraso = 9;
int assinante = 1; /* 1 = sim, 0 = não */
int multa = 0;
/* Até 2 dias de carência; depois, R$ 2 por dia */
if (dias_atraso > 2) {
multa = (dias_atraso - 2) * 2;
if (assinante) {
multa = multa / 2; /* assinante paga metade */
}
}
printf("Dias de atraso: %d\n", dias_atraso);
printf("Assinante: %s\n", assinante ? "sim" : "não");
printf("Multa: R$ %d\n", multa);
/* Bloqueia: mais de 7 dias sem assinatura, ou mais de 14 em qualquer caso */
if ((dias_atraso > 7 && !assinante) || dias_atraso > 14) {
puts("Novo empréstimo: bloqueado");
} else {
puts("Novo empréstimo: liberado");
}
return 0;
}
Passo a passo
assinanteé umintusado como valor lógico: em C, 0 é falso e qualquer outro valor é verdadeiro, entãoif (assinante)basta.- O
if (dias_atraso > 2)aplica a carência: com 9 dias, sobram 7 dias cobrados, e a multa vale7 * 2 = 14. - O
ifaninhado só roda dentro do primeiro: para assinantes,14 / 2dá7. A divisão é inteira, o que serve aqui porque a multa é cobrada em reais inteiros. - O ternário
assinante ? "sim" : "não"escolhe a string direto no argumento doprintf, sem precisar de umifsó para isso. - A condição de bloqueio junta
&&,!e||. Os parênteses deixam claro que o&&forma um grupo:(9 > 7 && !1)é falso e9 > 14também, então o empréstimo é liberado.
Por que funciona
Operadores lógicos combinam comparações simples numa regra só: && exige as duas partes, || aceita qualquer uma e ! inverte. Eles também fazem curto-circuito: se dias_atraso > 7 for falso, o C nem avalia !assinante, porque o && já é falso. O if aninhado expressa uma regra que só faz sentido dentro de outra (o desconto só existe se houver multa).
Erros comuns
- Esquecer a carência:
multa = dias_atraso * 2;cobra os 9 dias e dá R$ 9 para o assinante. Desconte os 2 dias antes de multiplicar. &e|no lugar de&&e||: são operadores bit a bit; às vezes dão o mesmo resultado por acaso, mas não fazem curto-circuito e quebram com valores diferentes de 0 e 1. Use os duplos.!aplicado à comparação inteira:!dias_atraso > 7é lido como(!dias_atraso) > 7, que é sempre falso. Para negar uma comparação, escreva!(dias_atraso > 7)oudias_atraso <= 7.
Outra forma de resolver
O desconto do assinante também pode ser um ternário:
multa = assinante ? multa / 2 : multa;
Fica mais curto, mas o if aninhado é mais fácil de ler e de estender quando a regra ganha outras faixas de desconto.
Saída esperada
Dias de atraso: 9
Assinante: sim
Multa: R$ 7
Novo empréstimo: liberado
03Cupom de desconto no carrinhoDesafio
Um carrinho de R$ 250 recebeu o cupom 'v'. Use um switch para tratar os cupons P (10% com compra mínima de R$ 100), V (R$ 30 com compra mínima de R$ 150) e F (frete grátis), aceitando maiúsculas e minúsculas, e calcule o frete: grátis pelo cupom ou quando o valor com desconto for de pelo menos R$ 200; caso contrário, R$ 20.
- Escolher o cupom com
switch, agrupando oscaseda letra maiúscula e da minúscula e comdefaultpara cupom inválido. - Conferir a compra mínima com um
ifdentro docasee imprimir a mensagem do cupom (aplicado ou o valor exigido). - Calcular o frete com o operador ternário e uma condição com
||. - Imprimir as linhas na ordem da saída esperada, com o total igual ao valor com desconto mais o frete.
#include <stdio.h>
int main(void)
{
int subtotal = 250;
char cupom = 'v';
int desconto = 0;
int frete_gratis = 0;
printf("Subtotal: R$ %d\n", subtotal);
/* Trate o cupom com switch */
/* Calcule o frete e o total */
return 0;
}
Subtotal: R$ 250
Cupom VALOR aplicado
Desconto: R$ 30
Frete: grátis
Total a pagar: R$ 220
Ver dica
case só aceita constantes, então a compra mínima não pode ir no rótulo do case; ela é um if dentro do bloco.
Ver resposta
#include <stdio.h>
int main(void)
{
int subtotal = 250;
char cupom = 'v';
int desconto = 0;
int frete_gratis = 0;
printf("Subtotal: R$ %d\n", subtotal);
switch (cupom) {
case 'P':
case 'p': /* maiúscula ou minúscula */
if (subtotal >= 100) {
desconto = subtotal * 10 / 100;
puts("Cupom PERCENTUAL aplicado");
} else {
puts("Cupom exige R$ 100 em compras");
}
break;
case 'V':
case 'v':
if (subtotal >= 150) {
desconto = 30;
puts("Cupom VALOR aplicado");
} else {
puts("Cupom exige R$ 150 em compras");
}
break;
case 'F':
case 'f':
frete_gratis = 1;
puts("Cupom FRETE aplicado");
break;
default:
puts("Cupom inválido");
break;
}
int com_desconto = subtotal - desconto;
/* Frete grátis pelo cupom ou por compra de R$ 200 após o desconto */
int frete = (frete_gratis || com_desconto >= 200) ? 0 : 20;
printf("Desconto: R$ %d\n", desconto);
if (frete == 0) {
puts("Frete: grátis");
} else {
printf("Frete: R$ %d\n", frete);
}
printf("Total a pagar: R$ %d\n", com_desconto + frete);
return 0;
}
Passo a passo
- O subtotal é impresso primeiro, e só depois o
switchdecide o cupom; assim a mensagem do cupom aparece na segunda linha. switch (cupom)compara ocharcom cadacase. Os parescase 'V':ecase 'v':sem nada entre eles fazem as duas letras caírem no mesmo bloco.- Dentro de cada
case, umifconfere o valor mínimo da compra: o cupom pode existir e mesmo assim não valer para este carrinho. - O
breakno fim de cada bloco encerra oswitch; sem ele, o cupomVcontinuaria executando o bloco doFe daria frete grátis por engano. - O
defaulttrata qualquer letra não prevista, para o programa nunca ficar em silêncio. - O ternário calcula o frete numa linha:
(0 || 220 >= 200)é verdadeiro, entãofretevale0. - O
iffinal escolhe entre "grátis" e o valor, e o total soma o valor com desconto e o frete:220 + 0.
Por que funciona
O switch é a ferramenta certa quando um único valor inteiro (um char, aqui) escolhe entre várias opções fixas: cada case é um ponto de entrada e o break é a saída. Já as regras com faixas e combinações (>=, ||) ficam com if e com o ternário, porque case só aceita constantes, não comparações como subtotal >= 150.
Juntando os dois, cada parte da regra de negócio fica onde é mais legível: o tipo do cupom no switch, as condições de valor nos if e a escolha simples entre dois números no ternário.
Erros comuns
- Esquecer o
break: sem ele nocase 'v', a execução "cai" nocase 'f', imprime "Cupom FRETE aplicado" também e ligafrete_gratis. O GCC com-Wimplicit-fallthroughavisa; coloquebreakem todocase. - Comparação no
case:case subtotal >= 150:não compila (case label does not reduce to an integer constant). Faixas de valores vão numifdentro docase. - Aspas duplas no
case:case "v":também não compila, porque"v"é uma string, não umchar. Use'v'. - Frete calculado sobre o subtotal:
subtotal >= 200daria frete grátis mesmo se o desconto levasse a compra para R$ 190. A regra pede o valor depois do desconto.
Outra forma de resolver
Sem switch, a escolha do cupom vira uma cadeia de if / else if:
if (cupom == 'V' || cupom == 'v') {
/* ... */
} else if (cupom == 'P' || cupom == 'p') {
/* ... */
}
Funciona igual e é preferível quando as condições não são só igualdade com constantes; com várias letras fixas, o switch deixa as opções alinhadas e mais fáceis de conferir.
Saída esperada
Subtotal: R$ 250
Cupom VALOR aplicado
Desconto: R$ 30
Frete: grátis
Total a pagar: R$ 220