Sua dose diária de programação

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

✦   Lição

Variáveis e tipos básicos

Uma variável é um nome para um espaço da memória que guarda um valor. Em C++ toda variável tem um tipo, escolhido na declaração e fixo dali em diante: int faltas = 3; cria uma variável inteira chamada faltas com o valor 3. O tipo diz ao compilador quanto espaço reservar e quais operações fazem sentido.

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

Variáveis e tipos básicos

por Sutton Ashford
Iniciante

Entenda o conceito

Uma variável é um nome para um espaço da memória que guarda um valor. Em C++ toda variável tem um tipo, escolhido na declaração e fixo dali em diante: int faltas = 3; cria uma variável inteira chamada faltas com o valor 3. O tipo diz ao compilador quanto espaço reservar e quais operações fazem sentido.

Os tipos básicos do dia a dia são int (inteiros), double (números com casas decimais), char (um único caractere, entre aspas simples), bool (true ou false) e std::string (texto, do cabeçalho <string>). Por padrão, o std::cout mostra um bool como 1 ou 0; com std::boolalpha, ele sai como true ou false.

O tipo muda o resultado das contas: entre dois int, a divisão descarta a parte decimal (7 / 2 dá 3). Para obter 3.5, converta um dos lados com static_cast<double>(...). A inicialização com chaves, como int estoque{12};, é mais segura, porque o compilador recusa conversões que perdem dados.

Quando um valor não deve mudar, declare-o com const; se ele já é conhecido na compilação, use constexpr. E auto deixa o compilador deduzir o tipo pelo valor inicial, o que poupa digitação sem tirar a verificação de tipos.

↳ Pontos-chave
  • Toda variável é declarada com tipo e nome (double media = 8.75;) e sempre deve receber um valor inicial antes de ser lida.
  • int, double, char, bool e std::string cobrem a maioria dos casos; std::string exige #include <string>.
  • Divisão entre dois int descarta a parte decimal; use static_cast<double>(x) antes de dividir quando precisar das casas decimais.
  • Inicializar com chaves (int qtd{5};) faz o compilador recusar conversões com perda, como guardar 7.9 num int.
  • const impede que o valor mude depois de criado, e constexpr exige que ele seja conhecido já na compilação.

Do conceito à prática

3 exemplos para ver a ideia funcionando.

01Ficha de aluno com os tipos básicos

boletim.cpp
// Ficha de um aluno: uma variável para cada tipo básico
#include <iostream>
#include <string>  // std::string não vem de <iostream>

int main() {
    // Forma geral: tipo nome = valor;
    std::string aluno = "Marina";  // texto
    int faltas = 3;                // número inteiro
    double media = 8.75;           // número com casas decimais
    char turma = 'B';              // um caractere, entre aspas simples
    bool aprovado = true;          // verdadeiro ou falso

    std::cout << "Aluno: " << aluno << '\n';
    std::cout << "Turma: " << turma << '\n';
    std::cout << "Faltas: " << faltas << '\n';
    std::cout << "Média: " << media << '\n';

    // Por padrão, bool sai como 1 (true) ou 0 (false)
    std::cout << "Aprovado: " << aprovado << '\n';

    // std::boolalpha faz o bool sair como true ou false
    std::cout << std::boolalpha << "Aprovado: " << aprovado << '\n';

    // A variável pode receber outro valor, desde que do mesmo tipo
    faltas = faltas + 1;
    std::cout << "Faltas após a aula de hoje: " << faltas << '\n';

    return 0;
}

Cada informação do aluno vai para uma variável do tipo que combina com ela: o nome é texto (std::string), as faltas são inteiras (int), a média tem casas decimais (double), a turma é uma letra (char) e a aprovação é sim ou não (bool). Repare que std::string precisa de #include <string>.

As duas linhas de "Aprovado" mostram a diferença do std::boolalpha: a primeira imprime 1, a segunda true. No fim, faltas = faltas + 1; mostra que uma variável pode mudar de valor, mas nunca de tipo.

02Estoque de canecas: divisão inteira e conversões

estoque.cpp
// Estoque de canecas: divisão inteira, resto e conversão de tipos
#include <iostream>

