Variáveis e tipos básicos
por Huxley SterlingEntenda o conceito
Uma variável é um espaço na memória com nome e tipo. Em C, toda variável precisa ser declarada antes do uso, com o tipo na frente: int vidas = 3;. O tipo define quanto espaço é reservado e como os bits são interpretados, e não muda depois da declaração.
Os tipos básicos são int para inteiros, double (e o menos preciso float) para números com parte decimal e char para um único caractere, escrito entre aspas simples ('A'). Há variações como long long, para inteiros grandes, e unsigned, que troca os negativos por um limite positivo maior.
O tipo também decide o resultado das contas: entre dois int, a divisão é inteira e descarta a parte decimal (7 / 2 dá 3), e o operador % devolve o resto. Para manter as casas decimais, um dos operandos precisa ser double, seja por uma constante como 2.0 ou por um cast, como (double)total.
Uma variável declarada sem valor contém lixo de memória, então inicialize sempre. Valores que não devem mudar ganham const, e o compilador recusa qualquer tentativa de alterá-los.
- Declare com tipo, nome e valor inicial (
int pontos = 0;); ler uma variável não inicializada dá um valor imprevisível. - Use
intpara contagens,doublepara valores com parte decimal echarpara um caractere entre aspas simples. - Cada tipo tem seu especificador no
printf:%dparaint,%fparadouble,%cparachare%lldparalong long. - Divisão entre inteiros descarta a parte decimal; converta um operando com
(double)antes de dividir para manter as casas. consttorna o valor somente leitura, e o compilador acusa erro se o código tentar alterá-lo.
Do conceito à prática
3 exemplos para ver a ideia funcionando.
01Placar do jogo com int, double e char
/* placar.c: declarar, atribuir e imprimir variáveis */
#include <stdio.h>
int main(void)
{
/* Declaração com inicialização: tipo, nome e valor */
int vidas = 3;
int pontos = 1200;
double tempo = 87.5; /* segundos, com parte decimal */
char rank = 'B'; /* um único caractere, entre aspas simples */
printf("Vidas: %d | Pontos: %d\n", vidas, pontos);
printf("Tempo: %.1f s | Rank: %c\n", tempo, rank);
/* A variável pode receber um novo valor depois */
vidas = vidas - 1;
pontos = pontos + 350;
rank = 'A';
puts("Depois da fase 2:");
printf("Vidas: %d | Pontos: %d | Rank: %c\n", vidas, pontos, rank);
return 0;
}
O exemplo declara variáveis de três tipos já com valor inicial e imprime cada uma com o especificador correspondente: %d para int, %.1f para double e %c para char.
Depois, as mesmas variáveis recebem novos valores com =. A declaração (com o tipo) acontece uma vez só; nas atribuições seguintes, o tipo não é repetido.
02Ajustando porções: divisão inteira e cast
/* porcoes.c: divisão inteira, conversão e constantes */
#include <stdio.h>
int main(void)
{
/* const impede que o valor seja alterado por engano */
const int PORCOES_RECEITA = 4;
int ovos = 3;
double farinha_g = 250.0;
int porcoes_desejadas = 6;
/* Só inteiros na conta: o resultado é int e a parte decimal some */
int ovos_inteiro = ovos * porcoes_desejadas / PORCOES_RECEITA;
/* Com um double na conta, a divisão mantém as casas decimais */
double ovos_exato = (double)ovos * porcoes_desejadas / PORCOES_RECEITA;
double farinha = farinha_g * porcoes_desejadas / PORCOES_RECEITA;
printf("Receita para %d porções\n", porcoes_desejadas);
printf("Ovos (conta inteira): %d\n", ovos_inteiro);
printf("Ovos (conta exata): %.1f\n", ovos_exato);
printf("Farinha: %.1f g\n", farinha);
/* O operador % devolve o resto da divisão inteira */
printf("Resto da conta inteira: %d\n",
ovos * porcoes_desejadas % PORCOES_RECEITA);
return 0;
}
Para ajustar a receita de 4 para 6 porções, 3 * 6 / 4 com inteiros dá 4, porque 18 / 4 descarta o .5; o % mostra o resto 2 que ficou de fora. Com (double)ovos na frente, a conta inteira passa a ser feita em ponto flutuante e dá 4.5. A farinha já é double, então a conta dela não perde nada.
A quantidade de porções da receita original está em uma const int: o nome explica o número e protege o valor contra alterações acidentais.
03Inventário: char como número, unsigned e sizeof
/* inventario.c: char é número, unsigned, long long e sizeof */
#include <stdio.h>
int main(void)
{
/* char guarda um código numérico: %c mostra a letra, %d o número */
char slot = 'A';
printf("Slot %c tem código %d\n", slot, slot);
slot = slot + 2;
printf("Dois slots depois: %c\n", slot);
/* unsigned char vai de 0 a 255 e "dá a volta" ao passar do limite */
unsigned char flechas = 250;
flechas = flechas + 10;
printf("Flechas depois de somar 10: %d\n", flechas);
/* long long comporta valores grandes; LL marca a constante */
long long ouro = 5000000000LL;
printf("Ouro acumulado: %lld\n", ouro);
/* float tem menos precisão que double */
float peso_f = 0.1f;
double peso_d = 0.1;
printf("float: %.10f\n", peso_f);
printf("double: %.10f\n", peso_d);
/* sizeof devolve o tamanho em bytes (um size_t, impresso com %zu) */
printf("char: %zu, int: %zu, double: %zu bytes\n",
sizeof(char), sizeof(int), sizeof(double));
return 0;
}
Um char é um inteiro pequeno: 'A' guarda o código 65, e somar 2 leva a 'C'. Já o unsigned char vai de 0 a 255, então 250 + 10 dá a volta e vira 4; tipos unsigned fazem essa conta módulo o limite em vez de ficar negativos. Para valores acima do limite do int, como 5 bilhões, use long long com %lld.
As duas linhas de peso mostram que 0.1 não tem representação exata em binário e que o float erra antes do double (algo como 0.1000000015 contra 0.1000000000). Por fim, sizeof informa quantos bytes cada tipo ocupa; o valor de int depende da plataforma, por isso ele é perguntado ao compilador em vez de suposto.
Agora é com você
Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.
01Ficha da receita de pão de queijoFácil
Guarde os dados de uma receita em variáveis e imprima a ficha exatamente como na saída esperada. Nenhum número ou letra da ficha pode ser escrito direto no texto do printf.
- Usar
intpara porções, tempo e temperatura,doublepara o polvilho echarpara a dificuldade. - Inicializar todas as variáveis na declaração.
- Imprimir cada valor com o especificador do seu tipo (
%d,%.2fe%c).
#include <stdio.h>
int main(void)
{
/* Declare aqui as variáveis da receita */
puts("Receita: Pão de queijo");
/* Imprima as demais linhas usando as variáveis */
return 0;
}
Receita: Pão de queijo
Porções: 6
Polvilho (kg): 0.50
Tempo de forno (min): 25
Temperatura: 180 graus
Dificuldade: B
Ver dica
Pergunte a cada dado: ele tem parte decimal? É uma letra só? A resposta escolhe o tipo, e o tipo escolhe o especificador.
Ver resposta
#include <stdio.h>
int main(void)
{
/* Cada informação fica numa variável do tipo adequado */
int porcoes = 6;
double polvilho_kg = 0.5;
int tempo_min = 25;
int temperatura = 180;
char dificuldade = 'B';
puts("Receita: Pão de queijo");
printf("Porções: %d\n", porcoes);
printf("Polvilho (kg): %.2f\n", polvilho_kg); /* duas casas */
printf("Tempo de forno (min): %d\n", tempo_min);
printf("Temperatura: %d graus\n", temperatura);
printf("Dificuldade: %c\n", dificuldade); /* %c para char */
return 0;
}
Passo a passo
- As cinco variáveis são declaradas no início de
main, cada uma com tipo, nome e valor inicial; declarar e inicializar na mesma linha evita usar uma variável com lixo de memória. - Porções, tempo e temperatura são contagens sem parte decimal, por isso usam
int. - A quantidade de polvilho tem parte decimal, então fica em
double, o tipo de ponto flutuante padrão em C. - A dificuldade é uma única letra:
charcom o valor entre aspas simples ('B'). - O título não depende de variável, então
putsbasta; as demais linhas usamprintfcom o especificador que combina com o tipo:%dparaint,%.2fparadoublee%cparachar. %.2fmostra0.5como0.50, com as duas casas pedidas na saída.
Por que funciona
Uma variável é um espaço na memória com nome e tipo. O tipo diz ao compilador quanto espaço reservar e como interpretar os bits, e diz a você qual especificador usar no printf. Escolhendo o tipo certo para cada dado, os valores saem exatamente como foram guardados.
Erros comuns
- Aspas duplas no
char:char dificuldade = "B";tenta guardar o endereço de uma string numchar; o GCC avisa e a saída sai errada. Use'B'. - Especificador trocado:
printf("Polvilho (kg): %d\n", polvilho_kg);passa umdoublepara%d, comportamento indefinido que costuma imprimir lixo. Use%f(aqui%.2f). - Guardar
0.5numint:int polvilho_kg = 0.5;descarta a parte decimal e a variável vale0. Usedouble. - Usar a variável sem inicializar:
int porcoes; printf("%d", porcoes);imprime um valor imprevisível. Sempre dê um valor antes de ler.
Outra forma de resolver
Dá para declarar várias variáveis do mesmo tipo numa linha só:
int porcoes = 6, tempo_min = 25, temperatura = 180;
É compacto e útil para valores relacionados, mas uma declaração por linha facilita comentar e encontrar cada variável.
Saída esperada
Receita: Pão de queijo
Porções: 6
Polvilho (kg): 0.50
Tempo de forno (min): 25
Temperatura: 180 graus
Dificuldade: B
02Média do boletim com e sem castMédio
Calcule a média das notas 7, 8 e 10 de um aluno de duas formas: com divisão inteira e com cast para double, e imprima as duas para comparar.
- Guardar as três notas e a soma em variáveis
int. - Calcular a média inteira com
soma / 3e guardá-la numint. - Calcular a média real com
(double)soma / 3e mostrá-la com%.2f.
#include <stdio.h>
int main(void)
{
int nota1 = 7;
int nota2 = 8;
int nota3 = 10;
/* Calcule a soma e as duas médias */
puts("Boletim de Rafa");
/* Imprima soma, média inteira e média real */
return 0;
}
Boletim de Rafa
Soma das notas: 25
Média (divisão inteira): 8
Média (com cast): 8.33
Ver dica
O tipo da divisão é decidido pelos operandos, não pela variável que recebe o resultado.
Ver resposta
#include <stdio.h>
int main(void)
{
int nota1 = 7;
int nota2 = 8;
int nota3 = 10;
int soma = nota1 + nota2 + nota3;
/* int / int: a parte decimal é descartada */
int media_inteira = soma / 3;
/* O cast converte soma para double ANTES da divisão */
double media_real = (double)soma / 3;
puts("Boletim de Rafa");
printf("Soma das notas: %d\n", soma);
printf("Média (divisão inteira): %d\n", media_inteira);
printf("Média (com cast): %.2f\n", media_real);
return 0;
}
Passo a passo
- As três notas são inteiras, então ficam em variáveis
int; a soma de inteiros também éinte vale25. soma / 3divide dois inteiros: o C faz divisão inteira e descarta a parte decimal, resultando em8.(double)somaé um cast: converte o valor desomaparadoublesó nessa expressão, sem mudar a variável.- Como um dos operandos agora é
double, o3também é convertido e a divisão dá8.333.... %dimprime a média inteira e%.2farredonda a média real para8.33.- O título não tem valores, então usa
puts.
Por que funciona
O tipo do resultado de uma operação depende dos tipos dos operandos. Entre dois int, a divisão é inteira; se pelo menos um for double, o outro é promovido e a conta é feita em ponto flutuante. O cast é a forma explícita de dizer ao compilador "trate este valor como double aqui".
Erros comuns
- Guardar em
doublesem converter:double media_real = soma / 3;ainda dá8.00, porque a divisão inteira acontece antes da atribuição. Converta um operando:(double)soma / 3. - Cast no lugar errado:
(double)(soma / 3)converte o resultado já truncado e também dá8.00. O cast precisa vir antes da divisão. %dcomdouble:printf("%d\n", media_real);é comportamento indefinido e imprime lixo; o-Wallavisa. Use%f.
Outra forma de resolver
Em vez do cast, use uma constante double no divisor:
double media_real = soma / 3.0;
Funciona porque 3.0 já é double. O cast é preferível quando o divisor também é uma variável int, como (double)soma / quantidade.
Saída esperada
Boletim de Rafa
Soma das notas: 25
Média (divisão inteira): 8
Média (com cast): 8.33
03Relógio da partida em horas, minutos e segundosDesafio
Uma partida durou 9876 segundos. Converta esse total para o formato HH:MM:SS, mostre quantos minutos completos ele tem e quanto vale em horas com duas casas decimais.
- Declarar
SEGUNDOS_POR_MINUTOeSEGUNDOS_POR_HORAcomoconst inte usá-las em todas as contas. - Separar horas, minutos e segundos só com os operadores
/e%sobre inteiros. - Mostrar o tempo formatado com
%02dem cada parte. - Calcular as horas decimais com cast para
doublee exibir com%.2f.
#include <stdio.h>
int main(void)
{
const int SEGUNDOS_POR_MINUTO = 60;
const int SEGUNDOS_POR_HORA = 3600;
int total = 9876;
/* Calcule horas, minutos, segundos, minutos completos e horas decimais */
return 0;
}
Tempo total: 9876 s
Formatado: 02:44:36
Minutos completos: 164
Em horas: 2.74 h
Ver dica
Primeiro tire as horas cheias e guarde o que sobrou com %; os minutos e segundos saem dessa sobra.
Ver resposta
#include <stdio.h>
int main(void)
{
/* Constantes com nome no lugar de números mágicos */
const int SEGUNDOS_POR_MINUTO = 60;
const int SEGUNDOS_POR_HORA = 3600;
int total = 9876;
/* Divisão inteira dá as horas cheias; % dá o que sobra */
int horas = total / SEGUNDOS_POR_HORA;
int resto = total % SEGUNDOS_POR_HORA;
int minutos = resto / SEGUNDOS_POR_MINUTO;
int segundos = resto % SEGUNDOS_POR_MINUTO;
int minutos_completos = total / SEGUNDOS_POR_MINUTO;
/* Cast para manter a parte decimal das horas */
double horas_decimais = (double)total / SEGUNDOS_POR_HORA;
printf("Tempo total: %d s\n", total);
printf("Formatado: %02d:%02d:%02d\n", horas, minutos, segundos);
printf("Minutos completos: %d\n", minutos_completos);
printf("Em horas: %.2f h\n", horas_decimais);
return 0;
}
Passo a passo
const intcria valores que não podem ser alterados depois; nomear60e3600deixa claro o que cada conta faz e o compilador recusa uma atribuição acidental.total / SEGUNDOS_POR_HORAé divisão inteira:9876 / 3600dá2horas cheias.total % SEGUNDOS_POR_HORAdevolve o resto,2676segundos que não completam uma hora.- O mesmo par
/e%aplicado ao resto separa44minutos e36segundos. total / SEGUNDOS_POR_MINUTOdá os minutos completos do tempo todo:164.(double)total / SEGUNDOS_POR_HORAconverte antes de dividir, então o resultado é2.7433..., mostrado como2.74por%.2f.%02dimprime o inteiro com pelo menos 2 dígitos, completando com zero à esquerda:2vira02.
Por que funciona
Aqui a divisão inteira, que costuma ser armadilha, é exatamente o que se quer: / entre inteiros dá a quantidade de unidades cheias e % dá a sobra. Encadeando os dois, de horas para minutos e de minutos para segundos, o total se decompõe sem perder nenhum segundo (2 × 3600 + 44 × 60 + 36 = 9876).
Quando a parte decimal importa, como nas horas em formato decimal, o cast para double muda o tipo da conta. A mesma variável int serve aos dois casos; o que decide o resultado é o tipo dos operandos em cada expressão.
Erros comuns
- Calcular os minutos a partir do total:
int minutos = total / SEGUNDOS_POR_MINUTO;dá164, não44, porque inclui os minutos das horas já contadas. Use o resto:resto / SEGUNDOS_POR_MINUTO. - Esquecer o
0em%02d:%2dcompleta com espaço e a saída fica2:44:36. O0é o que preenche com zeros. - Dividir sem cast:
double horas_decimais = total / SEGUNDOS_POR_HORA;faz divisão inteira e mostra2.00. Converta um operando antes. - Tentar alterar a constante:
SEGUNDOS_POR_HORA = 60;não compila (assignment of read-only variable). Se o valor muda, ele não deveria serconst.
Outra forma de resolver
As constantes também podem ser macros do pré-processador:
#define SEGUNDOS_POR_MINUTO 60
#define SEGUNDOS_POR_HORA 3600
O #define troca o nome pelo valor antes da compilação e era o estilo clássico em C; ele é preferível quando o valor precisa ser uma constante em tempo de compilação, como o tamanho de um vetor global. Para contas como estas, const int tem tipo e respeita escopo.
Saída esperada
Tempo total: 9876 s
Formatado: 02:44:36
Minutos completos: 164
Em horas: 2.74 h