C# e .NET no Console: Datas, Entrada, Lógica e Laços

Guia prático com 12 exercícios comentados para consolidar fundamentos operacionais.

Por Fábio Linhares • Instituto Infnet

Apresentacao das questoes

Estas questões não foram montadas para treinar “comandos soltos” de C#. Elas foram organizadas para levar o leitor a um ponto mais importante: sair do nível em que apenas escreve algo no console e chegar ao nível em que constrói programas completos, corretos e verificáveis. Ao longo da lista, ele terá de lidar com manipulação de datas usando DateOnly, DateTime e TimeSpan, entrada de dados com Console.ReadLine(), cálculos numéricos com formatação adequada, decisões com estruturas condicionais, repetição com laços e até controle de estado simples em um jogo com Random.

O primeiro desafio é aprender a respeitar o comportamento real dos dados. Datas, por exemplo, não se comportam como números quaisquer: idade exata, diferença entre datas e próximo aniversário exigem atenção ao calendário, aos anos bissextos e à ideia de intervalo real, não apenas a contas apressadas. Essa parte do material força o leitor a perceber uma distinção central em programação: uma solução pode até “parecer funcionar” em casos fáceis, mas só está correta de fato quando continua funcionando nos casos de borda.

O segundo desafio é compreender que entrada do usuário nunca deve ser tratada como algo trivial. Quando o programa pede nome, idade, temperatura, peso, altura ou salário, ele está pedindo mais do que valores: está exigindo que o aluno transforme texto digitado em informação útil, consistente e pronta para ser processada. Isso desenvolve uma qualidade muito importante em quem programa: parar de confiar cegamente na entrada e passar a pensar em leitura, interpretação, validação e apresentação como partes inseparáveis da solução.

Em seguida, as questões cobram domínio sobre regras de decisão. Verificar se um número é par ou ímpar, classificar uma nota, enquadrar um IMC em faixas e calcular descontos sobre salário parecem tarefas simples à primeira vista, mas todas exigem uma mesma competência profunda: escrever regras sem buracos, sem sobreposições e com limites claros. Aqui o leitor começa a desenvolver raciocínio de negócio, isto é, a capacidade de pegar uma regra verbal e traduzi-la para uma estrutura lógica precisa, coerente e testável.

A parte final acrescenta outro patamar de maturidade: repetição e estado. Na contagem regressiva e na tabuada, o leitor precisa mostrar que entende laços como mecanismo controlado, com início, evolução e parada. No jogo de adivinhação, surge algo ainda mais interessante: além do laço, é necessário manter um estado interno, reagir a palpites sucessivos, comparar valores e fornecer feedback até que a condição de sucesso seja alcançada. Nesse ponto, o aluno deixa de apenas “executar instruções” e começa, de fato, a modelar comportamento de programa.

Sequência Operacional Base
ler -> validar -> transformar -> calcular -> decidir -> exibir
A cada exercício, mantenha o mesmo ciclo: entender a regra, codificar sem atalho e conferir comportamento com casos de teste simples.
Nota sobre decimais

Nos exercícios com double.TryParse, o parse depende da cultura numérica da máquina. Se a entrada vier como 1,75 em um ambiente que espera 1.75, normalize o separador decimal antes do parse ou use cultura explícita.

EXERCÍCIO 01
Cálculo de idade precisa
Ela não quer apenas “subtrair anos”. Ela quer saber se o aluno entende que idade humana não é diferença bruta de dias dividida por 365. Idade exata precisa comparar calendário.
using System;
using System.Globalization;

Console.Write("Digite sua data de nascimento (dd/MM/yyyy): ");
string? entrada = Console.ReadLine();

if (!DateOnly.TryParseExact(
        entrada,
        "dd/MM/yyyy",
        CultureInfo.InvariantCulture,
        DateTimeStyles.None,
        out DateOnly nascimento))
{
    Console.WriteLine("Data inválida.");
    return;
}

DateOnly hoje = DateOnly.FromDateTime(DateTime.Today);

