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

Como Criar uma Variável em C++: Um Guia Visual e Prático

Aprenda variáveis em C++ de forma visual: declarar e inicializar, os tipos principais e o tamanho de cada um, divisão de inteiros, estouro, precisão dos decimais, inicialização com chaves, auto, const, regras de nomes, mensagens reais do compilador e exercícios com respostas.

nbkhope
Nesta página

Um programa que não lembra de nada não serve para muita coisa. Um jogo precisa lembrar a sua pontuação, uma loja precisa lembrar o que está no seu carrinho, e uma calculadora precisa lembrar os números que você digitou. Em C++, você lembra das coisas com variáveis.

Neste guia você vai criar variáveis de todos os tipos básicos, ver quanta memória cada uma ocupa e topar com as surpresas clássicas: divisão de números inteiros, números que estouram, decimais que não são bem exatos e variáveis usadas antes de ganhar um valor. Pelo caminho você vai ler mensagens reais do compilador e vai terminar com exercícios.

Todas as saídas abaixo vêm de execuções reais com o GCC 14.1 (g++ -std=c++20) no Windows de 64 bits. As mensagens do compilador são em inglês; vamos traduzindo as importantes.

Uma variável é uma caixa com etiqueta

Uma variável é uma caixa com etiqueta na memória. A declaração int idade = 35; tem três partes: o tipo int, que diz que tipo de dado a caixa guarda e qual o tamanho dela, 4 bytes; o nome idade, a etiqueta que você usa no código; e o valor inicial 35, o que vai na caixa. Na memória, idade ocupa 4 bytes guardando 35. Ao lado, double altura = 1.75 ocupa 8 bytes, bool ehEstudante = true ocupa 1 byte e char nota = 'A' ocupa 1 byte. O tipo decide quantos bytes a caixa tem e o que os bits lá dentro querem dizer

Para criar uma variável você escreve o tipo, depois o nome e, normalmente, um valor inicial:

1#include <iostream>
2#include <string>
3
4int main() {
5    int idade = 35;
6    double altura = 1.75;
7    bool ehEstudante = true;
8    char nota = 'A';
9    std::string nome = "Roger";
10
11    std::cout << nome << " tem " << idade << " anos e " << altura << " m de altura.\n";
12    std::cout << "Nota: " << nota << "\n";
13    std::cout << "Estudante? " << ehEstudante << "\n";
14    return 0;
15}
Roger tem 35 anos e 1.75 m de altura.
Nota: A
Estudante? 1
  • int guarda números inteiros: 35, -7, 2024.
  • double guarda números com casas decimais: 1.75, -0.5, 3.14159. (O C++ usa ponto, não vírgula, nos números.)
  • bool guarda true (verdadeiro) ou false (falso). Ele imprime como 1 ou 0 (mais sobre isso abaixo).
  • char guarda um único caractere, escrito entre aspas simples: 'A'.
  • std::string guarda texto, escrito entre aspas duplas. Ela precisa de #include <string>.

O tipo importa porque o C++ é estaticamente tipado: uma vez int, a variável é int para sempre, e o compilador confere cada uso dela.

Declarar, atribuir e mudar

Você pode declarar uma variável primeiro e dar o valor depois, e mudá-lo quantas vezes quiser. O sinal = quer dizer "guarde este valor", não "é igual a" (para comparar igualdade, o operador é ==):

1#include <iostream>
2
3int main() {
4    int pontos;
5    pontos = 10;
6    std::cout << "Começo: " << pontos << "\n";
7
8    pontos = pontos + 5;
9    std::cout << "Depois de um bônus: " << pontos << "\n";
10
11    pontos += 20;
12    pontos -= 3;
13    pontos *= 2;
14    std::cout << "Depois de mais mudanças: " << pontos << "\n";
15
16    pontos++;
17    std::cout << "Mais um: " << pontos << "\n";
18    return 0;
19}
1Começo: 10
2Depois de um bônus: 15
3Depois de mais mudanças: 64
4Mais um: 65

