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:

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

C
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:

C
int idade = 20;
float peso = 65.5f;
char tipo_sanguineo = 'A';
💡 Dica: Sempre inicialize variáveis ao declará-las. Esse é um bom hábito que te ajuda a evitar muitos bugs difíceis de rastrear causados por valores indefinidos.

Declarar Primeiro, Atribuir Depois

Você também pode declarar primeiro e atribuir depois:

C
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

C
int a = 1, b = 2, c = 3;
⚠️ Atenção: Declarar e inicializar múltiplas variáveis na mesma linha prejudica a legibilidade. Se cada variável tem um valor inicial significativo, escreva-as em linhas separadas.

Regras de Nomenclatura de Variáveis

C tem regras estritas para nomes de variáveis:

Deve seguir:

Deveria seguir:

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
💡 Dica: Para a programação do dia a dia, 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.

⚠️ Atenção: A tabela acima mostra 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:

C
float f = 0.1f;
printf("%.20f\n", f);
TEXT
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.

🔥 Erro Comum: Use 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:

C
char ch = 'A';
printf("%c\n", ch);
printf("%d\n", ch);
TEXT
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.

⚠️ Atenção: '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:

C
#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

C
#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;
}
▶ Experimente
TEXT
char:   1 bytes
short:  2 bytes
int:    4 bytes
long:   4 bytes
long long: 8 bytes
float:  4 bytes
double: 8 bytes
💡 Dica: 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:

C
int idade = 20;
printf("%zu\n", sizeof(idade));

Saída Formatada em Detalhes

Formatação de Inteiros

C
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);
TEXT
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

C
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);
TEXT
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)

C
#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)

C
#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

C
#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;
}
▶ Experimente
TEXT
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

C
#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;
}
▶ Experimente
TEXT
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
💡 Dica: Códigos ASCII maiúsculos e minúsculos diferem em 32. Subtraia 32 de uma letra minúscula para obter a maiúscula equivalente, e adicione 32 para o caminho inverso. Subtrair '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

📝 Exercícios

  1. 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.
  2. Escreva um programa que imprima os códigos ASCII das letras de 'a' a 'z', cinco por linha, usando %-5d para alinhamento.
  3. 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.
100%