if (nascimento > hoje)
{
    Console.WriteLine("A data de nascimento não pode estar no futuro.");
    return;
}

int anos = hoje.Year - nascimento.Year;
if (hoje < nascimento.AddYears(anos))
{
    anos--;
}

DateOnly baseData = nascimento.AddYears(anos);

int meses = 0;
while (baseData.AddMonths(1) <= hoje)
{
    baseData = baseData.AddMonths(1);
    meses++;
}

int dias = hoje.DayNumber - baseData.DayNumber;

Console.WriteLine($"Idade exata: {anos} anos, {meses} meses e {dias} dias.");
O que a questão pede
Ela não quer apenas “subtrair anos”. Ela quer saber se o aluno entende que idade humana não é diferença bruta de dias dividida por 365. Idade exata precisa comparar calendário.
Conceito cobrado
Transformar regra textual em lógica de programa com condições claras e comportamento verificável.
Estrutura dos dados

nascimento, hoje, anos, baseData, meses, dias

Como pensar
1. Ler a data. 2. Validar. 3. Pegar a data de hoje. 4. Calcular os anos completos. 5. A partir disso, avançar mês a mês. 6. O resto são os dias.
Como validar
Porque ela produz uma decomposição humana do intervalo: primeiro fecha anos completos, depois meses completos e só então calcula o resto em dias.
Tabela de Evidência
Entrada Saída esperada
Data de nascimento igual a hoje 0 anos, 0 meses e 0 dias.
29/02 em ano atual não bissexto A lógica continua válida sem quebrar o calendário.
Data futura Mensagem de data inválida, sem cálculo.
Variáveis-chave
  • nascimento: data lida e validada.
  • hoje: referência do calendário atual.
  • anos e baseData: fecham anos completos antes do ajuste fino.
  • meses e dias: completam a decomposição final.
Erro comum: Pular validação de entrada e assumir que todo valor digitado já chega no formato correto.
Caso de borda: Nascimento em 29/02 e ano atual não bissexto.
Consolidação: Faça a mesma lógica, mas exibindo também o total de dias de vida.
EXERCÍCIO 02
Dias até o próximo aniversário
Ela quer verificar se o aluno sabe construir uma data futura a partir de outra: “qual é o próximo aniversário a partir de hoje?”.
using System;
using System.Globalization;

Console.Write("Digite sua data de nascimento (dd/MM/yyyy): ");
string? entrada = Console.ReadLine();

if (!DateOnly.TryParseExact(
        entrada,
        "dd/MM/yyyy",
        CultureInfo.InvariantCulture,
        DateTimeStyles.None,
        out DateOnly nascimento))
{
    Console.WriteLine("Data inválida.");
    return;
}

DateOnly hoje = DateOnly.FromDateTime(DateTime.Today);

DateOnly CriarAniversarioNoAno(int ano, int mes, int dia)
{
    int ultimoDia = DateTime.DaysInMonth(ano, mes);
    int diaAjustado = Math.Min(dia, ultimoDia);
    return new DateOnly(ano, mes, diaAjustado);
}

DateOnly proximoAniversario = CriarAniversarioNoAno(
    hoje.Year,
    nascimento.Month,
    nascimento.Day);

if (proximoAniversario < hoje)
{
    proximoAniversario = CriarAniversarioNoAno(
        hoje.Year + 1,
        nascimento.Month,
        nascimento.Day);
}

int diasRestantes = proximoAniversario.DayNumber - hoje.DayNumber;

Console.WriteLine($"Faltam {diasRestantes} dia(s) para o seu próximo aniversário.");
O que a questão pede
Ela quer verificar se o aluno sabe construir uma data futura a partir de outra: “qual é o próximo aniversário a partir de hoje?”.
Conceito cobrado
Transformar regra textual em lógica de programa com condições claras e comportamento verificável.
Estrutura dos dados

hoje, proximoAniversario, diasRestantes