pontos = pontos + 5 lê o valor atual, soma 5 e guarda o resultado de volta. As atribuições compostas +=, -=, *= e /= são atalhos exatamente para isso, e o ++ soma um.

Sempre dê um valor à variável

Uma variável declarada mas que nunca recebeu valor guarda os bits que por acaso estavam naquela memória: lixo. Lê-la é um erro, e o compilador avisa se os avisos estiverem ligados:

1#include <iostream>
2
3int main() {
4    int total;
5    total = total + 10;
6    std::cout << total << "\n";
7    return 0;
8}
1$ g++ -std=c++20 -Wall -Wextra seminicio.cpp -o seminicio
2seminicio.cpp: In function 'int main()':
3seminicio.cpp:5:11: warning: 'total' is used uninitialized [-Wuninitialized]
4    5 |     total = total + 10;
5      |     ~~~~~~^~~~~~~~~~~~
6seminicio.cpp:4:9: note: 'total' was declared here
7    4 |     int total;
8      |         ^~~~~

("A variável total é usada sem ter sido inicializada.") O programa compila mesmo assim, mas o que ele imprime é imprevisível. O conserto é um hábito: inicialize toda variável ao declará-la, como em int total = 0;.

Qual é o tamanho de cada tipo?

Cada tipo usa um número fixo de bytes, e isso limita o que ele consegue guardar. O operador sizeof diz o tamanho de um tipo, e o std::numeric_limits, o alcance:

1#include <iostream>
2#include <limits>
3#include <string>
4
5int main() {
6    std::cout << "bool:        " << sizeof(bool) << " byte\n";
7    std::cout << "char:        " << sizeof(char) << " byte\n";
8    std::cout << "short:       " << sizeof(short) << " bytes, até " << std::numeric_limits<short>::max() << "\n";
9    std::cout << "int:         " << sizeof(int) << " bytes, até " << std::numeric_limits<int>::max() << "\n";
10    std::cout << "long:        " << sizeof(long) << " bytes, até " << std::numeric_limits<long>::max() << "\n";
11    std::cout << "long long:   " << sizeof(long long) << " bytes, até " << std::numeric_limits<long long>::max() << "\n";
12    std::cout << "float:       " << sizeof(float) << " bytes, cerca de " << std::numeric_limits<float>::digits10 << " dígitos exatos\n";
13    std::cout << "double:      " << sizeof(double) << " bytes, cerca de " << std::numeric_limits<double>::digits10 << " dígitos exatos\n";
14    std::cout << "std::string: " << sizeof(std::string) << " bytes (mais o texto, se for longo)\n";
15    return 0;
16}
1bool:        1 byte
2char:        1 byte
3short:       2 bytes, até 32767
4int:         4 bytes, até 2147483647
5long:        4 bytes, até 2147483647
6long long:   8 bytes, até 9223372036854775807
7float:       4 bytes, cerca de 6 dígitos exatos
8double:      8 bytes, cerca de 15 dígitos exatos
9std::string: 32 bytes (mais o texto, se for longo)
Qual é o tamanho de cada tipo do C++? Tamanhos em bytes medidos com o GCC 14.1 no Windows de 64 bits. bool: 1 byte. char: 1 byte. short: 2 bytes, até 32.767. int: 4 bytes, até cerca de 2,1 bilhões. long: 4 bytes no Windows, mas 8 bytes no Linux e no macOS de 64 bits. long long: 8 bytes, até cerca de 9,2 quintilhões. float: 4 bytes, cerca de 6 dígitos exatos. double: 8 bytes, cerca de 15 dígitos exatos. std::string: 32 bytes para o objeto em si; textos longos ficam em outro lugar. Cada byte a mais multiplica o alcance por 256

Duas coisas se destacam:

  • Um int vai até 2.147.483.647, pouco mais de 2 bilhões. Serve para idades e pontuações, não para a população do mundo (cerca de 8 bilhões).
  • O long tem 4 bytes no Windows, mas 8 bytes no Linux e no macOS de 64 bits. O padrão do C++ só define tamanhos mínimos, então eles podem mudar de um sistema para outro. Quando você precisa de um tamanho exato, use long long (pelo menos 8 bytes) ou os tipos de largura fixa como o std::int64_t, do <cstdint>.

