Variáveis e tipos básicos
por Sutton AshfordEntenda 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.
- 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,boolestd::stringcobrem a maioria dos casos;std::stringexige#include <string>.- Divisão entre dois
intdescarta a parte decimal; usestatic_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 guardar7.9numint. constimpede que o valor mude depois de criado, econstexprexige 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
// 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 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
// 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.
- Declarar uma variável de cada tipo:
std::string,int,double,charebool. - Imprimir os valores a partir das variáveis, sem digitar os números ou o nome dentro do texto.
- Mostrar o
boolcomotrue, usandostd::boolalpha. - Reproduzir exatamente a saída esperada, uma informação por linha.
#include <iostream>
#include <string>
int main() {
// Declare aqui as cinco variáveis do personagem
// Mostre cada uma numa linha
return 0;
}
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
#include <string>traz o tipostd::string; sem ele, o nome do personagem não teria onde ser guardado de forma confiável.std::string nome = "Arqueira";guarda texto, sempre entre aspas duplas.int nivel = 7;guarda um inteiro edouble vida = 82.5;guarda um número com casas decimais.char classe = 'A';guarda um único caractere, que em C++ fica entre aspas simples.bool ativo = true;guarda um valor lógico: verdadeiro ou falso.- Cada
std::coutjunta o rótulo e o valor da variável com<<, terminando com'\n'. std::boolalphafaz oboolsair comotrueem vez de1.
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;imprime1. Coloquestd::boolalphaantes do valor. - Vírgula no decimal:
double vida = 82,5;não compila, porque na declaração a vírgula separa variáveis e5não é um nome válido. O separador decimal em C++ é o ponto:82.5. - Faltar
std::nostring:string nomedá "'string' was not declared in this scope". Escrevastd::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.
- 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 comstd::fixedestd::setprecision(2). - Reproduzir exatamente a saída esperada.
#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;
}
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
- As três notas ficam em variáveis
int, porque são números inteiros. int soma = nota1 + nota2 + nota3;guarda 25; somar inteiros dá um inteiro.soma / 3divide doisint, então o resultado é 8: a parte decimal (0.333...) é jogada fora.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.std::fixedcomstd::setprecision(2)mostra odoublecom exatamente duas casas, arredondando 8.333... para 8.33.- Os manipuladores vêm depois das linhas inteiras só por organização: eles não alteram a forma como os
intsã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 asoma, 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 serdouble. - Esquecer o
<iomanip>: sem ele,std::setprecisionnão é declarado e a compilação falha. - Esquecer o
std::fixed: só comstd::setprecision(2), o número passa a ter duas casas significativas e sai como8.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.
- Declarar o percentual do cupom como
constexpr inte o limite do frete comoconstexpr double. - Calcular o desconto convertendo o percentual com
static_cast<double>, para que10 / 100não vire zero. - Guardar o resultado da comparação do frete numa variável
boole mostrá-la comstd::boolalpha. - Mostrar os valores em reais com
std::fixedestd::setprecision(2), reproduzindo exatamente a saída esperada.
#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;
}
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
constexpr int descontoPercentual = 10;econstexpr 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.- Quantidades são
int(não existe meia camiseta) e preços sãodouble, porque têm centavos. qtdCamiseta + qtdBonesoma doisinte dá 3 itens.- Em
qtdCamiseta * precoCamiseta, ointé promovido paradouble, e o subtotal fica 79.80 + 25.50 = 105.30. static_cast<double>(descontoPercentual) / 100dá 0.1; multiplicado pelo subtotal, gera o desconto de 10.53, e o total fica 94.77.total >= limiteFreteGratisé uma comparação: seu resultado é umbool, guardado emfreteGratis(aqui,false).std::fixedcomstd::setprecision(2)formata os valores em reais com duas casas; ointdo percentual continua saindo como10.- 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)calcula10 / 100, que dá0; o desconto sai0.00e o total fica 105.30. Converta comstatic_cast<double>ou divida por100.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 comoFrete grátis: 0. Coloque o manipulador antes dobool. - Preços em
int:int precoCamiseta = 39.90;guarda 39, e todos os totais ficam errados. Valores com centavos precisam dedouble(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