Como pensar
1. Ler a data de nascimento. 2. Extrair mês e dia. 3. Montar o aniversário no ano atual. 4. Se ele já passou, montar no próximo ano. 5. Subtrair as datas em dias.
Como validar
Porque “próximo aniversário” é uma data reconstruída no calendário atual. Se já passou, o algoritmo projeta a mesma combinação mês/dia para o ano seguinte.
Tabela de Evidência
Entrada Saída esperada
Aniversário hoje 0 dia(s) restantes.
Aniversário já passou no ano atual A data projetada muda para o próximo ano.
Nascimento em 29/02 O dia é ajustado para o último dia válido de fevereiro.
Variáveis-chave
  • nascimento: fornece mês e dia do aniversário.
  • hoje: define o ponto de partida do cálculo.
  • proximoAniversario: data projetada no ano atual ou no próximo.
  • diasRestantes: diferença final em dias.
Erro comum: Usar apenas o ano de nascimento. O próximo aniversário não depende do ano de nascimento; depende do mês e do dia, projetados no ano atual ou no próximo.
Caso de borda: Nascimento em 29/02.
Consolidação: Altere o programa para exibir também a data do próximo aniversário.
EXERCÍCIO 03
Diferença entre duas datas
Aqui há uma armadilha boa. TimeSpan resolve muito bem total de dias, mas não devolve “X meses e Y anos” com semântica humana. Isso precisa de lógica de calendário.
using System;
using System.Globalization;

Console.Write("Digite a primeira data (dd/MM/yyyy): ");
string? entrada1 = Console.ReadLine();

Console.Write("Digite a segunda data (dd/MM/yyyy): ");
string? entrada2 = Console.ReadLine();

if (!DateTime.TryParseExact(
        entrada1,
        "dd/MM/yyyy",
        CultureInfo.InvariantCulture,
        DateTimeStyles.None,
        out DateTime data1) ||
    !DateTime.TryParseExact(
        entrada2,
        "dd/MM/yyyy",
        CultureInfo.InvariantCulture,
        DateTimeStyles.None,
        out DateTime data2))
{
    Console.WriteLine("Uma ou ambas as datas são inválidas.");
    return;
}

if (data1 > data2)
{
    (data1, data2) = (data2, data1);
}

TimeSpan intervaloTotal = data2.Date - data1.Date;
int totalDias = intervaloTotal.Days;

int anos = data2.Year - data1.Year;
if (data2.Date < data1.Date.AddYears(anos))
{
    anos--;
}

DateTime baseData = data1.Date.AddYears(anos);

int meses = 0;
while (baseData.AddMonths(1) <= data2.Date)
{
    baseData = baseData.AddMonths(1);
    meses++;
}

int dias = (data2.Date - baseData).Days;

Console.WriteLine("Diferença entre as datas:");
Console.WriteLine($"Total de dias: {totalDias}");
Console.WriteLine($"Intervalo: {anos} ano(s), {meses} mes(es) e {dias} dia(s)");
O que a questão pede
Aqui há uma armadilha boa. TimeSpan resolve muito bem total de dias, mas não devolve “X meses e Y anos” com semântica humana. Isso precisa de lógica de calendário.
Conceito cobrado
Aqui há uma armadilha boa. TimeSpan resolve muito bem total de dias, mas não devolve “X meses e Y anos” com semântica humana. Isso precisa de lógica de calendário.
Estrutura dos dados

data1, data2, intervaloTotal, totalDias, anos, meses, dias

Como pensar
Separe em etapas: ler entrada, validar faixa/formato, aplicar regra, decidir caso e exibir resultado final.
Como validar
Porque produz duas leituras coerentes do mesmo intervalo: totalDias mede a diferença bruta e anos/meses/dias mostram a leitura por calendário.
Tabela de Evidência
Entrada Saída esperada
Mesma data nas duas entradas Total de dias: 0 e intervalo zerado.
Usuário informa primeiro a data maior O programa reordena internamente e calcula sem erro.
28/02/2024 e 01/03/2024 O total de dias considera o 29/02 do ano bissexto.
Variáveis-chave
  • data1 e data2: datas já ordenadas para o cálculo.
  • intervaloTotal e totalDias: diferença bruta em dias.
  • baseData: ponto de apoio para avançar mês a mês.
  • anos, meses e dias: decomposição final.