Surpresas com números

Divisão de inteiros

Quando os dois lados do / são inteiros, o C++ faz divisão inteira e joga fora o resto. O % dá o resto:

1#include <iostream>
2
3int main() {
4    int pizzas = 7;
5    int pessoas = 2;
6    std::cout << "Cada um ganha " << pizzas / pessoas << " pizzas inteiras\n";
7    std::cout << "Sobra: " << pizzas % pessoas << "\n";
8    std::cout << "Divisão exata: " << static_cast<double>(pizzas) / pessoas << "\n";
9    return 0;
10}
Cada um ganha 3 pizzas inteiras
Sobra: 1
Divisão exata: 3.5

static_cast<double>(pizzas) converte o valor para double naquela conta, e assim a divisão mantém as casas decimais.

Números que não cabem

Tente guardar 3 bilhões num int:

1#include <iostream>
2
3int main() {
4    int grandeDemais = 3000000000;
5    long long grandeOBastante = 3000000000;
6    std::cout << grandeDemais << "\n";
7    std::cout << grandeOBastante << "\n";
8    return 0;
9}
-1294967296
3000000000
O que acontece quando um número não cabe. Um int tem 32 bits e guarda valores de cerca de -2,1 bilhões a +2,1 bilhões. 3.000.000.000 precisa de mais que isso, então, quando ele é espremido num int, só os 32 bits de baixo são guardados, e o bit de cima é lido como o sinal: o valor dá a volta e vira -1.294.967.296. Isso é 3.000.000.000 menos 2 elevado a 32. Um long long tem 64 bits e guarda o número com folga. O GCC compilou isso sem erro e sem aviso, mesmo com -Wall -Wextra

Nenhum erro, e nem um aviso com -Wall -Wextra: o valor simplesmente dá a volta e vira um número negativo. Escolha um tipo grande o bastante para os seus dados. (Estourar um int durante uma conta, como somar 1 ao máximo, é ainda pior: é comportamento indefinido, ou seja, o programa pode fazer qualquer coisa.)

Decimais não são exatos

O double guarda os números em binário, e a maioria das frações decimais, como 0,1, não pode ser escrita de forma exata em binário, assim como 1/3 não pode ser escrito de forma exata em decimal:

1#include <iomanip>
2#include <iostream>
3
4int main() {
5    double soma = 0.1 + 0.2;
6    std::cout << soma << "\n";
7    std::cout << std::setprecision(17) << soma << "\n";
8    std::cout << (soma == 0.3) << "\n";
9
10    float terco = 1.0f / 3;
11    double tercoMelhor = 1.0 / 3;
12    std::cout << std::setprecision(10) << terco << " vs " << tercoMelhor << "\n";
13    return 0;
14}
10.3
20.30000000000000004
30
40.3333333433 vs 0.3333333333
float vs. double: quão exatos são os decimais? Um terço impresso com 10 dígitos, medido com o GCC 14.1: o float, de 4 bytes, dá 0.3333333433, errado depois de uns 7 dígitos; o double, de 8 bytes, dá 0.3333333333, certo até uns 16 dígitos. E 0.1 + 0.2 num double é na verdade 0.30000000000000004, então compará-lo com 0.3 usando == dá false. Prefira double a float, e compare decimais com uma pequena tolerância em vez de ==

O std::cout arredonda para 6 dígitos significativos por padrão, o que esconde o erro; o std::setprecision(17) mostra. Duas lições: use double em vez de float, a não ser que tenha um motivo, e não compare decimais com ==; confira se eles estão próximos. (Para dinheiro, os programas costumam contar centavos inteiros num inteiro.)

bool e char são números disfarçados