int main() {
    int canecas = 17;   // unidades no estoque
    int porCaixa = 5;   // quantas cabem em cada caixa

    // Entre dois int, / descarta a parte decimal e % dá o resto
    std::cout << "Caixas cheias: " << canecas / porCaixa << '\n';   // 3
    std::cout << "Canecas soltas: " << canecas % porCaixa << '\n';  // 2

    // Para ter casas decimais, converta um dos lados para double
    double caixasExatas = static_cast<double>(canecas) / porCaixa;
    std::cout << "Caixas exatas: " << caixasExatas << '\n';         // 3.4

    // Converter double para int corta a parte decimal, sem arredondar
    double pesoKg = 7.9;
    int pesoInteiro = static_cast<int>(pesoKg);
    std::cout << "Peso truncado: " << pesoInteiro << " kg\n";       // 7

    // Com chaves, o compilador recusa conversões com perda:
    // int erro{7.9};  // erro de compilação (narrowing)

    int reposicao{12};                 // chaves também inicializam
    auto total = canecas + reposicao;  // auto deduz int pelo valor
    std::cout << "Após reposição: " << total << '\n';               // 29

    return 0;
}

O exemplo mostra como o tipo muda o resultado da conta. 17 / 5 entre inteiros dá 3, e o operador % devolve o resto, 2. Quando a parte decimal importa, static_cast<double>(canecas) converte o estoque antes da divisão, e o resultado passa a ser 3.4.

O caminho inverso também existe: static_cast<int>(7.9) dá 7, porque a conversão para inteiro simplesmente corta as casas decimais. A linha comentada mostra a proteção da inicialização com chaves: int erro{7.9}; nem compila. Por fim, auto deduz que total é int, já que a soma de dois int é int.

03Receita escalonada com const e constexpr

porcoes.cpp
// Receita de panquecas: const, constexpr e saída com casas decimais
#include <iomanip>   // std::fixed e std::setprecision
#include <iostream>
#include <string>

int main() {
    // constexpr: valor conhecido na compilação e que nunca muda
    constexpr int porcoesOriginais = 4;
    constexpr double farinhaG = 250.0;
    constexpr double leiteMl = 300.0;
    constexpr int ovos = 2;

    // const: o valor é definido uma vez e não pode ser alterado
    const int porcoesDesejadas = 6;
    const std::string receita = "Panquecas";

    // Converte antes de dividir: 6 / 4 entre int daria 1
    const double fator = static_cast<double>(porcoesDesejadas) / porcoesOriginais;

    std::cout << receita << " para " << porcoesDesejadas << " porções\n";
    std::cout << std::fixed << std::setprecision(1);  // uma casa decimal
    std::cout << "Fator: " << fator << '\n';
    std::cout << "Farinha: " << farinhaG * fator << " g\n";
    std::cout << "Leite: " << leiteMl * fator << " ml\n";

    // int * double vira double; static_cast volta para int (corta decimais)
    const int ovosAjustados = static_cast<int>(ovos * fator);
    std::cout << "Ovos: " << ovosAjustados << '\n';

    // porcoesDesejadas = 8;  // erro de compilação: a variável é const

    return 0;
}

Os valores fixos da receita original são constexpr: o compilador os conhece antes de o programa rodar e impede qualquer alteração. As porções desejadas são const, que também protege o valor, mas aceitaria um número que só se conhece em tempo de execução, como uma resposta do usuário.

O fator 1.5 só aparece porque porcoesDesejadas é convertido para double antes da divisão; sem isso, 6 / 4 daria 1 e a receita não mudaria. Na conta dos ovos, 2 * 1.5 dá 3.0 e o static_cast<int> guarda 3. Com std::fixed e std::setprecision(1), os valores decimais saem sempre com uma casa, enquanto os int continuam sem casas.


Agora é com você

Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.

01Ficha de personagemFácil

Guarde em variáveis as informações de um personagem de jogo (nome Arqueira, nível 7, vida 82.5, classe 'A' e ativo verdadeiro) e mostre cada uma numa linha.

↳ Requisitos
  • Declarar uma variável de cada tipo: std::string, int, double, char e bool.
  • Imprimir os valores a partir das variáveis, sem digitar os números ou o nome dentro do texto.
  • Mostrar o bool como true, usando std::boolalpha.
  • Reproduzir exatamente a saída esperada, uma informação por linha.