Erro comum: * Achar que TimeSpan.Days / 30 dá meses corretos. * Não ordenar as datas quando o usuário digita a maior primeiro. * Ignorar a parte .Date e deixar horário interferir.
Caso de borda: Uma data em ano bissexto e outra depois de fevereiro.
Consolidação: Exiba qual das duas datas é a mais antiga antes de mostrar o intervalo.
EXERCÍCIO 04
Formulário de cadastro simples
Ela parece simples, mas mede uma coisa central: saber capturar entradas diferentes e apresentá-las com clareza.
using System;

Console.Write("Nome: ");
string? nome = Console.ReadLine();

if (string.IsNullOrWhiteSpace(nome))
{
    Console.WriteLine("Nome inválido.");
    return;
}

Console.Write("Idade: ");
if (!int.TryParse(Console.ReadLine(), out int idade) || idade < 0)
{
    Console.WriteLine("Idade inválida.");
    return;
}

Console.Write("Telefone: ");
string? telefone = Console.ReadLine();

if (string.IsNullOrWhiteSpace(telefone))
{
    Console.WriteLine("Telefone inválido.");
    return;
}

Console.Write("E-mail: ");
string? email = Console.ReadLine();

if (string.IsNullOrWhiteSpace(email) || !email.Contains("@"))
{
    Console.WriteLine("E-mail inválido.");
    return;
}

Console.WriteLine();
Console.WriteLine("=== DADOS CADASTRADOS ===");
Console.WriteLine($"Nome     : {nome}");
Console.WriteLine($"Idade    : {idade}");
Console.WriteLine($"Telefone : {telefone}");
Console.WriteLine($"E-mail   : {email}");
O que a questão pede
Ela parece simples, mas mede uma coisa central: saber capturar entradas diferentes e apresentá-las com clareza.
Conceito cobrado
Ela parece simples, mas mede uma coisa central: saber capturar entradas diferentes e apresentá-las com clareza.
Estrutura dos dados

nome, idade, telefone, email

Como pensar
* Nome, telefone e e-mail podem entrar como string. * Idade deve virar int. * O mínimo pedagógico é validar vazio e idade negativa.
Como validar
Porque transforma entrada textual em dados úteis e organiza a saída em um resumo final. O coração do exercício é ler, validar cada campo e só então exibir.
Tabela de Evidência
Entrada Saída esperada
Nome, idade, telefone e e-mail válidos Resumo final com os quatro campos.
Nome vazio Mensagem de nome inválido.
Idade negativa ou texto Mensagem de idade inválida.
Variáveis-chave
  • nome: precisa sair de nulo/branco para texto útil.
  • idade: único campo convertido para inteiro.
  • telefone e email: permanecem string, mas com validação mínima.
Erro comum: Pular validação de entrada e assumir que todo valor digitado já chega no formato correto.
Caso de borda: Idade 0.
Consolidação: Adicione endereço e CEP ao formulário.
EXERCÍCIO 05
Conversor de temperatura
Se o aluno entende fórmula, tipo numérico e formatação.
using System;
using System.Globalization;

bool TryReadDouble(string? texto, out double valor)
{
    return double.TryParse(
               texto,
               NumberStyles.Float | NumberStyles.AllowThousands,
               new CultureInfo("pt-BR"),
               out valor) ||
           double.TryParse(
               texto,
               NumberStyles.Float | NumberStyles.AllowThousands,
               CultureInfo.InvariantCulture,
               out valor);
}

Console.Write("Digite a temperatura em Celsius: ");

if (!TryReadDouble(Console.ReadLine(), out double celsius))
{
    Console.WriteLine("Valor inválido.");
    return;
}

double fahrenheit = celsius * 9.0 / 5.0 + 32.0;
double kelvin = celsius + 273.15;

