Variáveis e Tipos de Dados
Variáveis são como caixas com etiquetas — cada caixa tem um nome e um tipo, e só pode guardar o tipo certo de item. Coloque a coisa errada, e as coisas dão errado.
O Que É uma Variável
Uma variável é uma posição de memória nomeada no seu programa usada para armazenar dados. Pense nela como uma caixa:
- Nome da variável: A etiqueta na caixa, para você encontrá-la
- Tipo de dado: Que tipo de itens a caixa pode guardar
- Valor da variável: O que está dentro da caixa no momento
- Endereço de memória: A localização da caixa no armazém
Declaração e Inicialização de Variáveis
Declarando uma Variável
Declarar uma variável diz ao compilador: "Preciso de uma caixa, aqui está o nome e o tipo de coisas que ela guarda."
int idade;
float peso;
char tipo_sanguineo;
Após a declaração, o valor da variável é indefinido (um valor lixo) — contém qualquer dado aleatório que ficou naquela posição de memória. Nunca use uma variável não inicializada!
Inicializando uma Variável
Inicializar significa dar um valor inicial à variável no mesmo momento em que você a declara:
int idade = 20;
float peso = 65.5f;
char tipo_sanguineo = 'A';
Declarar Primeiro, Atribuir Depois
Você também pode declarar primeiro e atribuir depois:
int idade;
idade = 20;
Isso tem o mesmo efeito, mas a abordagem em duas etapas é mais dispersa, facilitando o uso acidental da variável entre a declaração e a atribuição enquanto ela ainda está não inicializada.
Declarando Múltiplas Variáveis do Mesmo Tipo
int a = 1, b = 2, c = 3;
Regras de Nomenclatura de Variáveis
C tem regras estritas para nomes de variáveis:
Deve seguir:
- Só pode conter letras (a-z, A-Z), dígitos (0-9) e underscores (_)
- Deve começar com uma letra ou underscore — não pode começar com um dígito
- Não pode ser uma palavra-chave de C (como
int,return,if, etc.) - Diferencia maiúsculas de minúsculas (
Idadeeidadesão variáveis diferentes)
Deveria seguir:
- Nomes devem ser significativos: use
quantidade_alunosem vez deqa - Use o estilo snake_case (letras minúsculas + underscores)
- Evite nomes que comecem com underscore duplo (como
__contador) — compiladores usam esses internamente - Evite nomes excessivamente longos (mais de 31 caracteres podem não ser suportados por todos os compiladores)
| Nome | Válido? | Observações |
|---|---|---|
idade |
Válido | Curto e significativo |
_contador |
Válido | Começa com underscore |
nome_aluno |
Válido | Estilo snake_case |
2o_lugar |
Inválido | Começa com um dígito |
minha-idade |
Inválido | Contém hífen (interpretado como subtração) |
int |
Inválido | Palavra-chave |
Idade |
Válido, mas não recomendado | Primeira letra maiúscula geralmente reservada para nomes de tipos |
Tipos de Dados Básicos
Um tipo de dado em C determina quanta memória uma variável ocupa, o intervalo de valores que pode armazenar e como os dados são interpretados. Aqui estão os tipos de dados básicos do C99:
Tipos Inteiros
| Tipo | Tamanho (bytes) | Intervalo Típico | Especificador de Formato |
|---|---|---|---|
char |
1 | -128 ~ 127 | %c ou %d |
unsigned char |
1 | 0 ~ 255 | %u |
short |
2 | -32768 ~ 32767 | %hd |
unsigned short |
2 | 0 ~ 65535 | %hu |
int |
4 | -2147483648 ~ 2147483647 | %d |
unsigned int |
4 | 0 ~ 4294967295 | %u |
long |
4 ou 8 | Depende da plataforma | %ld |
unsigned long |
4 ou 8 | Depende da plataforma | %lu |
long long |
8 | -9223372036854775808 ~ 9223372036854775807 | %lld |
int é suficiente. Use long long quando precisar de um intervalo maior, e char para caracteres. short é raramente usado em plataformas modernas porque int costuma ser igualmente eficiente.
int com 4 bytes, que é o caso na maioria das plataformas modernas. Porém, o padrão C só exige que int tenha pelo menos 2 bytes. O tamanho real depende da plataforma — use sizeof para confirmar.
Tipos de Ponto Flutuante
| Tipo | Tamanho (bytes) | Dígitos Significativos | Intervalo (valor absoluto) | Especificador de Formato |
|---|---|---|---|---|
float |
4 | 6-7 | 1.2e-38 ~ 3.4e38 | %f |
double |
8 | 15-16 | 2.2e-308 ~ 1.8e308 | %lf |
long double |
8 ou mais | 18+ | Depende da plataforma | %Lf |
Números de ponto flutuante têm precisão limitada e não podem representar todos os decimais exatamente. Por exemplo:
float f = 0.1f;
printf("%.20f\n", f);
0.10000000149011611938
0.1 é uma fração binária infinitamente repetitiva, então float não consegue armazená-la com precisão. Essa é uma característica inerente da representação de ponto flutuante, não um bug.
double por padrão quando precisar de números decimais. Oferece maior precisão e não é mais lento que float em CPUs modernas. Só prefira float em sistemas embarcados com restrição de memória.
O Tipo Caractere
O tipo char é essencialmente um inteiro de 1 byte, tipicamente usado para armazenar caracteres. Caracteres são armazenados na memória como códigos ASCII:
char ch = 'A';
printf("%c\n", ch);
printf("%d\n", ch);
A
65
O código ASCII para 'A' é 65. Usando %c imprime o caractere, enquanto %d imprime o valor inteiro. Isso mostra que caracteres e inteiros são intercambiáveis em C.
'A' é um caractere (aspas simples), enquanto "A" é uma string (aspas duplas, com um \0 no final). São coisas completamente diferentes — nunca confunda.
O Tipo _Bool
C99 introduziu o tipo _Bool, que só pode armazenar 0 e 1. Inclua <stdbool.h> para usar bool, true e false:
#include <stdbool.h>
bool e_valido = true;
bool e_vazio = false;
O Operador sizeof
sizeof é uma palavra-chave de C (não uma função) que retorna o número de bytes que um tipo de dado ou variável ocupa:
Exemplo
#include <stdio.h>
int main(void) {
printf("char: %zu bytes\n", sizeof(char));
printf("short: %zu bytes\n", sizeof(short));
printf("int: %zu bytes\n", sizeof(int));
printf("long: %zu bytes\n", sizeof(long));
printf("long long: %zu bytes\n", sizeof(long long));
printf("float: %zu bytes\n", sizeof(float));
printf("double: %zu bytes\n", sizeof(double));
return 0;
}
char: 1 bytes
short: 2 bytes
int: 4 bytes
long: 4 bytes
long long: 8 bytes
float: 4 bytes
double: 8 bytes
sizeof retorna um tipo size_t, cujo especificador de formato é %zu. Se seu compilador não suporta %zu (algumas versões antigas), você pode usar %lu no lugar.
sizeof também funciona com variáveis:
int idade = 20;
printf("%zu\n", sizeof(idade));
Saída Formatada em Detalhes
Formatação de Inteiros
int n = 42;
printf("Decimal: %d\n", n);
printf("Octal: %o\n", n);
printf("Hex (minúsculas): %x\n", n);
printf("Hex (maiúsculas): %X\n", n);
printf("Octal com prefixo: %#o\n", n);
printf("Hex com prefixo: %#x\n", n);
Decimal: 42
Octal: 52
Hex (minúsculas): 2a
Hex (maiúsculas): 2A
Octal com prefixo: 052
Hex com prefixo: 0x2a
Formatação de Ponto Flutuante
double pi = 3.141592653589793;
printf("Padrão: %f\n", pi);
printf("2 casas decimais: %.2f\n", pi);
printf("8 casas decimais: %.8f\n", pi);
printf("Notação científica: %e\n", pi);
printf("Largura 12.2f: [%12.2f]\n", pi);
Padrão: 3.141593
2 casas decimais: 3.14
8 casas decimais: 3.14159265
Notação científica: 3.141593e+00
Largura 12.2f: [ 3.14]
Intervalos de Valores dos Tipos
A biblioteca padrão de C fornece arquivos header para consultar o intervalo de cada tipo:
limits.h (Tipos Inteiros)
#include <limits.h>
printf("int mínimo: %d\n", INT_MIN);
printf("int máximo: %d\n", INT_MAX);
printf("char máximo: %d\n", CHAR_MAX);
Macros comuns:
| Macro | Significado |
|---|---|
INT_MIN |
Valor mínimo de int |
INT_MAX |
Valor máximo de int |
CHAR_MIN |
Valor mínimo de char |
CHAR_MAX |
Valor máximo de char |
LONG_MAX |
Valor máximo de long |
LLONG_MAX |
Valor máximo de long long |
float.h (Tipos de Ponto Flutuante)
#include <float.h>
printf("Dígitos significativos do float: %d\n", FLT_DIG);
printf("Dígitos significativos do double: %d\n", DBL_DIG);
printf("Valor máximo do float: %e\n", FLT_MAX);
Exemplo
Exemplo
#include <stdio.h>
#include <limits.h>
#include <float.h>
int main(void) {
char ch = 'Z';
int num = 100;
float f = 3.14f;
double d = 2.718281828;
printf("char '%c' = ASCII %d, tamanho = %zu\n", ch, ch, sizeof(ch));
printf("int %d, tamanho = %zu, intervalo = [%d, %d]\n", num, sizeof(num), INT_MIN, INT_MAX);
printf("float %.6f, tamanho = %zu, dígitos = %d\n", f, sizeof(f), FLT_DIG);
printf("double %.9f, tamanho = %zu, dígitos = %d\n", d, sizeof(d), DBL_DIG);
return 0;
}
char 'Z' = ASCII 90, tamanho = 1
int 100, tamanho = 4, intervalo = [-2147483648, 2147483647]
float 3.140000, tamanho = 4, dígitos = 6
double 2.718281828, tamanho = 8, dígitos = 15
Exemplo
#include <stdio.h>
int main(void) {
char minuscula = 'a';
char maiuscula = minuscula - 32;
printf("Minúscula: %c (ASCII %d)\n", minuscula, minuscula);
printf("Maiúscula: %c (ASCII %d)\n", maiuscula, maiuscula);
printf("\nCaracteres numéricos:\n");
char digito = '0';
printf("Caractere '%c' código ASCII = %d\n", digito, digito);
printf("Caractere '%c' valor numérico = %d\n", digito, digito - '0');
return 0;
}
Minúscula: a (ASCII 97)
Maiúscula: A (ASCII 65)
Caracteres numéricos:
Caractere '0' código ASCII = 48
Caractere '0' valor numérico = 0
'0' de um caractere numérico dá seu valor numérico — essa é a base para converter caracteres em números.
❓ Perguntas Frequentes
P: Qual a diferença entre int e long long? Quando devo usar long long? R: int tem tipicamente 4 bytes com máximo por volta de 2,1 bilhões; long long tem 8 bytes com máximo por volta de 9,2 quintilhões. Use long long quando o intervalo de int não for suficiente (ex. calcular fatoriais, aritmética com números grandes). Para o dia a dia, int é suficiente — não use long long por padrão, pois desperdiça memória e pode ser mais lento em algumas plataformas.
P: Devo escolher float ou double? R: Use double por padrão. double tem 15-16 dígitos significativos contra 6-7 do float — uma diferença enorme de precisão. Em CPUs modernas, aritmética com double é tão rápida quanto com float. Só prefira float em dispositivos embarcados com restrição de memória.
P: char é com sinal ou sem sinal? R: Depende do compilador e da plataforma. O padrão C não especifica se char é signed — os compiladores decidem. Se você precisa de uma garantia de sinal, use signed char ou unsigned char explicitamente. Para caracteres ASCII (0-127), não importa. Para valores acima de 127, você deve ser explícito.
P: Por que não devo usar variáveis não inicializadas? R: Variáveis locais não inicializadas são armazenadas na pilha e contém qualquer dado aleatório que ficou na memória (valores lixo). Usá-las leva a comportamento indefinido — o programa pode funcionar às vezes e travar outras, com resultados diferentes a cada execução. Esses bugs são extremamente difíceis de rastrear, então sempre inicialize variáveis na declaração.
📖 Resumo
- Variáveis são posições de memória nomeadas; especifique o tipo e nome ao declarar, e sempre inicialize
- Nomes devem começar com letra ou underscore, diferenciam maiúsculas de minúsculas e não podem usar palavras-chave
- Tipos inteiros: char (1 byte), short (2), int (4), long (4 ou 8), long long (8)
- Tipos de ponto flutuante: float (4 bytes, 6-7 dígitos de precisão), double (8 bytes, 15-16 dígitos de precisão)
- sizeof retorna o tamanho em bytes de um tipo ou variável; limits.h e float.h fornecem intervalos de valores
📝 Exercícios
- Escreva um programa que use sizeof para imprimir os tamanhos em bytes de todos os tipos inteiros e de ponto flutuante no seu computador. Compare com os resultados de um colega para ver se coincidem.
- Escreva um programa que imprima os códigos ASCII das letras de 'a' a 'z', cinco por linha, usando %-5d para alinhamento.
- Calcule e imprima o resultado de INT_MAX + 1 (overflow de inteiro). Compare a saída com INT_MIN e pense por que isso acontece.