código inicial
#include <iostream>
#include <string>

int main() {
    // Declare aqui as cinco variáveis do personagem

    // Mostre cada uma numa linha

    return 0;
}
saída esperada
Nome: Arqueira
Nível: 7
Vida: 82.5
Classe: A
Ativo: true
Ver dica

Pense em qual tipo combina com cada informação; a classe é uma letra só, então as aspas são diferentes das do nome.

Ver resposta
#include <iostream>
#include <string>  // necessário para std::string

int main() {
    // Uma variável para cada informação, com o tipo adequado
    std::string nome = "Arqueira";
    int nivel = 7;
    double vida = 82.5;
    char classe = 'A';
    bool ativo = true;

    std::cout << "Nome: " << nome << '\n';
    std::cout << "Nível: " << nivel << '\n';
    std::cout << "Vida: " << vida << '\n';
    std::cout << "Classe: " << classe << '\n';
    // boolalpha troca o 1 por true
    std::cout << std::boolalpha << "Ativo: " << ativo << '\n';

    return 0;
}

Passo a passo

  1. #include <string> traz o tipo std::string; sem ele, o nome do personagem não teria onde ser guardado de forma confiável.
  2. std::string nome = "Arqueira"; guarda texto, sempre entre aspas duplas.
  3. int nivel = 7; guarda um inteiro e double vida = 82.5; guarda um número com casas decimais.
  4. char classe = 'A'; guarda um único caractere, que em C++ fica entre aspas simples.
  5. bool ativo = true; guarda um valor lógico: verdadeiro ou falso.
  6. Cada std::cout junta o rótulo e o valor da variável com <<, terminando com '\n'.
  7. std::boolalpha faz o bool sair como true em vez de 1.

Por que funciona

Cada dado tem um tipo que descreve o que ele é, e o std::cout sabe imprimir todos os tipos básicos: o double 82.5 sai como 82.5, o char sai como a letra e o std::string sai como o texto. Como os valores estão em variáveis, mudar o personagem é trocar uma linha só, e o texto de saída continua igual.

Erros comuns

  • Aspas duplas no char: char classe = "A"; não compila, porque "A" é um texto, não um caractere. Use 'A'.
  • Esquecer o std::boolalpha: std::cout << ativo; imprime 1. Coloque std::boolalpha antes do valor.
  • Vírgula no decimal: double vida = 82,5; não compila, porque na declaração a vírgula separa variáveis e 5 não é um nome válido. O separador decimal em C++ é o ponto: 82.5.
  • Faltar std:: no string: string nome dá "'string' was not declared in this scope". Escreva std::string.

Outra forma de resolver

Também dá para usar auto nas declarações: auto nivel = 7; vira int e auto vida = 82.5; vira double. Para o nome, porém, auto nome = "Arqueira"; gera um ponteiro para caracteres, não um std::string; por isso, em lições iniciais, escrever o tipo explicitamente é mais claro.

Saída esperada

Nome: Arqueira
Nível: 7
Vida: 82.5
Classe: A
Ativo: true

02Média do boletimMédio

Guarde três notas inteiras (7, 8 e 10) em variáveis, calcule a soma e mostre a média de duas formas: com divisão inteira e com duas casas decimais.

↳ Requisitos
  • Guardar as notas e a soma em variáveis do tipo int.
  • Calcular a média inteira com soma / 3, sem conversão.
  • Calcular a média real com static_cast<double> antes da divisão e mostrá-la com std::fixed e std::setprecision(2).
  • Reproduzir exatamente a saída esperada.
código inicial
#include <iomanip>
#include <iostream>

int main() {
    int nota1 = 7;
    int nota2 = 8;
    int nota3 = 10;
    // Calcule a soma e as duas médias

    return 0;
}
saída esperada
Soma das notas: 25
Média inteira: 8
Média real: 8.33
Ver dica

O tipo dos operandos decide o tipo da divisão: basta que um deles seja double para as casas decimais aparecerem.

Ver resposta
#include <iomanip>   // std::fixed e std::setprecision
#include <iostream>