Console.WriteLine($"Fahrenheit: {fahrenheit:F2} °F");
Console.WriteLine($"Kelvin    : {kelvin:F2} K");
O que a questão pede
Se o aluno entende fórmula, tipo numérico e formatação.
Conceito cobrado
Transformar regra textual em lógica de programa com condições claras e comportamento verificável.
Estrutura dos dados

celsius, fahrenheit, kelvin

Como pensar
Se há decimal, use double.
Como validar
Porque usa a fórmula certa e um tipo capaz de armazenar decimais, além de exibir o resultado com duas casas.
Tabela de Evidência
Entrada Saída esperada
0 32.00 °F e 273.15 K.
100 212.00 °F e 373.15 K.
Texto inválido Mensagem de valor inválido.
Variáveis-chave
  • celsius: entrada decimal original.
  • fahrenheit e kelvin: resultados derivados da mesma leitura.
  • Em ambiente com cultura diferente, observe o separador decimal aceito por double.TryParse.
Erro comum: Usar int e cair em divisão inteira. Em C#, 9/5 com inteiros vale 1, não 1.8.
Caso de borda: -273.15 °C, o zero absoluto.
Consolidação: Adicione também conversão para Rankine.
EXERCÍCIO 06
Cálculo de IMC
Resolver cálculo de IMC com entrada, processamento e saída coerentes para o problema proposto.
using System;
using System.Globalization;

bool TryReadDouble(string? texto, out double valor)
{
    return double.TryParse(
               texto,
               NumberStyles.Float | NumberStyles.AllowThousands,
               new CultureInfo("pt-BR"),
               out valor) ||
           double.TryParse(
               texto,
               NumberStyles.Float | NumberStyles.AllowThousands,
               CultureInfo.InvariantCulture,
               out valor);
}

Console.Write("Digite seu peso em kg: ");
if (!TryReadDouble(Console.ReadLine(), out double peso) || peso <= 0)
{
    Console.WriteLine("Peso inválido.");
    return;
}

Console.Write("Digite sua altura em metros: ");
if (!TryReadDouble(Console.ReadLine(), out double altura) || altura <= 0)
{
    Console.WriteLine("Altura inválida.");
    return;
}

double imc = peso / (altura * altura);

string classificacao;
if (imc < 18.5)
    classificacao = "Baixo peso";
else if (imc < 25.0)
    classificacao = "Peso normal";
else if (imc < 30.0)
    classificacao = "Sobrepeso";
else if (imc < 35.0)
    classificacao = "Obesidade grau I";
else if (imc < 40.0)
    classificacao = "Obesidade grau II";
else
    classificacao = "Obesidade grau III";

Console.WriteLine($"IMC: {imc:F2}");
Console.WriteLine($"Classificação: {classificacao}");
O que a questão pede
Resolver cálculo de IMC com entrada, processamento e saída coerentes para o problema proposto.
Conceito cobrado
* < 18.5 → Baixo peso * < 25 → Peso normal * < 30 → Sobrepeso * < 35 → Obesidade grau I * < 40 → Obesidade grau II * >= 40 → Obesidade grau III
Estrutura dos dados

peso, altura, imc, classificacao

Como pensar
Separe em etapas: ler entrada, validar faixa/formato, aplicar regra, decidir caso e exibir resultado final.
Como validar
Porque calcula com a fórmula pedida e aplica faixas sem sobreposição: cada valor de IMC cai em exatamente uma classe.
Tabela de Evidência
Entrada Saída esperada
70 kg e 1.75 m IMC perto de 22.86 e classificação normal.
Altura 0 Mensagem de altura inválida.
Entrada negativa Bloqueio antes do cálculo.
Variáveis-chave
  • peso e altura: entradas decimais a validar.
  • imc: valor calculado antes da classificação.
  • classificacao: resultado textual decidido pelas faixas.
