💡 Dica: Regra prática — use -> com ponteiros e . com objetos. Isso cobre 90% dos casos.
O que é uma struct?
Até agora, declaramos variáveis int, double e char uma de cada vez. Mas dados do mundo real geralmente vêm como um conjunto de valores relacionados — por exemplo, o nome, a idade e a altura de uma pessoa.
Uma struct permite agrupar variáveis de diferentes tipos em um único tipo novo.
Sem uma struct...
char name[20]; int age; double height;
Se você adicionar outra pessoa, vai precisar de name1, name2, ... — a quantidade de variáveis explode.
Com uma struct
struct Person { char name[20]; int age; double height; };
Tudo fica empacotado em um único Person.
Definindo e Usando uma struct
Usar uma struct exige dois passos: (1) definir o tipo (o molde), depois (2) declarar uma variável (uma instância).
// (1) Define o tipo da struct (o molde)
struct Student {
char name[20];
int score;
};
// (2) Declare variáveis e use
struct Student s1;
strcpy(s1.name, "Tanaka"); // acesso com ponto (.)
s1.score = 85;
// Você também pode inicializar na declaração
struct Student s2 = {"Sato", 92};
Acesse membros com o operador ponto (.):s1.score significa "o campo score dentro de s1."
Layout de Memória da Struct
Os membros de uma struct são organizados na memória consecutivamente, na ordem de declaração.
Layout de memória de struct Student s1;
name[20] ocupa 20 bytes e score ocupa 4 bytes, então um Student usa no mínimo 24 bytes (o padding pode aumentar mais).
🧱 Visualização de Padding — a ordem dos membros afeta o tamanho
Para um acesso eficiente à memória, int precisa de alinhamento em 4 bytes e double em 8 bytes (alinhamento). O compilador insere padding entre os membros automaticamente. Só reordenar os membros pode reduzir o tamanho de uma struct.
🧪 Escolha um padrão
Escolha um padrão
// Nenhum padrão selecionado
Composição do tamanho
Dados reais: - B
Padding: - B
sizeof total: - B
※ Valores típicos em x86_64 Linux com gcc. Os resultados variam conforme a plataforma.
Layout em nível de byte (1 célula = 1 byte)
💡 Dica profissional: Para economizar memória (sistemas embarcados, grandes conjuntos de dados), declare os membros do maior para o menor (double → int → short → char). Para objetivos de localidade de cache, valem outras estratégias.
Arrays de Structs
Um array de structs permite gerenciar muitos registros que compartilham o mesmo formato. É aqui que as structs realmente brilham.
// Imprime a nota de cada aluno
for(int i = 0; i < 3; i++){
printf("%s: %d pontos\n", class[i].name, class[i].score);
}
Combine o índice do array com o operador ponto, como em class[i].score. Lê-se naturalmente como "a nota do i-ésimo aluno."
Passando uma struct para uma Função
Structs podem ser passadas por valor (copiadas), mas copiar é caro para structs grandes, então passar um ponteiro é comum.
// Passagem por valor (a struct é copiada)
void printStudent(struct Student s){
printf("%s: %d pontos\n", s.name, s.score);
}
// Passagem por ponteiro (refere-se ao original)
void addBonus(struct Student *sp, int bonus){
sp->score += bonus; // equivalente a (*sp).score
}
addBonus(&s1, 5); // soma 5 pontos em s1.score
O operador de seta (->) é uma abreviação para acessar membros através de um ponteiro. sp->score é o mesmo que (*sp).score.
typedef — Dando um Apelido a um Tipo
typedef permite dar a um tipo um apelido mais claro. É especialmente útil com structs.
Uso básico
// Um apelido para unsigned inttypedefunsigned int uint;
uint score = 100; // igual a unsigned int score = 100;
Structs e typedef (importante)
// Sem typedef — você precisa de "struct" toda vezstructPoint { int x, y; };
structPoint p1 = {3, 7}; // "struct" obrigatório// Com typedef — você pode omitir "struct"typedefstruct { int x, y; } Point;
Point p1 = {3, 7}; // mais limpo
Na prática, structs com typedef são o padrão. O código fica mais curto e mais fácil de ler.
Enum (enum) — Um Grupo de Constantes Nomeadas
enum permite nomear e agrupar constantes inteiras relacionadas — ótimo para evitar números mágicos.
enumColor { RED, GREEN, BLUE }; // RED=0, GREEN=1, BLUE=2enumColor c = GREEN;
printf("%d\n", c); // 1
Especificando valores
enumMonth {
JAN = 1, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC
}; // FEB=2, MAR=3, ... DEC=12 (autoincrementado)
enum + switch
enumDirection { UP, DOWN, LEFT, RIGHT };
enumDirection dir = UP;
switch (dir) {
case UP: printf("Up\n"); break;
case DOWN: printf("Down\n"); break;
case LEFT: printf("Left\n"); break;
case RIGHT: printf("Right\n"); break;
}
vs #define: Você poderia escrever #define RED 0 no lugar, mas um enum é tratado como um tipo, então o compilador pode ajudar com a verificação de tipos.
Método
Verificação de tipo
Escopo
Exibição no depurador
#define RED 0
Nenhuma
Arquivo inteiro
Apenas número
enum { RED }
Sim
Controlável
Mostrado pelo nome
Experimente Você Mesmo — Structs
Guarde três alunos em um array de structs e calcule a média das notas.
struct.c
Saída
Clique em Executar...
💡 Mais ideias para testar
Crie um array de structs para guardar vários alunos
Passe um ponteiro de struct para uma função e modifique seus membros
Aninhe um Point dentro de um Rect
Use typedef para criar um apelido Point para o tipo