int main() {
    int nota1 = 7;
    int nota2 = 8;
    int nota3 = 10;
    int soma = nota1 + nota2 + nota3;  // 25

    // int / int: a parte decimal é descartada
    int mediaInteira = soma / 3;

    // Converte a soma antes de dividir: double / int vira double
    double mediaReal = static_cast<double>(soma) / 3;

    std::cout << "Soma das notas: " << soma << '\n';
    std::cout << "Média inteira: " << mediaInteira << '\n';
    std::cout << std::fixed << std::setprecision(2);  // duas casas
    std::cout << "Média real: " << mediaReal << '\n';

    return 0;
}

Passo a passo

  1. As três notas ficam em variáveis int, porque são números inteiros.
  2. int soma = nota1 + nota2 + nota3; guarda 25; somar inteiros dá um inteiro.
  3. soma / 3 divide dois int, então o resultado é 8: a parte decimal (0.333...) é jogada fora.
  4. static_cast<double>(soma) transforma 25 em 25.0 antes da divisão; como um dos lados é double, a conta passa a ser feita com casas decimais.
  5. std::fixed com std::setprecision(2) mostra o double com exatamente duas casas, arredondando 8.333... para 8.33.
  6. Os manipuladores vêm depois das linhas inteiras só por organização: eles não alteram a forma como os int são impressos.

Por que funciona

Em C++, o tipo do resultado de uma operação depende do tipo dos operandos. Com dois int, a divisão é inteira; com um double envolvido, o outro lado é promovido para double e a divisão é real. O static_cast é a forma explícita e segura de pedir essa conversão, deixando claro para quem lê que a mudança de tipo é intencional.

Erros comuns

  • Converter depois de dividir: static_cast<double>(soma / 3) dá 8.00, porque a divisão inteira já aconteceu dentro dos parênteses. Converta a soma, não o resultado.
  • Guardar em int: int mediaReal = static_cast<double>(soma) / 3; calcula 8.333... e corta para 8 na atribuição. A variável precisa ser double.
  • Esquecer o <iomanip>: sem ele, std::setprecision não é declarado e a compilação falha.
  • Esquecer o std::fixed: só com std::setprecision(2), o número passa a ter duas casas significativas e sai como 8.3.

Outra forma de resolver

Dividir por 3.0 em vez de 3 também funciona: soma / 3.0 já é uma divisão real, porque 3.0 é um literal double. É uma forma curta quando o divisor é um número fixo; quando os dois lados são variáveis int, o static_cast é o caminho.

Saída esperada

Soma das notas: 25
Média inteira: 8
Média real: 8.33

03Resumo do carrinho com cupomDesafio

Monte o resumo de um carrinho com 2 camisetas de R$ 39.90 e 1 boné de R$ 25.50, aplicando um cupom de 10% e informando se a compra atingiu o frete grátis (a partir de R$ 100.00) e quanto falta para ele.

↳ Requisitos
  • Declarar o percentual do cupom como constexpr int e o limite do frete como constexpr double.
  • Calcular o desconto convertendo o percentual com static_cast<double>, para que 10 / 100 não vire zero.
  • Guardar o resultado da comparação do frete numa variável bool e mostrá-la com std::boolalpha.
  • Mostrar os valores em reais com std::fixed e std::setprecision(2), reproduzindo exatamente a saída esperada.
código inicial
#include <iomanip>
#include <iostream>

int main() {
    // Constantes da loja: percentual do cupom e limite do frete

    // Quantidades e preços dos itens

    // Itens, subtotal, desconto, total e frete

    // Resumo

    return 0;
}
saída esperada
Itens no carrinho: 3
Subtotal: R$ 105.30
Desconto (10%): R$ 10.53
Total: R$ 94.77
Frete grátis: false
Faltam para o frete grátis: R$ 5.23
Ver dica

Antes de multiplicar o subtotal pelo cupom, pergunte-se qual é o tipo de descontoPercentual / 100 e quanto essa conta vale.

Ver resposta
#include <iomanip>   // std::fixed e std::setprecision
#include <iostream>

