Variáveis e tipos básicos
por Briar WestbrookEntenda o conceito
Uma variável é um nome que guarda um valor na memória para ser usado depois. Em C# toda variável tem um tipo, definido na declaração e fixo para sempre: int quantidade = 12; cria uma variável inteira, e ela nunca vai guardar um texto. Esse controle é feito pelo compilador, que recusa o programa antes de ele rodar se você misturar tipos de forma errada.
Os tipos básicos mais usados são int (inteiros), long (inteiros maiores), double (números com casas decimais, rápidos mas aproximados), decimal (casas decimais exatas, ideal para dinheiro, com o sufixo m), bool (true ou false), char (um caractere, entre aspas simples) e string (texto, entre aspas duplas).
Com var, o compilador infere o tipo pelo valor inicial: var vida = 100; continua sendo int, só que você não precisa escrevê-lo. Para valores que não mudam, use const. E, quando for preciso trocar de tipo, existem as conversões: implícitas quando não há perda (int para double) e explícitas com cast quando pode haver perda ((int)7.9 vale 7).
- A declaração segue o formato
tipo nome = valor;e o tipo não muda depois: uma variávelintsó recebe inteiros. doubleé aproximado (0.1 + 0.2 == 0.3dáFalse); para dinheiro usedecimalcom sufixomou guarde os centavos em inteiros.varnão cria variável sem tipo: o compilador escolhe o tipo pelo valor inicial e ele fica fixo.- Divisão entre dois
intdescarta a parte fracionária:7 / 2vale3, mas7 / 2.0vale3.5. constguarda um valor que nunca muda; cast como(int)mediaconverte de forma explícita e corta as casas decimais.
Do conceito à prática
3 exemplos para ver a ideia funcionando.
01Ficha de produto com tipos explícitos
// Ficha de um produto do estoque: cada variável tem um tipo explícito.
// Sintaxe: tipo nome = valor;
string produto = "Tênis de corrida";
int quantidade = 12; // número inteiro
decimal preco = 249.90m; // decimal: o sufixo m é obrigatório
double pesoKg = 0.85; // double: número com casas decimais
bool emPromocao = false; // true ou false
char tamanho = 'M'; // um único caractere, aspas simples
Console.WriteLine("=== Estoque ===");
// A interpolação $"..." coloca o valor de cada variável no texto
Console.WriteLine($"Produto: {produto}");
Console.WriteLine($"Quantidade: {quantidade}");
Console.WriteLine($"Preço: {preco}");
Console.WriteLine($"Peso (kg): {pesoKg}");
Console.WriteLine($"Em promoção: {emPromocao}");
Console.WriteLine($"Tamanho: {tamanho}");
// Uma variável pode receber um novo valor do mesmo tipo
quantidade = quantidade - 2;
Console.WriteLine($"Depois de 2 vendas: {quantidade} unidades");
// Cada tipo numérico tem limites
Console.WriteLine($"Maior int possível: {int.MaxValue}");
Cada dado do produto ganhou o tipo que combina com ele: string para o nome, int para a quantidade, decimal para o preço (repare no sufixo m, sem ele o compilador trata 249.90 como double e recusa a atribuição), double para o peso, bool para a promoção e char para o tamanho.
A interpolação $"...{variavel}..." insere o valor no texto. O exemplo também mostra que a variável pode receber um novo valor do mesmo tipo (quantidade = quantidade - 2;) e que cada tipo numérico tem limites, como int.MaxValue. O separador decimal de 249.90 segue o idioma do sistema: em português aparece com vírgula.
02Personagem de jogo com var e const
// Ficha de um personagem de jogo usando var e const.
// Com var, o compilador descobre o tipo pelo valor inicial.
const int VidaMaxima = 100; // constante: nunca muda
var nome = "Lia"; // string
var vida = VidaMaxima; // int
var nivel = 1; // int
var ouro = 15.5; // double
var temEscudo = true; // bool
// GetType().Name mostra o tipo que o compilador escolheu
Console.WriteLine($"nome é {nome.GetType().Name}");
Console.WriteLine($"vida é {vida.GetType().Name}");
Console.WriteLine($"ouro é {ouro.GetType().Name}");
Console.WriteLine($"temEscudo é {temEscudo.GetType().Name}");
// Operadores compostos alteram a própria variável
vida -= 35; // o mesmo que vida = vida - 35
nivel++; // soma 1
temEscudo = false;
Console.WriteLine($"{nome} está no nível {nivel}");
Console.WriteLine($"Vida: {vida}/{VidaMaxima}");
Console.WriteLine($"Escudo: {temEscudo}");
// vida = "cheia"; // erro CS0029: vida é int e continua int
// VidaMaxima = 120; // erro CS0131: uma const não pode ser alterada
Com var, o tipo vem do valor inicial: "Lia" vira String, 1 vira Int32 (o nome interno de int), 15.5 vira Double e true vira Boolean. O GetType().Name mostra isso em tempo de execução, provando que var não é uma variável sem tipo.
Os operadores compostos (-=, ++) atualizam a variável sem repetir o nome. As duas linhas comentadas no fim não compilam: uma tenta pôr texto num int e a outra tenta alterar uma const. É o compilador protegendo o tipo e as constantes.
03Boletim escolar com conversões
// Boletim escolar: conversões entre tipos numéricos e texto.
int nota1 = 7;
int nota2 = 8;
int nota3 = 8;
int soma = nota1 + nota2 + nota3;
// int / int dá int: a parte fracionária é descartada
int mediaInteira = soma / 3;
// Conversão implícita: int cabe em double sem perda
double somaReal = soma;
double media = somaReal / 3;
// Conversão explícita (cast): double para int corta as casas
int mediaCortada = (int)media;
double mediaArredondada = Math.Round(media, 1);
// Texto para número: int.Parse lê o conteúdo da string
string faltasDigitadas = "4";
int faltas = int.Parse(faltasDigitadas);
Console.WriteLine($"Soma das notas: {soma}");
Console.WriteLine($"Média com int: {mediaInteira}");
// Num sistema em português, double aparece com vírgula: 7,7
Console.WriteLine($"Média com double: {mediaArredondada}");
Console.WriteLine($"Média com cast para int: {mediaCortada}");
Console.WriteLine($"Faltas: {faltas + 1} (somou mais uma)");
bool aprovado = media >= 7 && faltas < 10;
Console.WriteLine($"Aprovado: {aprovado}");
A soma das notas é 23, e 23 / 3 com dois int dá 7, sem casas decimais. Ao copiar a soma para um double (conversão implícita, sem perda), a divisão passa a dar 7.666..., que Math.Round(media, 1) arredonda para 7.7. Já (int)media é uma conversão explícita: corta as casas e devolve 7, sem arredondar.
O exemplo também converte texto em número com int.Parse, comum quando o valor vem do teclado ou de um arquivo, e combina tudo num bool com &&. Os números com casas decimais aparecem com vírgula ou ponto conforme o idioma do sistema.
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 um livro do acervoFácil
Declare variáveis para os dados de um livro da biblioteca (título, autor, ano, estante e se está disponível), escolhendo o tipo certo para cada uma, e imprima uma ficha com uma informação por linha.
- Declarar cada variável com o tipo explícito, sem
var. - Usar pelo menos os tipos
string,int,charebool. - Imprimir com interpolação (
$"..."), uma linha por informação. - A saída deve ser idêntica à esperada, inclusive
Truecom T maiúsculo.
// Ficha de um livro do acervo
string titulo = "Dom Casmurro";
// declare autor, ano, estante e disponivel
Console.WriteLine($"Título: {titulo}");
// imprima as outras quatro linhas
Título: Dom Casmurro
Autor: Machado de Assis
Ano: 1899
Estante: B
Disponível: True
Ver dica
O ano é um número inteiro, a estante é uma única letra (aspas simples) e a disponibilidade é sim ou não.
Ver resposta
// Ficha de um livro do acervo, com um tipo explícito para cada dado
string titulo = "Dom Casmurro";
string autor = "Machado de Assis";
int ano = 1899;
char estante = 'B'; // char usa aspas simples
bool disponivel = true;
Console.WriteLine($"Título: {titulo}");
Console.WriteLine($"Autor: {autor}");
Console.WriteLine($"Ano: {ano}");
Console.WriteLine($"Estante: {estante}");
Console.WriteLine($"Disponível: {disponivel}");
Passo a passo
string tituloestring autorguardam textos, sempre entre aspas duplas.int ano = 1899;usa um inteiro, pois o ano é um número sem casas decimais e pode entrar em contas depois.char estante = 'B';guarda um único caractere; por isso as aspas são simples.bool disponivel = true;só aceitatrueoufalse, o tipo natural para uma pergunta de sim ou não.- Cada
Console.WriteLine($"...")usa interpolação: o que está entre chaves é trocado pelo valor da variável. - Ao imprimir um
bool, o C# escreveTrueouFalse, com a primeira letra maiúscula.
Por que funciona
Cada variável recebe um tipo compatível com o valor, e o compilador confere isso antes de rodar. A interpolação converte cada valor em texto na hora de montar a linha, então números, caracteres e booleanos podem ser misturados ao texto sem conversão manual.
Erros comuns
- Aspas duplas no
char:char estante = "B";gera o erro CS0029, porque"B"é umastring. Use'B'. - Ano como texto:
int ano = "1899";também não compila. Tire as aspas ou, se o valor vier como texto, converta comint.Parse. - Esquecer o
$:Console.WriteLine("Ano: {ano}");imprime{ano}literalmente. A interpolação só acontece com o$antes das aspas. - Escrever
Trueno código:bool disponivel = True;não compila; no código o valor é minúsculo,true.
Outra forma de resolver
Você pode declarar tudo com var (var ano = 1899;) e o resultado seria o mesmo, pois o compilador infere os mesmos tipos. O enunciado pede tipos explícitos para praticar a escolha de cada um; no dia a dia, var é comum quando o tipo é óbvio pelo valor.
Saída esperada
Título: Dom Casmurro
Autor: Machado de Assis
Ano: 1899
Estante: B
Disponível: True
02Receita ajustada para mais porçõesMédio
Uma receita de 4 porções usa 500 g de farinha e 3 ovos. Calcule as quantidades para 6 porções usando um fator de multiplicação do tipo double, arredonde os ovos para cima e mostre também qual seria o fator se a divisão fosse feita só com inteiros.
- Guardar as porções originais numa
const inte as quantidades em variáveisint. - Calcular o fator com cast para
doubleantes da divisão, para obter 1.5. - Converter os ovos para
intcom(int)Math.Ceiling(...), já que não existe meio ovo. - Imprimir também o resultado da divisão entre dois
int, que dá 1.
const int PorcoesOriginais = 4;
int porcoesDesejadas = 6;
int farinhaGramas = 500;
int ovos = 3;
// calcule o fator (double), a farinha e os ovos ajustados
// calcule o fator com divisão inteira, para comparar
Receita original: 4 porções
Receita ajustada: 6 porções
Farinha: 750 g
Ovos: 5
Com divisão inteira, o fator seria 1
Ver dica
Converta um dos lados da divisão para double antes de dividir; se converter o resultado, a parte fracionária já terá se perdido.
Ver resposta
// Ajusta uma receita de 4 para 6 porções
const int PorcoesOriginais = 4;
int porcoesDesejadas = 6;
int farinhaGramas = 500;
int ovos = 3;
// O cast para double vem antes da divisão: 6 / 4 com int daria 1
double fator = (double)porcoesDesejadas / PorcoesOriginais;
double farinhaAjustada = farinhaGramas * fator;
// Não existe meio ovo: arredonda para cima e converte para int
int ovosAjustados = (int)Math.Ceiling(ovos * fator);
// Divisão entre dois int descarta a parte fracionária
int fatorErrado = porcoesDesejadas / PorcoesOriginais;
Console.WriteLine($"Receita original: {PorcoesOriginais} porções");
Console.WriteLine($"Receita ajustada: {porcoesDesejadas} porções");
Console.WriteLine($"Farinha: {farinhaAjustada} g");
Console.WriteLine($"Ovos: {ovosAjustados}");
Console.WriteLine($"Com divisão inteira, o fator seria {fatorErrado}");
Passo a passo
const int PorcoesOriginais = 4;declara uma constante: o valor faz parte da receita e não deve mudar no programa.(double)porcoesDesejadas / PorcoesOriginaisconverte o 6 paradoubleantes da divisão; como um dos lados édouble, a conta inteira viradoublee dá1.5.farinhaGramas * fatormultiplica umintpor umdouble; ointé promovido automaticamente e o resultado,750, édouble.ovos * fatordá4.5;Math.Ceilingarredonda para cima (5.0) e o cast(int)transforma em inteiro, já queMath.Ceilingdevolvedouble.porcoesDesejadas / PorcoesOriginaissem cast é uma divisão entre doisint: a parte fracionária é descartada e o resultado é1.- Um
doublecom valor inteiro, como750, é impresso sem casas decimais, por isso a saída mostra750 g.
Por que funciona
O tipo do resultado de uma operação depende dos tipos dos operandos. Com dois int, a divisão é inteira; basta um double para a conta ser feita com casas decimais. O cast explícito no fim é necessário porque passar de double para int pode perder informação, e o C# exige que você assuma essa perda por escrito.
Erros comuns
- Cast no lugar errado:
(double)(porcoesDesejadas / PorcoesOriginais)divide primeiro como inteiros (dá1) e só depois converte, resultando em1.0. Converta um operando, não o resultado. - Esquecer o cast dos ovos:
int ovosAjustados = Math.Ceiling(ovos * fator);gera o erro CS0266, porque não há conversão implícita dedoubleparaint. - Usar só o cast:
(int)(ovos * fator)corta o4.5para4, deixando a receita com ovos a menos. O cast trunca; quem arredonda para cima éMath.Ceiling.
Outra forma de resolver
Em vez do cast, dá para escrever um literal double na conta: porcoesDesejadas / 4.0. Funciona, mas repete o número 4 em vez de usar a constante; o cast é preferível quando os dois valores estão em variáveis.
Saída esperada
Receita original: 4 porções
Receita ajustada: 6 porções
Farinha: 750 g
Ovos: 5
Com divisão inteira, o fator seria 1
03Caixa da loja em centavosDesafio
Calcule o subtotal, o desconto de 10% e o total de uma compra (2 camisetas de R$ 39,90, 1 boné de R$ 24,90 e 3 meias de R$ 12,50) guardando os preços em centavos, como inteiros. Mostre os valores no formato R$ 142,20, a quantidade de itens e, por fim, prove com um bool que double não soma 0.1 + 0.2 de forma exata.
- Guardar os preços em centavos em variáveis
inte o percentual de desconto numaconst int. - Calcular subtotal, desconto e total em
long, sem usardoublenemdecimalnas contas de dinheiro. - Formatar os valores com
/ 100para os reais e% 100com:D2para os centavos. - Guardar o resultado de
0.1 + 0.2 == 0.3numa variávelboole imprimi-la na última linha.
const int DescontoPercentual = 10;
int precoCamiseta = 3990; // R$ 39,90
int precoBone = 2490; // R$ 24,90
int precoMeia = 1250; // R$ 12,50
// declare as quantidades e calcule subtotal, desconto e total em long
// imprima os valores no formato R$ reais,centavos
// compare 0.1 + 0.2 com 0.3 usando double
Subtotal: R$ 142,20
Desconto (10%): R$ 14,22
Total: R$ 127,98
Itens no carrinho: 6
0.1 + 0.2 == 0.3 em double? False
Ver dica
Para 14220 centavos, 14220 / 100 dá os reais e 14220 % 100 dá os centavos; o formato :D2 impede que 5 centavos apareçam como ,5.
Ver resposta
// Caixa da loja: dinheiro em centavos (inteiros) para não perder precisão
const int DescontoPercentual = 10;
int precoCamiseta = 3990; // R$ 39,90
int precoBone = 2490; // R$ 24,90
int precoMeia = 1250; // R$ 12,50
int qtdCamiseta = 2;
int qtdBone = 1;
int qtdMeia = 3;
// long dá folga para somas grandes; o cast no primeiro termo
// faz toda a conta acontecer em long
long subtotal = (long)precoCamiseta * qtdCamiseta
+ precoBone * qtdBone
+ precoMeia * qtdMeia;
long desconto = subtotal * DescontoPercentual / 100;
long total = subtotal - desconto;
int itens = qtdCamiseta + qtdBone + qtdMeia;
// / separa os reais, % sobra os centavos; D2 garante dois dígitos
Console.WriteLine($"Subtotal: R$ {subtotal / 100},{subtotal % 100:D2}");
Console.WriteLine($"Desconto ({DescontoPercentual}%): R$ {desconto / 100},{desconto % 100:D2}");
Console.WriteLine($"Total: R$ {total / 100},{total % 100:D2}");
Console.WriteLine($"Itens no carrinho: {itens}");
// Por que não double? Frações decimais não têm representação exata
bool somaExata = 0.1 + 0.2 == 0.3;
Console.WriteLine($"0.1 + 0.2 == 0.3 em double? {somaExata}");
Passo a passo
- Os preços ficam em centavos (
3990em vez de39.90): inteiros são exatos, então nenhuma conta perde um centavo por arredondamento. const int DescontoPercentual = 10;deixa o percentual com nome e num só lugar; mudar a promoção é mudar uma linha.(long)precoCamiseta * qtdCamisetaconverte o primeiro termo paralong; a partir dele, as multiplicações e somas seguintes também são feitas emlong, o que evita estouro em compras grandes.subtotal * DescontoPercentual / 100multiplica antes de dividir:14220 * 10 / 100dá1422. Dividir primeiro faria a divisão inteira descartar centavos.- Na impressão,
subtotal / 100é a divisão inteira (os reais) esubtotal % 100é o resto (os centavos). - O formato
:D2completa os centavos com zero à esquerda, então5vira05, e a vírgula fica dentro do texto, sem depender do idioma do sistema. bool somaExata = 0.1 + 0.2 == 0.3;guardafalse, porque0.1e0.2não têm representação exata em binário; impresso, o valor aparece comoFalse.
Por que funciona
Cada tipo tem um papel: int para preços e quantidades, long para totais que podem crescer, bool para guardar o resultado de uma comparação. Como dinheiro em centavos é sempre inteiro, divisão inteira e resto bastam para separar reais e centavos, e o resultado não varia com o idioma do sistema, ao contrário de um double impresso direto.
Erros comuns
- Dividir antes de multiplicar:
subtotal / 100 * DescontoPercentualdá142 * 10 = 1420, perdendo 2 centavos. Multiplique primeiro. - Esquecer o
:D2: um total de12705centavos sairiaR$ 127,5em vez deR$ 127,05. Use{total % 100:D2}. - Guardar o resultado em
int:int subtotal = (long)precoCamiseta * qtdCamiseta + ...;gera o erro CS0266, porquelongnão cabe implicitamente emint. - Usar
doublepara dinheiro:39.90 * 2 + 24.90pode gerar algo como104.69999999999999, exatamente o problema mostrado na última linha.
Outra forma de resolver
O tipo decimal foi feito para dinheiro: decimal preco = 39.90m; guarda o valor exato com casas decimais, e total.ToString("C", new CultureInfo("pt-BR")) formata como moeda. É a escolha preferida em sistemas reais; os centavos inteiros são úteis quando você quer controle total da formatação ou quando o banco de dados guarda valores assim.
Saída esperada
Subtotal: R$ 142,20
Desconto (10%): R$ 14,22
Total: R$ 127,98
Itens no carrinho: 6
0.1 + 0.2 == 0.3 em double? False