1#include <iostream>
2
3int main() {
4    bool estaAberto = true;
5    std::cout << estaAberto << "\n";
6    std::cout << std::boolalpha << estaAberto << "\n";
7
8    char letra = 'A';
9    std::cout << letra << " tem o código " << static_cast<int>(letra) << "\n";
10    char proxima = letra + 1;
11    std::cout << "A próxima letra é " << proxima << "\n";
12    return 0;
13}
11
2true
3A tem o código 65
4A próxima letra é B

Um bool imprime como 1 ou 0, a não ser que você mande o std::boolalpha para o fluxo antes. Um char é na verdade um número pequeno (65 é o código do A na tabela ASCII), então dá para fazer contas com ele.

Jeitos de inicializar

O C++ tem vários estilos de inicialização. Os dois que você mais vai ver:

1#include <iostream>
2
3int main() {
4    int comIgual = 3.7;
5    int comChaves{42};
6    double proporcao{0.5};
7    std::cout << comIgual << " " << comChaves << " " << proporcao << "\n";
8    return 0;
9}
3 42 0.5

A versão com = cortou o 3.7 para 3 em silêncio. A inicialização com chaves { } se recusa a perder informação assim, então o engano vira um erro de compilação em vez de um bug silencioso:

1int main() {
2    int pontos{3.7};
3    return pontos;
4}
1estreitamento.cpp: In function 'int main()':
2estreitamento.cpp:2:16: error: narrowing conversion of '3.7000000000000002e+0' from 'double' to 'int' [-Wnarrowing]
3    2 |     int pontos{3.7};
4      |                ^~~

É um erro de conversão de estreitamento (narrowing conversion). (Repare no compilador imprimindo 3.7 como 3.7000000000000002: o problema dos decimais de novo!) Muitos guias de estilo modernos recomendam as chaves justamente por isso.

Deixando o compilador escolher: auto

Com o auto, o compilador descobre o tipo a partir do valor inicial:

1#include <iostream>
2#include <string>
3
4int main() {
5    auto quantidade = 10;
6    auto preco = 4.99;
7    auto pronto = false;
8    auto titulo = std::string("Variáveis em C++");
9    std::cout << quantidade << " itens a " << preco << " cada\n";
10    std::cout << titulo << ", pronto: " << std::boolalpha << pronto << "\n";
11    return 0;
12}
10 itens a 4.99 cada
Variáveis em C++, pronto: false

quantidade é um int, preco um double, pronto um bool e titulo uma std::string. A variável continua com tipo fixo; você só não escreve o tipo. Repare que auto titulo = "Variáveis em C++";, sem o std::string(…), criaria um array de caracteres no estilo do C em vez de uma std::string, um motivo para usar o auto com cuidado.

Valores que nunca mudam: const

Marque uma variável como const quando o valor dela não deve mudar depois de definido. O compilador então recusa qualquer tentativa de mudá-la:

1int main() {
2    const double pi = 3.14159;
3    pi = 3;
4    return 0;
5}
1constante.cpp: In function 'int main()':
2constante.cpp:3:8: error: assignment of read-only variable 'pi'
3    3 |     pi = 3;
4      |     ~~~^~~

("Atribuição a uma variável somente leitura.") Use const à vontade: ele documenta a sua intenção e transforma mudanças acidentais em erros de compilação. (Para valores conhecidos já na compilação, o constexpr vai um passo além e garante que o valor seja calculado enquanto o programa compila.)

Dando nome às variáveis

Regras e convenções para nomes de variáveis em C++. Válidos: pontos, nomeDoJogador, velocidade_max, _contagem, fase2. Inválidos: 2oLugar, que começa com dígito; nome jogador, que tem um espaço; custo-total, em que o sinal de menos quer dizer subtração; e class, que é uma palavra reservada. Os nomes diferenciam maiúsculas de minúsculas, então pontos, Pontos e PONTOS são três variáveis diferentes. Convenções populares: camelCase, como precoTotal, e snake_case, como preco_total; escolha um e use sempre. Prefira nomes descritivos: segundosPassados é melhor que s