Erro comum: Pular validação de entrada e assumir que todo valor digitado já chega no formato correto.
Caso de borda: Altura 0 ou negativa.
Consolidação: Peça sexo e idade, mas sem mudar a fórmula; só organize melhor a saída.
EXERCÍCIO 07
Verificador de número par ou ímpar
Se o aluno conhece o operador resto %.
using System;

Console.Write("Digite um número inteiro: ");

if (!int.TryParse(Console.ReadLine(), out int numero))
{
    Console.WriteLine("Número inválido.");
    return;
}

if (numero % 2 == 0)
    Console.WriteLine("O número é par.");
else
    Console.WriteLine("O número é ímpar.");
O que a questão pede
Se o aluno conhece o operador resto %.
Conceito cobrado
Um número é par quando o resto da divisão por 2 é zero.
Estrutura dos dados

numero

Como pensar
Separe em etapas: ler entrada, validar faixa/formato, aplicar regra, decidir caso e exibir resultado final.
Como validar
Teste com pelo menos um caso esperado, um caso de limite e um caso inválido para confirmar consistência da regra do resto.
Tabela de Evidência
Entrada Saída esperada
0 Número par.
-3 Número ímpar.
Texto inválido Mensagem de número inválido.
Variáveis-chave
  • numero: valor inteiro já validado.
  • numero % 2: prova operacional da decisão.
Erro comum: Pular validação de entrada e assumir que todo valor digitado já chega no formato correto.
Caso de borda: 0, que é par.
Consolidação: Exiba também se o número é positivo, negativo ou zero.
EXERCÍCIO 08
Classificação de nota escolar
As categorias foram dadas, mas os intervalos não. Então o aluno precisa criar faixas coerentes, completas e sem buracos.
using System;
using System.Globalization;

bool TryReadDouble(string? texto, out double valor)
{
    return double.TryParse(
               texto,
               NumberStyles.Float | NumberStyles.AllowThousands,
               new CultureInfo("pt-BR"),
               out valor) ||
           double.TryParse(
               texto,
               NumberStyles.Float | NumberStyles.AllowThousands,
               CultureInfo.InvariantCulture,
               out valor);
}

Console.Write("Digite uma nota de 0 a 10: ");

if (!TryReadDouble(Console.ReadLine(), out double nota) || nota < 0 || nota > 10)
{
    Console.WriteLine("Nota inválida.");
    return;
}

string classificacao;

if (nota < 5.0)
    classificacao = "Insuficiente";
else if (nota < 7.0)
    classificacao = "Regular";
else if (nota < 9.0)
    classificacao = "Bom";
else
    classificacao = "Excelente";

Console.WriteLine($"Classificação: {classificacao}");
O que a questão pede
As categorias foram dadas, mas os intervalos não. Então o aluno precisa criar faixas coerentes, completas e sem buracos.
Conceito cobrado
* 0 até menor que 5 → Insuficiente * 5 até menor que 7 → Regular * 7 até menor que 9 → Bom * 9 até 10 → Excelente
Estrutura dos dados

nota, classificacao

Como pensar
Separe em etapas: ler entrada, validar faixa/formato, aplicar regra, decidir caso e exibir resultado final.
Como validar
Porque cobre todo o intervalo de 0 a 10, sem sobreposição e sem região esquecida: toda nota válida entra em exatamente uma faixa.
Tabela de Evidência
Entrada Saída esperada
4.9 Insuficiente.
7.0 Bom.
10 Excelente.
Variáveis-chave
  • nota: entrada decimal a manter entre 0 e 10.
  • classificacao: texto final decidido pelas faixas.
  • Observe os pontos de fronteira: 5.0, 7.0, 9.0 e 10.0.
Erro comum: Fazer faixas do tipo nota > 5 && nota < 7 e esquecer os valores exatos 5, 7, 9 ou 10. Prefira limites encadeados sem buracos.
Caso de borda: 0 e 10.
Consolidação: Adicione aprovação/reprovação além da classificação.
EXERCÍCIO 09
Calculadora de salário líquido
Ela mede se o aluno sabe escrever regras de negócio por faixas.
using System;
using System.Globalization;

