C Structs
Até aqui, cada informação morava numa variável separada: nome, idade, nota. Para uma aluna, funciona. Para uma turma inteira, vira uma bagunça de variáveis soltas e de arrays paralelos que precisam andar sempre na mesma ordem. Uma struct junta várias informações que andam juntas num tipo novo, criado por você: o tipo struct Aluno, que tem nome, idade e nota. Nesta aula você vai declarar a sua primeira struct, preencher, guardar várias num array, copiar e mostrar na tela.
- O que é uma struct e como declarar uma:
struct Aluno { … };. - Como criar uma variável do tipo
struct Alunoe acessar os campos com o ponto:a.nota. - Por que um campo sem valor guarda lixo, e como zerar tudo com
{0}ou{}(C23). - Como preencher com chaves, pela ordem ou pelo nome do campo (
.nome = …, C99). - Como guardar uma turma inteira num array de structs.
- Como copiar uma struct com
=, e por que==não compara structs. - Como colocar uma struct dentro de outra e como mostrar os campos com
printf.
Todos os programas desta aula foram compilados com o gcc 15.2 na máquina fictícia da Ana (usuária ana, computador notebook), na pasta ~/c, com o comando padrão do guia: gcc -std=c23 -Wall -Wextra arquivo.c -o programa (veja Compilar com gcc). Você pode repetir cada um no editor do guia.
A ideia: uma ficha de cadastro
Pense na secretaria de uma escola. Para cada aluno existe uma ficha de papel, sempre com os mesmos espaços: Nome, Idade, Nota. A ficha em branco é o modelo; cada ficha preenchida é um aluno de verdade.
A struct é o modelo da ficha. Ela diz quais espaços existem e o tipo de cada um. Depois você cria quantas fichas preenchidas quiser, todas no mesmo formato.
| Na secretaria | Em C | Exemplo |
|---|---|---|
| O modelo da ficha | a struct (um tipo novo) | struct Aluno { … }; |
| Cada espaço da ficha | um campo (ou membro) | int idade; |
| Uma ficha preenchida | uma variável do tipo struct Aluno | struct Aluno a; |
| Ler o espaço "Idade" de uma ficha | o operador ponto | a.idade |
O nome vem do inglês structure, "estrutura": uma estrutura de dados montada com peças menores. Em C, uma struct guarda só dados: não tem funções dentro, nem construtores, nem partes "privadas", como as classes de outras linguagens. As funções que trabalham com ela ficam do lado de fora, como sempre.
1. Declarar a struct e criar uma variável
#include <stdio.h>
#include <string.h>
struct Aluno {
char nome[50];
int idade;
double nota;
};
int main(void) {
struct Aluno a;
strcpy(a.nome, "Ana");
a.idade = 20;
a.nota = 8.5;
printf("%s tem %d anos e tirou %.1f\n", a.nome, a.idade, a.nota);
a.nota = 9.0;
printf("Nota corrigida: %.1f\n", a.nota);
return 0;
}
- struct Aluno
- Começa a declaração de um tipo novo.
Alunoé a etiqueta (tag) da struct. Por costume, começa com maiúscula, para não confundir com variáveis. - { … };
- Entre as chaves ficam os campos. Repare no ponto e vírgula depois da chave: na struct ele é obrigatório (esquecer é um erro clássico, que você verá em "Quando dá errado").
- char nome[50];
- Um campo: tipo + nome, igual a declarar uma variável. Este é um array de 50
char: o nome fica guardado dentro da ficha (até 49 letras mais o'\0'). - int idade; double nota;
- Os campos podem ter tipos diferentes entre si. Essa é a grande diferença para um array, em que todos os elementos têm o mesmo tipo.
- struct Aluno a;
- Cria uma variável
ado tipostruct Aluno. Em C, o nome do tipo são as duas palavras:struct Aluno. Escrever sóAluno a;é erro (dá para encurtar com typedef, na próxima aula, mas uma coisa de cada vez). - strcpy(a.nome, "Ana");
- O ponto entra na ficha
ae pega o camponome. Comonomeé um array dechar, o texto entra comstrcpy(ousnprintf), não com=(veja Funções de String). - a.idade = 20;
- Campos numéricos se comportam como variáveis comuns: dá para guardar, ler e mudar com
=.
$ gcc -std=c23 -Wall -Wextra aluno.c -o aluno $ ./aluno Ana tem 20 anos e tirou 8.5 Nota corrigida: 9.0
Declare a struct fora do main, lá em cima, depois dos #include. Assim todas as funções do arquivo conhecem o tipo struct Aluno. Em projetos maiores, ela vai para um arquivo .h (veja Arquivos .h e .c).
2. Campos sem valor: lixo da memória
O que tem em a.idade se você nunca guardou nada lá? Uma variável local sem valor inicial não vale zero: vale o que estava naquele pedaço da memória antes (veja Variáveis). Com os campos de uma struct é igual:
#include <stdio.h>
#include <string.h>
struct Aluno {
char nome[50];
int idade;
double nota;
};
int main(void) {
struct Aluno a;
strcpy(a.nome, "Ana");
printf("%s, %d anos, nota %g\n", a.nome, a.idade, a.nota);
return 0;
}
$ gcc -std=c23 -Wall -Wextra lixo.c -o lixo
lixo.c: In function ‘main’:
lixo.c:13:5: warning: ‘a.nota’ is used uninitialized [-Wuninitialized]
13 | printf("%s, %d anos, nota %g\n", a.nome, a.idade, a.nota);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lixo.c:11:18: note: ‘a’ declared here
11 | struct Aluno a;
| ^
lixo.c:13:5: warning: ‘a.idade’ is used uninitialized [-Wuninitialized]
13 | printf("%s, %d anos, nota %g\n", a.nome, a.idade, a.nota);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lixo.c:11:18: note: ‘a’ declared here
11 | struct Aluno a;
| ^
$ ./lixo
Ana, 0 anos, nota 0 « zero desta vez, por sorte
O gcc avisou duas vezes: ‘a.nota’ is used uninitialized = "a.nota é usado sem ter recebido valor". Nesta execução saiu zero, mas é sorte: o C não promete nada, e em outro programa (ou com outra opção de compilação) sai um número sem sentido. Ler um valor que nunca foi guardado é comportamento indefinido.
A solução: começar zerado
Diferente do C++, uma struct em C não pode ter valores padrão escritos dentro dela. O jeito é zerar na hora de criar a variável, com chaves:
struct Aluno a = {0}; /* todos os campos zerados (qualquer versão do C) */
struct Aluno b = {}; /* o mesmo, a partir do C23 */
Com {0}, o primeiro campo recebe 0 e todos os que você não citou também viram zero: os números ficam 0 e o nome fica com todos os bytes '\0' (um texto vazio). As chaves vazias {} fazem o mesmo e são oficiais a partir do C23; antes disso, use {0}, que funciona em todas as versões. Crie suas structs sempre zeradas quando for preenchê-las aos poucos.
Missão: a variável a já existe, zerada. Preencha os três campos com o ponto (o nome com strcpy), para a tela mostrar Bia tem 19 anos e nota 7.5. Rode primeiro sem mudar nada e veja os zeros.
#include <stdio.h>
#include <string.h>
struct Aluno {
char nome[50];
int idade;
double nota;
};
int main(void) {
struct Aluno a = {0};
/* preencha os três campos de a aqui */
printf("%s tem %d anos e nota %.1f\n", a.nome, a.idade, a.nota);
return 0;
}
#include <stdio.h>
#include <string.h>
struct Aluno {
char nome[50];
int idade;
double nota;
};
int main(void) {
struct Aluno a = {0};
strcpy(a.nome, "Bia");
a.idade = 19;
a.nota = 7.5;
printf("%s tem %d anos e nota %.1f\n", a.nome, a.idade, a.nota);
return 0;
}
3. Preencher tudo de uma vez com chaves
Preencher campo por campo dá trabalho. Você pode criar a variável já preenchida, com os valores entre chaves. Pela ordem dos campos, ou citando o nome de cada campo com um ponto na frente (os designadores, do C99):
#include <stdio.h>
struct Aluno {
char nome[50];
int idade;
double nota;
};
int main(void) {
struct Aluno a = {"Ana", 20, 8.5};
struct Aluno b = {"Bruno", 19};
struct Aluno c = {0};
struct Aluno d = {};
struct Aluno e = {.nome = "Carla", .idade = 22, .nota = 9.5};
struct Aluno f = {.nota = 6.0, .nome = "Davi"};
printf("%s | %d | %.1f\n", a.nome, a.idade, a.nota);
printf("%s | %d | %.1f\n", b.nome, b.idade, b.nota);
printf("[%s] | %d | %.1f\n", c.nome, c.idade, c.nota);
printf("[%s] | %d | %.1f\n", d.nome, d.idade, d.nota);
printf("%s | %d | %.1f\n", e.nome, e.idade, e.nota);
printf("%s | %d | %.1f\n", f.nome, f.idade, f.nota);
return 0;
}
$ gcc -std=c23 -Wall -Wextra chaves.c -o chaves
chaves.c: In function ‘main’:
chaves.c:11:12: warning: missing initializer for field ‘nota’ of ‘struct Aluno’ [-Wmissing-field-initializers]
11 | struct Aluno b = {"Bruno", 19};
| ^~~~~
chaves.c:6:12: note: ‘nota’ declared here
6 | double nota;
| ^~~~
$ ./chaves
Ana | 20 | 8.5
Bruno | 19 | 0.0 « faltou a nota: ficou zero
[] | 0 | 0.0 « {0}: tudo zerado, nome vazio
[] | 0 | 0.0 « {}: o mesmo (C23)
Carla | 22 | 9.5
Davi | 0 | 6.0 « designadores fora de ordem, idade pulada: zero
| Linha | O que faz |
|---|---|
{"Ana", 20, 8.5} | Preenche pela ordem: nome, idade, nota. O texto entre aspas pode ir direto para o array nome aqui, na criação (depois, só com strcpy). |
{"Bruno", 19} | Valores a menos: os campos do fim viram zero. O -Wextra avisa (missing initializer for field ‘nota’, "faltou valor inicial para o campo nota"), porque pode ter sido esquecimento. |
{0} e {} | Tudo zerado. Esses dois não geram aviso: o compilador entende que zerar era a intenção. |
{.nome = "Carla", .idade = 22, .nota = 9.5} | Designadores C99: cada valor vem com o nome do campo. Mais fácil de ler, e não depende da ordem dos campos na struct. |
{.nota = 6.0, .nome = "Davi"} | Em C, os designadores podem vir em qualquer ordem e pular campos; os pulados viram zero, sem aviso. (Em C++, a ordem tem de ser a da declaração.) |
Os designadores são ótimos quando a struct tem vários campos do mesmo tipo: em {20, 22} você precisa lembrar qual número é qual; em {.idade = 20, .sala = 22}, não. E se alguém um dia mudar a ordem dos campos na struct, a forma com designadores continua certa.
4. Uma turma inteira: array de structs
Aqui a struct mostra a sua força. Um array de struct Aluno é uma pilha de fichas (veja Arrays). Cada elemento é uma ficha completa:
#include <stdio.h>
struct Aluno {
char nome[50];
int idade;
double nota;
};
int main(void) {
struct Aluno turma[] = {
{"Ana", 20, 8.5},
{"Bruno", 19, 6.0},
{"Carla", 22, 9.5},
{"Davi", 21, 7.0},
};
size_t n = sizeof turma / sizeof turma[0];
double soma = 0.0;
for (size_t i = 0; i < n; i++) {
printf("%-6s %4.1f\n", turma[i].nome, turma[i].nota);
soma += turma[i].nota;
}
printf("Alunos: %zu\n", n);
printf("Média da turma: %.2f\n", soma / n);
printf("Primeiro: %s\n", turma[0].nome);
return 0;
}
- struct Aluno turma[] = { … };
- Um array de alunos. Cada
{"Ana", 20, 8.5}lá dentro preenche uma ficha, pelas regras da seção 3. Sem número entre os colchetes, o tamanho vem da lista (4). A vírgula depois do último é permitida e facilita acrescentar linhas. - sizeof turma / sizeof turma[0]
- O tamanho do array inteiro dividido pelo tamanho de uma ficha = quantas fichas (veja sizeof).
- turma[i].nota
- Primeiro o
[i]pega a ficha da posiçãoi; depois o.notapega o campo dela. - %-6s %4.1f
- Nome alinhado à esquerda em 6 espaços e nota em 4 espaços com uma casa decimal, para formar colunas (veja Formatos do printf).
$ gcc -std=c23 -Wall -Wextra turma.c -o turma $ ./turma Ana 8.5 Bruno 6.0 Carla 9.5 Davi 7.0 Alunos: 4 Média da turma: 7.75 Primeiro: Ana
Sem struct, você precisaria de três arrays separados (nomes, idades, notas) e de cuidado para que a posição 2 de cada um fosse sempre a mesma pessoa. Com a struct, cada pessoa é uma peça só: ordenar ou apagar um aluno nunca separa o nome da nota.
5. Copiar com = e passar para funções
Ao contrário dos arrays, uma struct pode ser copiada inteira com =. A cópia leva todos os campos, inclusive o array nome, e fica independente da original. Passar uma struct para uma função também faz uma cópia:
#include <stdio.h>
#include <string.h>
struct Aluno {
char nome[50];
int idade;
double nota;
};
void dar_bonus(struct Aluno a) {
a.nota += 1.0;
printf("Dentro da função: %.1f\n", a.nota);
}
int main(void) {
struct Aluno ana = {"Ana", 20, 6.5};
dar_bonus(ana);
printf("No main: %.1f\n", ana.nota);
struct Aluno outra = ana;
strcpy(outra.nome, "Bia");
outra.nota = 10.0;
printf("%s: %.1f | %s: %.1f\n", ana.nome, ana.nota, outra.nome, outra.nota);
return 0;
}
$ gcc -std=c23 -Wall -Wextra copia.c -o copia $ ./copia Dentro da função: 7.5 No main: 6.5 « a função mudou a cópia dela, não a Ana do main Ana: 6.5 | Bia: 10.0 « mudar a outra não muda a ana
Guarde esse comportamento de dar_bonus: para uma função mudar a struct de verdade (e para não copiar 64 bytes a cada chamada), ela recebe um ponteiro para a struct. Esse é o assunto da próxima aula, Structs e Ponteiros (->).
Aqui o nome é um array (char nome[50]), que mora dentro da ficha e é copiado junto. Se o campo fosse um ponteiro (char *nome, apontando para uma string dinâmica), o = copiaria só o endereço: as duas fichas apontariam para o mesmo texto, e mudar um mudaria o outro. Para copiar o texto também, faça outra.nome = strdup(ana.nome);.
Devolver uma struct e struct dentro de struct
Uma função também pode devolver uma struct inteira. E um campo pode ser, ele mesmo, outra struct: a data de nascimento tem dia, mês e ano, e cabe muito bem numa struct Data:
#include <stdio.h>
#include <string.h>
struct Data {
int dia;
int mes;
int ano;
};
struct Aluno {
char nome[50];
struct Data nascimento;
double nota;
};
void mostrar(struct Aluno a) {
printf("%s, nascida em %02d/%02d/%d, nota %.1f\n",
a.nome, a.nascimento.dia, a.nascimento.mes, a.nascimento.ano, a.nota);
}
struct Aluno criar(const char *nome, double nota) {
struct Aluno novo = {0};
snprintf(novo.nome, sizeof novo.nome, "%s", nome);
novo.nota = nota;
return novo;
}
int main(void) {
struct Aluno ana = {"Ana", {14, 3, 2005}, 8.5};
mostrar(ana);
struct Aluno eva = criar("Eva", 7.0);
eva.nascimento = (struct Data){2, 9, 2006};
mostrar(eva);
printf("sizeof(struct Data) = %zu\n", sizeof(struct Data));
return 0;
}
| Linha | O que faz |
|---|---|
struct Data nascimento; | Um campo que é outra struct. A struct Data precisa estar declarada antes. |
a.nascimento.dia | Dois pontos seguidos: entra em a, depois em nascimento, depois pega o dia. |
{"Ana", {14, 3, 2005}, 8.5} | Chaves dentro de chaves: as de dentro preenchem a data. |
snprintf(novo.nome, sizeof novo.nome, "%s", nome); | Copia o nome sem nunca passar dos 50 bytes do campo, mesmo que o texto seja maior (o strcpy não tem essa proteção). |
return novo; | Devolve a struct inteira (uma cópia). Para structs pequenas, é normal e barato. |
(struct Data){2, 9, 2006} | Um literal composto C99: cria uma struct Data sem nome, ali mesmo, para atribuir de uma vez. |
$ gcc -std=c23 -Wall -Wextra funcoes.c -o funcoes $ ./funcoes Ana, nascida em 14/03/2005, nota 8.5 Eva, nascida em 02/09/2006, nota 7.0 sizeof(struct Data) = 12
Três int de 4 bytes: 12 bytes. O %02d escreve o número com dois dígitos, completando com zero à esquerda (3 vira 03).
6. Comparar structs: == não funciona
Copiar com = pode. Comparar com ==, não:
#include <stdio.h>
struct Aluno {
char nome[50];
int idade;
double nota;
};
int main(void) {
struct Aluno a = {"Ana", 20, 8.5};
struct Aluno b = a;
if (a == b) {
printf("iguais\n");
}
return 0;
}
$ gcc -std=c23 -Wall -Wextra compara.c -o compara
compara.c: In function ‘main’:
compara.c:12:11: error: invalid operands to binary == (have ‘struct Aluno’ and ‘struct Aluno’)
12 | if (a == b) {
| ^~
invalid operands to binary == = "operandos inválidos para o ==": o == só sabe comparar números, caracteres e ponteiros. O C não decide sozinho o que é "dois alunos iguais" (mesmo nome? mesma nota? os dois?). No editor do guia, o Clang diz invalid operands to binary expression ('struct Aluno' and 'struct Aluno').
A solução é escrever uma função que compara campo por campo, do jeito que fizer sentido para o seu programa. Textos se comparam com strcmp (veja Funções de String):
#include <stdio.h>
#include <string.h>
struct Aluno {
char nome[50];
int idade;
double nota;
};
bool mesmo_aluno(struct Aluno a, struct Aluno b) {
return strcmp(a.nome, b.nome) == 0 && a.idade == b.idade && a.nota == b.nota;
}
int main(void) {
struct Aluno a = {"Ana", 20, 8.5};
struct Aluno b = a;
struct Aluno c = {"Ana", 20, 9.0};
printf("a e b: %s\n", mesmo_aluno(a, b) ? "iguais" : "diferentes");
printf("a e c: %s\n", mesmo_aluno(a, c) ? "iguais" : "diferentes");
return 0;
}
$ gcc -std=c23 -Wall -Wextra iguais.c -o iguais $ ./iguais a e b: iguais a e c: diferentes
memcmp?
Parece tentador comparar a memória inteira das duas fichas. O problema são os bytes de preenchimento (padding): o compilador deixa buracos entre os campos para cada um começar num endereço "redondo". Somando os campos do Aluno, dá 50 + 4 + 8 = 62 bytes, mas sizeof(struct Aluno) é 64 no gcc: há 2 bytes de enchimento depois do nome, com conteúdo qualquer. E o que vem depois do '\0' dentro do nome também pode ser lixo. Duas fichas "iguais" podem ter bytes diferentes. Compare campo por campo.
7. Mostrar uma struct na tela
O printf não tem um formato para structs: ele não sabe quais campos existem nem como mostrá-los. Passar a struct inteira dá aviso e lixo na tela:
$ gcc -std=c23 -Wall -Wextra imprimir.c -o imprimir
imprimir.c: In function ‘main’:
imprimir.c:11:14: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘struct Aluno’ [-Wformat=]
11 | printf("%s\n", a);
| ~^ ~
| | |
| | struct Aluno
| char *
$ ./imprimir
«três ou quatro caracteres estranhos»
format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘struct Aluno’ = "o formato %s espera um texto, mas o argumento 2 é uma struct Aluno". O jeito é mostrar campo por campo, de preferência numa função própria, como a mostrar da seção 5. Assim, mudar o formato da ficha na tela é mudar um lugar só.
Formas de preencher uma struct: qual usar
| Forma | Exemplo | Quando usar |
|---|---|---|
| Zerar e preencher campo por campo | struct Aluno a = {0}; a.idade = 20; | Quando os valores chegam aos poucos (lidos do teclado ou de um arquivo). |
| Chaves pela ordem | struct Aluno a = {"Ana", 20, 8.5}; | Structs pequenas, em listas (arrays de structs). |
| Designadores C99 | struct Aluno a = {.nome = "Ana", .nota = 8.5}; | Structs com muitos campos ou campos do mesmo tipo. A mais legível; o que ficar de fora vira zero. |
| Tudo zerado | {0}, ou {} C23 | Uma ficha em branco. Use {0} se o código precisa compilar em versões antigas. |
| Literal composto C99 | a = (struct Aluno){"Bia", 19, 7.5}; | Trocar todos os campos de uma variável que já existe, numa linha. |
Quando dá errado
; da struct
#include <stdio.h>
struct Aluno {
char nome[50];
int idade;
double nota;
}
int main(void) {
struct Aluno a = {"Ana", 20, 8.5};
printf("%s\n", a.nome);
return 0;
}
$ gcc -std=c23 -Wall -Wextra semponto.c -o semponto
semponto.c:9:1: error: expected ‘;’, identifier or ‘(’ before ‘int’
9 | int main(void) {
| ^~~
O que aconteceu: a chave que fecha a struct precisa de ; depois. Funções não precisam (int main(void) { … }), structs precisam. Repare que o gcc aponta a linha seguinte (9), onde ele percebeu o problema: esperava ‘;’ … antes de ‘int’.
Como resolver: ponha o ; depois da } da struct. O Clang, no editor do guia, é mais direto: expected ';' after struct, apontando a linha 7.
$ gcc -std=c23 -Wall -Wextra semstruct.c -o semstruct
semstruct.c: In function ‘main’:
semstruct.c:10:5: error: unknown type name ‘Aluno’; use ‘struct’ keyword to refer to the type
10 | Aluno a;
| ^~~~~
| struct
semstruct.c:11:6: error: request for member ‘idade’ in something not a structure or union
11 | a.idade = 20;
| ^
«…»
O que aconteceu: em C, o nome do tipo é struct Aluno, com as duas palavras. Só Aluno é um "nome de tipo desconhecido". O gcc até sugere: use ‘struct’ keyword. Os erros seguintes são consequência: como a não virou uma struct, ela não tem o campo idade. (Quem vem do C++ cai muito nesse, porque lá Aluno a; funciona.)
Como resolver: escreva struct Aluno a;, ou crie um apelido com typedef.
a.nome = "Ana";
$ gcc -std=c23 -Wall -Wextra atribuir.c -o atribuir
atribuir.c: In function ‘main’:
atribuir.c:11:12: error: assignment to expression with array type
11 | a.nome = "Ana";
| ^
O que aconteceu: "atribuição a uma expressão do tipo array". O campo nome é um array, e array não recebe = (veja Strings). Nas chaves da criação ({"Ana", …}) pode, porque ali é inicialização, não atribuição.
Como resolver: strcpy(a.nome, "Ana"); ou, mais seguro, snprintf(a.nome, sizeof a.nome, "%s", texto);.
$ gcc -std=c23 -Wall -Wextra membro.c -o membro
membro.c: In function ‘main’:
membro.c:11:21: error: ‘struct Aluno’ has no member named ‘email’
11 | printf("%s\n", a.email);
| ^
O que aconteceu: o struct Aluno não tem o campo email. Acontece por erro de digitação (a.Nome em vez de a.nome) ou porque você esqueceu de declarar o campo.
Como resolver: confira o nome exato na declaração da struct (maiúsculas contam) ou acrescente o campo lá.
O que aconteceu: a == b com duas structs não compila (seção 6).
Como resolver: escreva uma função que compara os campos que importam, com strcmp para os textos.
main nada mudou
O que aconteceu: o parâmetro é struct Aluno a: a função recebeu uma cópia, como em copia.c.
Como resolver: passe um ponteiro: void dar_bonus(struct Aluno *a), e chame com dar_bonus(&ana). Detalhes em Structs e Ponteiros.
Referência rápida
| Escrita | Significado |
|---|---|
struct Aluno { char nome[50]; int idade; }; | Declara um tipo novo com dois campos (não esqueça o ; final). |
struct Aluno a; | Cria uma variável; campos com lixo se for local. |
struct Aluno a = {0}; / = {}; | Cria com tudo zerado ({} a partir do C23). |
struct Aluno a = {"Ana", 20}; | Preenche pela ordem dos campos; o resto vira zero. |
struct Aluno a = {.idade = 20, .nome = "Ana"}; | Designadores (C99), em qualquer ordem; o resto vira zero. |
a.idade | Acessa um campo (ler ou mudar). |
a.nascimento.dia | Campo de uma struct dentro de outra. |
strcpy(a.nome, "Ana"); | Guarda texto num campo array (nunca a.nome = …). |
struct Aluno b = a; | Copia todos os campos; b é independente. |
a == b | Erro: compare campo por campo. |
struct Aluno turma[30]; | Um array de structs; turma[i].nota. |
(struct Aluno){"Bia", 19, 7.5} | Literal composto (C99): uma struct sem nome, criada na hora. |
p->nota | Campo por um ponteiro: próxima aula. |
Exercícios
1. Declarar um campo
Complete a struct Produto com um campo preco do tipo double:
2. Criar a variável
Complete para criar uma variável p do tipo da struct acima, com tudo zerado (forma que funciona em qualquer versão do C):
3. Acessar o campo
Complete para dar o preço de 4.50 ao produto p:
4. Com struct Aluno { char nome[50]; int idade; double nota; };, quanto vale b.nota depois de struct Aluno b = {"Bruno", 19};?
5. Qual destas linhas não compila?
6. Uma função void f(struct Aluno a) faz a.nota = 10;. O que acontece com a variável que foi passada no main?
Missão final: a melhor nota da turma
Missão: complete a função melhor, que devolve a posição do aluno com a maior nota. Dentro do for, se turma[i].nota for maior que turma[indice].nota, guarde i em indice. A tela deve mostrar Melhor: Carla (9.5).
#include <stdio.h>
struct Aluno {
char nome[50];
int idade;
double nota;
};
size_t melhor(const struct Aluno turma[], size_t n) {
size_t indice = 0;
for (size_t i = 1; i < n; i++) {
/* se a nota de turma[i] for maior que a de turma[indice], guarde i em indice */
}
return indice;
}
int main(void) {
struct Aluno turma[] = {
{"Ana", 20, 8.5},
{"Bruno", 19, 6.0},
{"Carla", 22, 9.5},
{"Davi", 21, 7.0},
};
size_t n = sizeof turma / sizeof turma[0];
size_t m = melhor(turma, n);
printf("Melhor: %s (%.1f)\n", turma[m].nome, turma[m].nota);
return 0;
}
#include <stdio.h>
struct Aluno {
char nome[50];
int idade;
double nota;
};
size_t melhor(const struct Aluno turma[], size_t n) {
size_t indice = 0;
for (size_t i = 1; i < n; i++) {
if (turma[i].nota > turma[indice].nota) {
indice = i;
}
}
return indice;
}
int main(void) {
struct Aluno turma[] = {
{"Ana", 20, 8.5},
{"Bruno", 19, 6.0},
{"Carla", 22, 9.5},
{"Davi", 21, 7.0},
};
size_t n = sizeof turma / sizeof turma[0];
size_t m = melhor(turma, n);
printf("Melhor: %s (%.1f)\n", turma[m].nome, turma[m].nota);
return 0;
}
Resumo
- Uma struct cria um tipo novo que agrupa campos de tipos diferentes:
struct Aluno { char nome[50]; int idade; double nota; };. Não esqueça o;depois da chave. - Em C, o tipo se chama
struct Aluno(as duas palavras). A struct guarda só dados: nada de funções dentro. - Acesse cada campo com o ponto:
a.nota. Texto num campo array entra comstrcpy/snprintf. - Campo sem valor = lixo. Crie com
{0}(ou{}no C23) para zerar tudo. - Preencha com chaves:
{"Ana", 20, 8.5}(pela ordem) ou{.nome = "Ana", .nota = 8.5}(designadores, C99, em qualquer ordem). =copia a struct inteira;==não compila: compare campo por campo.- Passar uma struct para uma função copia tudo; para mudar a original, use um ponteiro (próxima aula).