As regras:

  • Use letras, dígitos e sublinhados, começando com uma letra ou um sublinhado.
  • Sem espaços, sem símbolos como - ou $ e sem palavras reservadas (int, class, return, new…).
  • Evite acentos (é, ç, ã) nos nomes: alguns compiladores aceitam, mas é fonte de problemas. Por isso escrevemos preco e ehEstudante.
  • Os nomes diferenciam maiúsculas de minúsculas: pontos, Pontos e PONTOS são três variáveis diferentes.

Quebre uma regra e o compilador para você:

1int main() {
2    int 2oLugar = 2;
3    return 0;
4}
1nomeruim.cpp: In function 'int main()':
2nomeruim.cpp:2:9: error: expected unqualified-id before numeric constant
3    2 |     int 2oLugar = 2;
4      |         ^~~~~~~

Além das regras, escolha nomes descritivos. segundosPassados diz exatamente o que guarda para quem ler depois (muitas vezes você mesmo, um mês depois); s não diz nada. Os dois estilos mais comuns são o camelCase e o snake_case; escolha um e mantenha.

Sua vez: pratique

Tente fazer estes antes de espiar as respostas. Compile cada um com g++ -std=c++20 -Wall -Wextra.

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

1#include <iostream>
2
3int main() {
4    int macas = 10;
5    int amigos = 4;
6    macas -= 2;
7    std::cout << macas / amigos << " " << macas % amigos << "\n";
8    double media = macas / amigos;
9    std::cout << media << "\n";
10    return 0;
11}

Exercício 2: Troque dois valores. Dados int esquerda = 3; e int direita = 8;, troque os valores para que esquerda fique com 8 e direita com 3, e imprima os dois. (Dica: você vai precisar de uma terceira variável.)

Exercício 3: Calculadora do círculo. Leia um raio (um número inteiro) e imprima a área e o comprimento da circunferência, usando um const double pi = 3.14159;.

Exercício 4: Segundos em horas. Leia uma quantidade de segundos e imprima em horas, minutos e segundos. Por exemplo, 3725 segundos são 1 h 2 min 5 s.

Exercício 5: Conserte o programa (desafio). Ele deveria imprimir o preço de 3 ingressos a 12.50 cada e quantos lugares sobram de 150, mas tem três problemas. Encontre-os.

1#include <iostream>
2
3int main() {
4    const int lugares = 150;
5    int precoDoIngresso{12.50};
6    int ingressos = 3;
7    lugares = lugares - ingressos;
8    std::cout << "Total: " << ingressos * precoDoIngresso << "\n";
9    std::cout << "Lugares sobrando: " << lugares << "\n";
10    return 0;
11}

Quiz rápido

  1. Quais são as três partes de int idade = 35;?
  2. Qual é a diferença entre = e ==?
  3. Por que 7 / 2 dá 3 em C++?
  4. Por que int pontos{3.7}; é um erro de compilação, mas int pontos = 3.7; não é?
  5. O que o const faz?

Respostas

Exercício 1: Depois do macas -= 2, macas vale 8. 8 / 4 dá 2 com resto 0. A armadilha está na última linha: macas / amigos é calculado primeiro como divisão inteira (dando 2), e só depois guardado no double:

1#include <iostream>
2
3int main() {
4    int macas = 10;
5    int amigos = 4;
6    macas -= 2;
7    std::cout << macas / amigos << " " << macas % amigos << "\n";
8    double media = macas / amigos;
9    std::cout << media << "\n";
10    return 0;
11}
2 0
2

Exercício 2: Guarde um valor antes de sobrescrevê-lo:

1#include <iostream>
2
3int main() {
4    int esquerda = 3;
5    int direita = 8;
6    int guardado = esquerda;
7    esquerda = direita;
8    direita = guardado;
9    std::cout << "esquerda = " << esquerda << ", direita = " << direita << "\n";
10    return 0;
11}
esquerda = 8, direita = 3

(A biblioteca padrão também tem o std::swap(esquerda, direita), no <utility>.)

Exercício 3: O raio é um int, mas multiplicar pelo double pi torna os resultados double:

1#include <iostream>
2
3int main() {
4    const double pi = 3.14159;
5    int raio = 0;
6    std::cout << "Raio: ";
7    std::cin >> raio;
8    double area = pi * raio * raio;
9    double circunferencia = 2 * pi * raio;
10    std::cout << "Área: " << area << "\n";
11    std::cout << "Circunferência: " << circunferencia << "\n";
12    return 0;
13}
Raio: 10
Área: 314.159
Circunferência: 62.8318

Exercício 4: A divisão inteira e o operador de resto fazem todo o trabalho:

1#include <iostream>
2
3int main() {
4    int totalDeSegundos = 0;
5    std::cout << "Segundos: ";
6    std::cin >> totalDeSegundos;
7    int horas = totalDeSegundos / 3600;
8    int minutos = totalDeSegundos % 3600 / 60;
9    int segundos = totalDeSegundos % 60;
10    std::cout << horas << " h " << minutos << " min " << segundos << " s\n";
11    return 0;
12}
Segundos: 3725
1 h 2 min 5 s
Segundos: 86399
23 h 59 min 59 s

Exercício 5: (1) int precoDoIngresso{12.50} é um erro de estreitamento: um preço com centavos precisa de um double. (2) lugares é const, então não pode mudar: mantenha o total como constante e calcule os lugares que sobram numa variável nova. (3) Com isso consertado, funciona:

1#include <iostream>
2
3int main() {
4    const int lugares = 150;
5    double precoDoIngresso{12.50};
6    int ingressos = 3;
7    int lugaresSobrando = lugares - ingressos;
8    std::cout << "Total: " << ingressos * precoDoIngresso << "\n";
9    std::cout << "Lugares sobrando: " << lugaresSobrando << "\n";
10    return 0;
11}
Total: 37.5
Lugares sobrando: 147

Quiz: (1) O tipo (int), o nome (idade) e o valor inicial (35). (2) O = guarda um valor numa variável; o == pergunta se dois valores são iguais. (3) Os dois números são inteiros, então o C++ faz divisão inteira e descarta o resto; transforme um deles em double para manter as casas decimais. (4) A inicialização com chaves proíbe conversões de estreitamento que perdem informação; o = corta 3.7 para 3 em silêncio. (5) Ele deixa a variável somente leitura depois de inicializada; qualquer tentativa de mudá-la é um erro de compilação.

Cola rápida

Eu quero…Escreva
Um número inteiroint quantidade = 0;
Um número inteiro bem grandelong long populacao = 8000000000;
Um número com casas decimaisdouble preco = 4.99;
Verdadeiro ou falsobool estaPronto = false;
Um caracterechar inicial = 'R';
Textostd::string nome = "Roger"; (com #include <string>)
Recusar conversões com perdaint pontos{42};
Deixar o compilador escolher o tipoauto total = 0.0;
Um valor que nunca mudaconst double pi = 3.14159;
Mudar um valorpontos = 10; / pontos += 5; / pontos++;
Dividir mantendo os decimaisstatic_cast<double>(pizzas) / pessoas
Ver o tamanho de um tiposizeof(int)
Imprimir true / falsestd::cout << std::boolalpha << estaPronto;

Resumindo

Variáveis são o jeito de os programas lembrarem das coisas:

  • Uma variável tem tipo, nome e valor: int idade = 35;.
  • O tipo decide o tamanho e o alcance: um int tem 4 bytes e para em cerca de 2,1 bilhões; o long tem 4 bytes no Windows, mas 8 no Linux e no macOS.
  • Inicialize toda variável; ler uma que não tem valor é um erro.
  • Cuidado com as armadilhas dos números: a divisão inteira descarta o resto, valores que não cabem dão a volta sem nenhum aviso, e decimais como 0.1 + 0.2 não são exatos.
  • As chaves { } pegam o estreitamento, o auto deduz o tipo e o const tranca um valor.
  • Escolha nomes descritivos que sigam as regras: letras, dígitos e sublinhados, nunca começando com dígito.

Em seguida, use as suas variáveis para tomar decisões com o comando if, repetir trabalho com o laço for e guardar muitos valores de uma vez com 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.