bool TryReadDouble(string? texto, out double valor)
{
    return double.TryParse(
               texto,
               NumberStyles.Float | NumberStyles.AllowThousands,
               new CultureInfo("pt-BR"),
               out valor) ||
           double.TryParse(
               texto,
               NumberStyles.Float | NumberStyles.AllowThousands,
               CultureInfo.InvariantCulture,
               out valor);
}

Console.Write("Digite o salário bruto: ");

if (!TryReadDouble(Console.ReadLine(), out double salarioBruto) || salarioBruto < 0)
{
    Console.WriteLine("Salário inválido.");
    return;
}

double aliquota;

if (salarioBruto <= 2000.00)
    aliquota = 0.00;
else if (salarioBruto <= 3500.00)
    aliquota = 0.075;
else if (salarioBruto <= 5000.00)
    aliquota = 0.15;
else
    aliquota = 0.225;

double desconto = salarioBruto * aliquota;
double salarioLiquido = salarioBruto - desconto;

Console.WriteLine($"Salário bruto : R$ {salarioBruto:F2}");
Console.WriteLine($"Alíquota      : {aliquota * 100:F1}%");
Console.WriteLine($"Desconto      : R$ {desconto:F2}");
Console.WriteLine($"Salário líquido: R$ {salarioLiquido:F2}");
O que a questão pede
Ela mede se o aluno sabe escrever regras de negócio por faixas.
Conceito cobrado
Ela mede se o aluno sabe escrever regras de negócio por faixas.
Estrutura dos dados

salarioBruto, aliquota, desconto, salarioLiquido

Como pensar
Separe em etapas: ler entrada, validar faixa/formato, aplicar regra, decidir caso e exibir resultado final.
Como validar
Porque implementa exatamente o que o enunciado pede no plano lógico: escolher faixa, calcular desconto e produzir o líquido.
Tabela de Evidência
Entrada Saída esperada
2000.00 Alíquota 0% e desconto zerado.
3500.00 Alíquota 7.5%, desconto 262.50 e líquido 3237.50.
5000.00 Alíquota 15% e líquido 4250.00.
Variáveis-chave
  • salarioBruto: valor de entrada usado para escolher a faixa.
  • aliquota: percentual aplicado ao cálculo.
  • desconto e salarioLiquido: resultados finais a conferir.
Erro comum: Pular validação de entrada e assumir que todo valor digitado já chega no formato correto.
Caso de borda: Exatamente nos limites: 2000, 3500, 5000.
Consolidação: Faça uma versão progressiva, por faixas acumuladas, e compare com a versão simples.
EXERCÍCIO 10
Contagem regressiva
Se o aluno sabe usar laço com condição de parada correta.
using System;

Console.Write("Digite um número inteiro não negativo: ");

if (!int.TryParse(Console.ReadLine(), out int numero) || numero < 0)
{
    Console.WriteLine("Número inválido.");
    return;
}

for (int i = numero; i >= 0; i--)
{
    Console.Write(i);

    if (i > 0)
        Console.Write(", ");
}

Console.WriteLine();
O que a questão pede
Se o aluno sabe usar laço com condição de parada correta.
Conceito cobrado
Transformar regra textual em lógica de programa com condições claras e comportamento verificável.
Estrutura dos dados

numero, i

Como pensar
Separe em etapas: ler entrada, validar faixa/formato, aplicar regra, decidir caso e exibir resultado final.
Como validar
Porque o laço desce de numero até 0, inclusive. O separador só aparece quando ainda há próximo elemento.
Tabela de Evidência
Entrada Saída esperada
3 3, 2, 1, 0.
0 Saída contendo apenas 0.
-1 Mensagem de número inválido.
Variáveis-chave
  • numero: valor inicial da regressão.
  • i: contador que desce até zero.
