Structs aninhadas e arrays de structs
Nesta aula, exploramos structs aninhadas (structs dentro de structs) e arrays de structs em C. Aprendemos a declarar, inicializar e acessar esses tipos de dados compostos, além de discutir casos de uso comuns. Por meio de exemplos práticos e exercícios, consolidamos o entendimento de como organizar dados hierárquicos e coleções de registros.
Structs em C permitem agrupar variáveis de tipos diferentes sob um mesmo nome. Quando uma struct contém outra struct como membro, chamamos de struct aninhada. Já os arrays de structs nos permitem armazenar uma coleção de registros do mesmo tipo. Esses conceitos são fundamentais para modelar dados complexos, como cadastros de pessoas, registros acadêmicos ou sistemas de estoque.
Nesta aula, vamos aprender a declarar, inicializar e acessar structs aninhadas e arrays de structs, com exemplos práticos e boas práticas de uso.
Aninhamento
Aninhamento de structs ocorre quando uma struct é declarada como membro de outra struct. Isso permite representar relações hierárquicas de forma natural. Por exemplo, uma struct Pessoa pode ter um membro do tipo Endereco, que por sua vez contém campos como rua, número e cidade.
Para acessar um campo de uma struct aninhada, usamos o operador ponto (.) de forma encadeada: variavel.membro_struct.campo. Se usarmos ponteiros, utilizamos -> para o ponteiro externo e ponto para o campo interno. Veja o exemplo:
#include <stdio.h>
#include <string.h>
struct Endereco {
char rua[50];
int numero;
char cidade[30];
};
struct Pessoa {
char nome[50];
int idade;
struct Endereco endereco;
};
int main() {
struct Pessoa p1;
strcpy(p1.nome, "Maria");
p1.idade = 30;
strcpy(p1.endereco.rua, "Rua das Flores");
p1.endereco.numero = 123;
strcpy(p1.endereco.cidade, "São Paulo");
printf("%s mora na %s, %d - %s\n", p1.nome, p1.endereco.rua, p1.endereco.numero, p1.endereco.cidade);
return 0;
}
Note que a struct Endereco é declarada antes de ser usada em Pessoa. A ordem de declaração é importante: a struct interna deve ser conhecida antes da externa.
Arrays de structs
Um array de structs é um vetor cujos elementos são do tipo struct. Isso é útil para armazenar múltiplos registros do mesmo tipo, como uma lista de alunos ou produtos. A declaração segue a sintaxe: struct NomeDaStruct nome_array[tamanho];.
Para acessar um campo de um elemento do array, usamos nome_array[indice].campo. Exemplo com um array de Pessoa:
#include <stdio.h>
#include <string.h>
struct Pessoa {
char nome[50];
int idade;
};
int main() {
struct Pessoa pessoas[3];
strcpy(pessoas[0].nome, "Ana");
pessoas[0].idade = 25;
strcpy(pessoas[1].nome, "João");
pessoas[1].idade = 32;
strcpy(pessoas[2].nome, "Pedro");
pessoas[2].idade = 28;
for (int i = 0; i < 3; i++) {
printf("%s tem %d anos\n", pessoas[i].nome, pessoas[i].idade);
}
return 0;
}
Arrays de structs podem ser combinados com aninhamento: cada elemento pode conter uma struct aninhada. Por exemplo, um array de Pessoa com endereço.
Inicialização
Structs aninhadas e arrays de structs podem ser inicializados na declaração usando chaves aninhadas. A ordem dos valores deve corresponder à ordem dos campos na declaração. Para arrays, usamos uma lista de inicializadores entre chaves, separados por vírgulas.
Exemplo de inicialização de uma struct aninhada:
struct Endereco end = {"Av. Brasil", 500, "Rio de Janeiro"};
struct Pessoa p = {"Carlos", 40, end};
// ou diretamente:
struct Pessoa p2 = {"Carla", 35, {"Rua X", 10, "Belo Horizonte"}};
Inicialização de array de structs:
struct Pessoa pessoas[2] = {
{"Alice", 22, {"Rua A", 1, "São Paulo"}},
{"Bob", 28, {"Rua B", 2, "Curitiba"}}
};
Se o número de inicializadores for menor que o tamanho do array, os elementos restantes são inicializados com zero (para tipos numéricos) ou string vazia. É possível usar inicializadores designados (C99) para especificar campos específicos, mas isso é menos comum.
Casos de uso
Structs aninhadas e arrays de structs são amplamente utilizados em programas que precisam representar dados do mundo real. Exemplos comuns:
- Cadastro de clientes: cada cliente tem nome, telefone, e um endereço (aninhado). Um array armazena todos os clientes.
- Registros acadêmicos: um aluno tem dados pessoais e uma lista de disciplinas cursadas (array de struct de disciplina).
- Sistemas de estoque: cada produto tem código, descrição, preço e quantidade. Um array de produtos facilita a gestão.
- Jogos: uma struct
Jogadorpode conter posição (x,y) e pontuação. Um array de jogadores representa o time.
Além disso, é comum combinar arrays de structs com funções para manipular dados. Por exemplo, uma função que imprime todos os elementos de um array de structs, ou que busca um registro por algum campo.
Boas práticas: sempre defina structs com nomes claros e evite aninhamentos muito profundos (mais de 2 ou 3 níveis) para manter a legibilidade. Use typedef para simplificar a declaração de structs, especialmente quando usadas em arrays.
Referências
- cppreference.com: Struct declaration
- learn-c.org: Structures
- GeeksforGeeks: Structures in C
- Wikipedia: Struct (C)
- Tutorialspoint: C Structures
- Programiz: C Structures
Exercícios
Crie uma struct
Datacom dia, mes e ano (inteiros). Depois, crie uma structEventoque contenha um nome (string de até 50 caracteres) e umaData. Declare e inicialize uma variável do tipoEventocom valores de sua escolha, e imprima o nome e a data no formato dd/mm/aaaa.✓ Resposta:#include <stdio.h> #include <string.h> struct Data { int dia; int mes; int ano; }; struct Evento { char nome[50]; struct Data data; }; int main() { struct Evento ev = {"Aniversário", {15, 10, 2025}}; printf("%s: %02d/%02d/%04d\n", ev.nome, ev.data.dia, ev.data.mes, ev.data.ano); return 0; }Declare um array de 5 structs
Pessoa(com nome e idade). Inicialize os dois primeiros elementos com valores e deixe os demais com zero. Em seguida, imprima todos os elementos do array (nomes e idades).✓ Resposta:#include <stdio.h> #include <string.h> struct Pessoa { char nome[50]; int idade; }; int main() { struct Pessoa pessoas[5] = { {"Ana", 25}, {"João", 30} }; for (int i = 0; i < 5; i++) { printf("%s, %d\n", pessoas[i].nome, pessoas[i].idade); } return 0; }Utilizando a struct
Pessoado exercício anterior, crie uma função que receba um array dePessoae seu tamanho, e imprima apenas as pessoas com idade maior ou igual a 18. Teste com um array de 3 pessoas.✓ Resposta:#include <stdio.h> #include <string.h> struct Pessoa { char nome[50]; int idade; }; void maiores(struct Pessoa p[], int n) { for (int i = 0; i < n; i++) { if (p[i].idade >= 18) printf("%s (%d)\n", p[i].nome, p[i].idade); } } int main() { struct Pessoa pessoas[3] = { {"Lucas", 17}, {"Maria", 22}, {"Pedro", 19} }; maiores(pessoas, 3); return 0; }Defina uma struct
Pontocom coordenadas x e y (float). Em seguida, defina uma structRetanguloque contenha dois pontos:inferior_esquerdoesuperior_direito. Escreva um programa que calcule e imprima a área do retângulo (largura * altura).✓ Resposta:#include <stdio.h> struct Ponto { float x; float y; }; struct Retangulo { struct Ponto inferior_esquerdo; struct Ponto superior_direito; }; int main() { struct Retangulo r = {{0.0, 0.0}, {4.0, 3.0}}; float largura = r.superior_direito.x - r.inferior_esquerdo.x; float altura = r.superior_direito.y - r.inferior_esquerdo.y; float area = largura * altura; printf("Área: %.2f\n", area); return 0; }Crie um array de structs
Alunocom camposnome(string 50) enotas(array de 3 floats). Inicialize um array de 2 alunos com notas. Para cada aluno, calcule e imprima a média das notas.✓ Resposta:#include <stdio.h> #include <string.h> struct Aluno { char nome[50]; float notas[3]; }; int main() { struct Aluno turma[2] = { {"Carlos", {7.5, 8.0, 9.2}}, {"Fernanda", {6.8, 7.3, 8.5}} }; for (int i = 0; i < 2; i++) { float soma = 0; for (int j = 0; j < 3; j++) { soma += turma[i].notas[j]; } printf("%s: média %.2f\n", turma[i].nome, soma / 3); } return 0; }