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 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.

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 Briar Westbrook
Iniciante

Entenda 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).

↳ Pontos-chave
  • A declaração segue o formato tipo nome = valor; e o tipo não muda depois: uma variável int só recebe inteiros.
  • double é aproximado (0.1 + 0.2 == 0.3 dá False); para dinheiro use decimal com sufixo m ou guarde os centavos em inteiros.
  • var não cria variável sem tipo: o compilador escolhe o tipo pelo valor inicial e ele fica fixo.
  • Divisão entre dois int descarta a parte fracionária: 7 / 2 vale 3, mas 7 / 2.0 vale 3.5.
  • const guarda um valor que nunca muda; cast como (int)media converte 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

estoque.cs
// 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

personagem.cs
// 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.cs
// 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.

↳ Requisitos
  • Declarar cada variável com o tipo explícito, sem var.
  • Usar pelo menos os tipos string, int, char e bool.
  • Imprimir com interpolação ($"..."), uma linha por informação.
  • A saída deve ser idêntica à esperada, inclusive True com T maiúsculo.
código inicial
// 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
saída esperada
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

  1. string titulo e string autor guardam textos, sempre entre aspas duplas.
  2. int ano = 1899; usa um inteiro, pois o ano é um número sem casas decimais e pode entrar em contas depois.
  3. char estante = 'B'; guarda um único caractere; por isso as aspas são simples.
  4. bool disponivel = true; só aceita true ou false, o tipo natural para uma pergunta de sim ou não.
  5. Cada Console.WriteLine($"...") usa interpolação: o que está entre chaves é trocado pelo valor da variável.
  6. Ao imprimir um bool, o C# escreve True ou False, 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" é uma string. Use 'B'.
  • Ano como texto: int ano = "1899"; também não compila. Tire as aspas ou, se o valor vier como texto, converta com int.Parse.
  • Esquecer o $: Console.WriteLine("Ano: {ano}"); imprime {ano} literalmente. A interpolação só acontece com o $ antes das aspas.
  • Escrever True no 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.

↳ Requisitos
  • Guardar as porções originais numa const int e as quantidades em variáveis int.
  • Calcular o fator com cast para double antes da divisão, para obter 1.5.
  • Converter os ovos para int com (int)Math.Ceiling(...), já que não existe meio ovo.
  • Imprimir também o resultado da divisão entre dois int, que dá 1.
código inicial
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
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
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

  1. const int PorcoesOriginais = 4; declara uma constante: o valor faz parte da receita e não deve mudar no programa.
  2. (double)porcoesDesejadas / PorcoesOriginais converte o 6 para double antes da divisão; como um dos lados é double, a conta inteira vira double e dá 1.5.
  3. farinhaGramas * fator multiplica um int por um double; o int é promovido automaticamente e o resultado, 750, é double.
  4. ovos * fator dá 4.5; Math.Ceiling arredonda para cima (5.0) e o cast (int) transforma em inteiro, já que Math.Ceiling devolve double.
  5. porcoesDesejadas / PorcoesOriginais sem cast é uma divisão entre dois int: a parte fracionária é descartada e o resultado é 1.
  6. Um double com valor inteiro, como 750, é impresso sem casas decimais, por isso a saída mostra 750 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 em 1.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 de double para int.
  • Usar só o cast: (int)(ovos * fator) corta o 4.5 para 4, 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.

↳ Requisitos
  • Guardar os preços em centavos em variáveis int e o percentual de desconto numa const int.
  • Calcular subtotal, desconto e total em long, sem usar double nem decimal nas contas de dinheiro.
  • Formatar os valores com / 100 para os reais e % 100 com :D2 para os centavos.
  • Guardar o resultado de 0.1 + 0.2 == 0.3 numa variável bool e imprimi-la na última linha.
código inicial
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
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
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

  1. Os preços ficam em centavos (3990 em vez de 39.90): inteiros são exatos, então nenhuma conta perde um centavo por arredondamento.
  2. const int DescontoPercentual = 10; deixa o percentual com nome e num só lugar; mudar a promoção é mudar uma linha.
  3. (long)precoCamiseta * qtdCamiseta converte o primeiro termo para long; a partir dele, as multiplicações e somas seguintes também são feitas em long, o que evita estouro em compras grandes.
  4. subtotal * DescontoPercentual / 100 multiplica antes de dividir: 14220 * 10 / 100 dá 1422. Dividir primeiro faria a divisão inteira descartar centavos.
  5. Na impressão, subtotal / 100 é a divisão inteira (os reais) e subtotal % 100 é o resto (os centavos).
  6. O formato :D2 completa os centavos com zero à esquerda, então 5 vira 05, e a vírgula fica dentro do texto, sem depender do idioma do sistema.
  7. bool somaExata = 0.1 + 0.2 == 0.3; guarda false, porque 0.1 e 0.2 não têm representação exata em binário; impresso, o valor aparece como False.

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 * DescontoPercentual dá 142 * 10 = 1420, perdendo 2 centavos. Multiplique primeiro.
  • Esquecer o :D2: um total de 12705 centavos sairia R$ 127,5 em vez de R$ 127,05. Use {total % 100:D2}.
  • Guardar o resultado em int: int subtotal = (long)precoCamiseta * qtdCamiseta + ...; gera o erro CS0266, porque long não cabe implicitamente em int.
  • Usar double para dinheiro: 39.90 * 2 + 24.90 pode gerar algo como 104.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

Últimas lições

Ver o arquivo completo →