Structs aninhadas e arrays de structs
Esta aula aborda structs aninhadas, arrays de structs, sua inicialização e casos de uso práticos em C. O aluno aprenderá a compor estruturas de dados complexas e a manipulá-las com exemplos de código.
Em C, structs permitem agrupar dados heterogêneos sob um mesmo tipo. Quando uma struct contém outra struct como membro, temos um aninhamento. Além disso, podemos criar arrays de structs para armazenar coleções de registros. Nesta aula, exploraremos como declarar, inicializar e utilizar essas construções, que são fundamentais para representar dados do mundo real.
Dominar structs aninhadas e arrays de structs é essencial para modelar entidades complexas (como um funcionário com endereço, ou uma turma de alunos) e para organizar dados de forma eficiente. Veremos exemplos práticos e boas práticas de uso.
Aninhamento
Uma struct pode ter como membro outra struct. Isso é chamado de aninhamento e permite criar hierarquias de dados. Por exemplo, uma struct Pessoa pode conter uma struct Endereco.
Para acessar um membro de uma struct aninhada, usamos o operador ponto (.) de forma encadeada: variavel.membro_struct.membro_interno.
Exemplo:
#include <stdio.h>
struct Endereco {
char rua[100];
int numero;
char cidade[50];
};
struct Pessoa {
char nome[50];
int idade;
struct Endereco endereco;
};
int main() {
struct Pessoa p1;
// Atribuindo valores
sprintf(p1.nome, "Maria");
p1.idade = 30;
sprintf(p1.endereco.rua, "Rua das Flores");
p1.endereco.numero = 123;
sprintf(p1.endereco.cidade, "São Paulo");
printf("%s mora em %s, %d\n", p1.nome, p1.endereco.cidade, p1.endereco.numero);
return 0;
}
Note que p1.endereco é uma struct do tipo Endereco, e seus membros são acessados com um ponto adicional.
Arrays de structs
Assim como qualquer outro tipo, podemos criar arrays de structs. Isso é útil para armazenar múltiplos registros, como uma lista de alunos, produtos ou funcionários.
Declaração: struct Pessoa turma[30]; cria um array de 30 structs Pessoa.
Para acessar um elemento do array, usamos índice: turma[0], turma[1], etc. E para acessar um membro de um elemento: turma[i].nome.
Exemplo:
#include <stdio.h>
struct Aluno {
char nome[50];
float nota;
};
int main() {
struct Aluno turma[3];
// Preenchendo o array
for(int i = 0; i < 3; i++) {
printf("Digite nome e nota do aluno %d: ", i+1);
scanf("%s %f", turma[i].nome, &turma[i].nota);
}
// Exibindo
printf("\nAlunos cadastrados:\n");
for(int i = 0; i < 3; i++) {
printf("%s: %.2f\n", turma[i].nome, turma[i].nota);
}
return 0;
}
Arrays de structs são frequentemente usados com laços para processamento em lote.
Inicialização
Structs e arrays de structs podem ser inicializados no momento da declaração usando chaves {}. A ordem dos valores deve corresponder à ordem dos membros na definição da struct.
Para structs aninhadas, usamos chaves aninhadas. Exemplo:
#include <stdio.h>
struct Endereco {
char rua[100];
int numero;
};
struct Pessoa {
char nome[50];
int idade;
struct Endereco endereco;
};
int main() {
// Inicialização de struct aninhada
struct Pessoa p = {"João", 25, {"Av. Brasil", 500}};
printf("%s, %d anos, %s %d\n", p.nome, p.idade, p.endereco.rua, p.endereco.numero);
// Inicialização de array de structs
struct Pessoa turma[2] = {
{"Ana", 20, {"Rua A", 10}},
{"Pedro", 22, {"Rua B", 20}}
};
for(int i = 0; i < 2; i++) {
printf("%s: %s %d\n", turma[i].nome, turma[i].endereco.rua, turma[i].endereco.numero);
}
return 0;
}
Também é possível usar inicialização designada (C99 em diante) para maior clareza, mas a forma posicional é mais comum.
Para arrays, se fornecemos menos valores que o tamanho, os elementos restantes são inicializados com zero (ou valores padrão).
Casos de uso
Structs aninhadas e arrays de structs são amplamente usados em programação para modelar dados do mundo real. Exemplos:
- Cadastro de funcionários: cada funcionário tem dados pessoais (nome, CPF) e um endereço (rua, cidade). Um array de funcionários representa a equipe.
- Jogos: um jogo pode ter um array de inimigos, cada um com posição (x,y) e vida. A posição pode ser uma struct aninhada.
- Sistemas acadêmicos: uma turma contém vários alunos; cada aluno tem nome, matrícula e notas (array de floats).
- Gráficos: um polígono pode ser representado por um array de pontos (struct com x,y).
Essas estruturas permitem organizar dados de forma lógica e facilitam a manutenção do código.
Boas práticas
- Use nomes claros para structs e membros.
- Evite aninhamentos muito profundos (mais de 2 níveis) para não prejudicar a legibilidade.
- Considere usar
typedefpara simplificar a declaração de structs. - Inicialize sempre as structs para evitar valores lixo.
Referências
- cppreference: Struct declaration
- Learn-C.org: Structures
- TutorialsPoint: C Structures
- Programiz: C Structures
- GeeksforGeeks: Structures in C
Exercícios
Crie uma struct
Pontocom membrosxey(float). Em seguida, crie uma structRetanguloque contenha dois pontos:inferior_esquerdoesuperior_direito. Declare e inicialize um retângulo com valores de sua escolha. Depois, calcule e imprima a área.✓ Resposta:#include <stdio.h> struct Ponto { float x, y; }; struct Retangulo { struct Ponto inf_esq; struct Ponto sup_dir; }; int main() { struct Retangulo r = {{1.0, 2.0}, {5.0, 6.0}}; float largura = r.sup_dir.x - r.inf_esq.x; float altura = r.sup_dir.y - r.inf_esq.y; float area = largura * altura; printf("Área: %.2f\n", area); return 0; }Declare um array de 5 structs
Aluno(com nome e nota). Preencha os dados via teclado (usescanf). Ao final, exiba o nome do aluno com maior nota.✓ Resposta:#include <stdio.h> #include <string.h> struct Aluno { char nome[50]; float nota; }; int main() { struct Aluno turma[5]; int i; for(i = 0; i < 5; i++) { printf("Nome e nota do aluno %d: ", i+1); scanf("%s %f", turma[i].nome, &turma[i].nota); } int maior_idx = 0; for(i = 1; i < 5; i++) { if(turma[i].nota > turma[maior_idx].nota) maior_idx = i; } printf("Maior nota: %s (%.2f)\n", turma[maior_idx].nome, turma[maior_idx].nota); return 0; }Usando a struct
Pontodo exercício 1, crie um array de 3 pontos e inicialize-o com coordenadas fixas. Em seguida, calcule a distância entre o primeiro e o último ponto. (Fórmula: sqrt((x2-x1)^2 + (y2-y1)^2); usemath.hesqrt).✓ Resposta:#include <stdio.h> #include <math.h> struct Ponto { float x, y; }; int main() { struct Ponto pontos[3] = {{0,0}, {3,4}, {6,8}}; float dx = pontos[2].x - pontos[0].x; float dy = pontos[2].y - pontos[0].y; float dist = sqrt(dx*dx + dy*dy); printf("Distância: %.2f\n", dist); return 0; }Crie uma struct
Datacom dia, mês e ano (int). Depois, uma structEventocom nome (string) e data (struct Data). Declare um array de 2 eventos inicializados. Imprima os eventos no formato "nome: dd/mm/aaaa".✓ Resposta:#include <stdio.h> struct Data { int dia, mes, ano; }; struct Evento { char nome[100]; struct Data data; }; int main() { struct Evento eventos[2] = { {"Aniversário", {15, 10, 2023}}, {"Reunião", {20, 11, 2023}} }; for(int i = 0; i < 2; i++) { printf("%s: %02d/%02d/%04d\n", eventos[i].nome, eventos[i].data.dia, eventos[i].data.mes, eventos[i].data.ano); } return 0; }Escreva uma função que receba um array de structs
Produto(com nome, preço e quantidade) e seu tamanho, e retorne o valor total em estoque (soma de preço * quantidade para cada produto). Teste com um array inicializado de 3 produtos.✓ Resposta:#include <stdio.h> struct Produto { char nome[50]; float preco; int quantidade; }; float valor_total(struct Produto prod[], int n) { float total = 0; for(int i = 0; i < n; i++) { total += prod[i].preco * prod[i].quantidade; } return total; } int main() { struct Produto estoque[3] = { {"Arroz", 5.50, 10}, {"Feijão", 8.00, 5}, {"Óleo", 7.20, 3} }; printf("Valor total: R$ %.2f\n", valor_total(estoque, 3)); return 0; }