Erro comum: * parar em 1 e esquecer o 0; * deixar vírgula sobrando no final; * permitir número negativo sem decidir o que fazer.
Caso de borda: Entrada 0.
Consolidação: Faça a mesma saída em ordem crescente de 0 até o número.
EXERCÍCIO 11
Tabuada interativa
Se o aluno sabe repetir um cálculo mudando apenas uma variável de controle.
using System;

Console.Write("Digite um número inteiro: ");

if (!int.TryParse(Console.ReadLine(), out int numero))
{
    Console.WriteLine("Número inválido.");
    return;
}

for (int i = 1; i <= 10; i++)
{
    Console.WriteLine($"{numero} x {i} = {numero * i}");
}
O que a questão pede
Se o aluno sabe repetir um cálculo mudando apenas uma variável de controle.
Conceito cobrado
Transformar regra textual em lógica de programa com condições claras e comportamento verificável.
Estrutura dos dados

numero, i

Como pensar
Leia o número uma vez e repita i de 1 até 10. O valor fixo é numero; o valor que muda a cada linha é i, e o produto forma a saída.
Como validar
Porque a cada iteração muda só o multiplicador. O número-base fica fixo e a saída prova a repetição controlada.
Tabela de Evidência
Entrada Saída esperada
5 Linhas de 5 x 1 até 5 x 10.
0 Todas as multiplicações resultam em zero.
Texto inválido Mensagem de número inválido.
Variáveis-chave
  • numero: fator fixo da tabuada.
  • i: multiplicador que varia de 1 a 10.
  • numero * i: resultado calculado em cada linha.
Erro comum: Pular validação de entrada e assumir que todo valor digitado já chega no formato correto.
Caso de borda: Número 0.
Consolidação: Permita que o usuário escolha até qual multiplicador quer ir.
EXERCÍCIO 12
Jogo de adivinhação
Ela combina leitura, validação, laço, comparação e estado simples em um único programa de console.
using System;

Random random = new Random();
int numeroSecreto = random.Next(1, 101); // 1 a 100
int tentativas = 0;

Console.WriteLine("Tente adivinhar o número secreto entre 1 e 100.");

while (true)
{
    Console.Write("Seu palpite: ");

    if (!int.TryParse(Console.ReadLine(), out int palpite))
    {
        Console.WriteLine("Digite um número inteiro válido.");
        continue;
    }

    if (palpite < 1 || palpite > 100)
    {
        Console.WriteLine("O palpite deve estar entre 1 e 100.");
        continue;
    }

    tentativas++;

    if (palpite == numeroSecreto)
    {
        Console.WriteLine($"Parabéns! Você acertou em {tentativas} tentativa(s).");
        break;
    }
    else if (palpite < numeroSecreto)
    {
        Console.WriteLine("O número secreto é maior.");
    }
    else
    {
        Console.WriteLine("O número secreto é menor.");
    }
}
O que a questão pede
Sortear um número, receber palpites sucessivos até o acerto e informar se cada tentativa ficou acima ou abaixo do alvo.
Conceito cobrado
Laço com condição de parada, validação de entrada, comparação de valores e manutenção de estado com Random e tentativas.
Estrutura dos dados

numeroSecreto, palpite, tentativas

Como pensar
Separe em etapas: ler entrada, validar faixa/formato, aplicar regra, decidir caso e exibir resultado final.
Como validar
Porque existe laço com estado: o programa valida o palpite, compara com o número secreto, incrementa tentativas e só encerra quando a condição de acerto é satisfeita.
Tabela de Evidência
Situação Saída esperada
Palpite menor que o número secreto Mensagem indicando que o número é maior.
Palpite maior que o número secreto Mensagem indicando que o número é menor.
Acerto após N tentativas Mensagem final informando o total de tentativas.
Variáveis-chave
  • numeroSecreto: estado oculto sorteado uma única vez.
  • palpite: entrada nova a cada iteração.
  • tentativas: contador cumulativo do jogo.
Erro comum: Pular validação de entrada e assumir que todo valor digitado já chega no formato correto.
Caso de borda: Palpite 1 ou 100.
Consolidação: Depois de acertar, pergunte se o usuário quer jogar novamente.