int main() {
    // Constantes da loja: conhecidas na compilação, nunca mudam
    constexpr int descontoPercentual = 10;
    constexpr double limiteFreteGratis = 100.0;

    // Itens do carrinho
    int qtdCamiseta = 2;
    double precoCamiseta = 39.90;
    int qtdBone = 1;
    double precoBone = 25.50;

    int itens = qtdCamiseta + qtdBone;
    // int * double vira double
    double subtotal = qtdCamiseta * precoCamiseta + qtdBone * precoBone;

    // static_cast evita a divisão inteira 10 / 100, que daria 0
    double desconto = subtotal * (static_cast<double>(descontoPercentual) / 100);
    double total = subtotal - desconto;

    // A comparação produz um bool: true ou false
    bool freteGratis = total >= limiteFreteGratis;

    std::cout << "Itens no carrinho: " << itens << '\n';
    std::cout << std::fixed << std::setprecision(2);
    std::cout << "Subtotal: R$ " << subtotal << '\n';
    std::cout << "Desconto (" << descontoPercentual << "%): R$ " << desconto << '\n';
    std::cout << "Total: R$ " << total << '\n';
    std::cout << std::boolalpha << "Frete grátis: " << freteGratis << '\n';
    std::cout << "Faltam para o frete grátis: R$ " << limiteFreteGratis - total << '\n';

    return 0;
}

Passo a passo

  1. constexpr int descontoPercentual = 10; e constexpr double limiteFreteGratis = 100.0; são regras da loja: ficam fixas no código e o compilador impede que alguém as altere por engano.
  2. Quantidades são int (não existe meia camiseta) e preços são double, porque têm centavos.
  3. qtdCamiseta + qtdBone soma dois int e dá 3 itens.
  4. Em qtdCamiseta * precoCamiseta, o int é promovido para double, e o subtotal fica 79.80 + 25.50 = 105.30.
  5. static_cast<double>(descontoPercentual) / 100 dá 0.1; multiplicado pelo subtotal, gera o desconto de 10.53, e o total fica 94.77.
  6. total >= limiteFreteGratis é uma comparação: seu resultado é um bool, guardado em freteGratis (aqui, false).
  7. std::fixed com std::setprecision(2) formata os valores em reais com duas casas; o int do percentual continua saindo como 10.
  8. A última linha calcula a diferença direto na saída: 100.00 - 94.77 = 5.23.

Por que funciona

O programa mistura tipos de propósito e deixa claro onde cada conversão acontece. A promoção de int para double nas multiplicações é automática e segura; a divisão do percentual, que seria inteira, é convertida à mão com static_cast. Com constexpr nas regras da loja e bool para o resultado da comparação, cada valor tem o tipo que descreve o que ele significa.

Os preços em double não são exatos na memória (39.90 vira algo como 39.899999...), mas a diferença é minúscula e o std::setprecision(2) arredonda para os centavos corretos. Em sistemas financeiros de verdade, é comum guardar os valores em centavos, como int, para evitar esse detalhe.

Erros comuns

  • Divisão inteira no percentual: subtotal * (descontoPercentual / 100) calcula 10 / 100, que dá 0; o desconto sai 0.00 e o total fica 105.30. Converta com static_cast<double> ou divida por 100.0.
  • Tentar alterar uma constante: descontoPercentual = 15; gera erro de compilação ("assignment of read-only variable"). Para mudar o cupom, troque o valor na declaração.
  • Esquecer o std::boolalpha: a linha do frete sai como Frete grátis: 0. Coloque o manipulador antes do bool.
  • Preços em int: int precoCamiseta = 39.90; guarda 39, e todos os totais ficam errados. Valores com centavos precisam de double (ou de centavos inteiros).

Outra forma de resolver

Trabalhar em centavos evita qualquer imprecisão: int precoCamiseta = 3990;, int subtotal = 2 * 3990 + 2550; (10530) e int desconto = subtotal * descontoPercentual / 100; (1053). Para exibir, divide-se por 100 e usa-se o resto para os centavos. Essa forma é a preferida em sistemas de pagamento; para um resumo simples, double com std::setprecision(2) é mais direto.

Saída esperada

Itens no carrinho: 3
Subtotal: R$ 105.30
Desconto (10%): R$ 10.53
Total: R$ 94.77
Frete grátis: false
Faltam para o frete grátis: R$ 5.23

Últimas lições

Ver o arquivo completo →