typedef Parte 1 de 2O que é, como declarar, inicializar, usar typedef e passar para funções
struct?Imagine que você quer representar um aluno no programa. Ele tem matrícula (int), nome (char[]) e nota (float). Sem struct, você precisaria de três variáveis soltas — e à medida que o programa crescesse, ficaria impossível de gerenciar. Em Java você criaria uma classe. Em C, você usa uma struct.
public class Aluno {
int matricula;
String nome;
float nota;
// Java permite métodos:
float calcularSituacao() {
return nota >= 7.0f ? 1 : 0;
}
}
struct Aluno {
int matricula;
char nome[50];
float nota;
// ❌ C não tem métodos em struct
// funções ficam fora da struct
};
/* 1. Definição do tipo struct */ struct Aluno { int matricula; char nome[50]; float nota1; float nota2; }; /* 2. Declaração de variável do tipo struct */ struct Aluno a1; struct Aluno a2, a3; // múltiplas variáveis
struct é obrigatória ao declarar variáveis — ao contrário de Java, onde o nome da classe é suficiente. Para eliminar essa repetição, use typedef (seção 4).
.)
#include <stdio.h>
#include <string.h>
struct Aluno {
int matricula;
char nome[50];
float nota1, nota2;
};
int main() {
struct Aluno a;
/* Atribuição campo por campo */
a.matricula = 1001;
strcpy(a.nome, "Ana Oliveira"); // strings precisam de strcpy!
a.nota1 = 8.5f;
a.nota2 = 9.0f;
printf("Matrícula: %d\n", a.matricula);
printf("Nome: %s\n", a.nome);
printf("Notas: %.1f %.1f\n", a.nota1, a.nota2);
printf("Média: %.1f\n", (a.nota1 + a.nota2) / 2.0f);
return 0;
}
Aluno a = new Aluno(); a.matricula = 1001; a.nome = "Ana Oliveira"; // OK a.nota1 = 8.5f; System.out.println(a.nome);
struct Aluno a;
a.matricula = 1001;
strcpy(a.nome, "Ana"); // strcpy!
a.nota1 = 8.5f;
printf("%s\n", a.nome);
a.campo funciona da mesma forma. A diferença prática é que campos char[] exigem strcpy em vez de atribuição simples, pois strings em C são arrays (veja Aula 26).
struct Ponto {
float x;
float y;
};
struct Produto {
int codigo;
char nome[40];
float preco;
};
/* Forma 1 — inicializador posicional (C89) */
struct Ponto p1 = {3.0f, 4.0f};
/* Forma 2 — designated initializers (C99, mais legível) */
struct Produto prod = {
.codigo = 101,
.nome = "Caneta",
.preco = 2.50f
};
/* Forma 3 — struct literal (C99) */
struct Ponto p2 = (struct Ponto){.x = 1.0f, .y = 2.0f};
/* Forma 4 — zero-initialize */
struct Produto vazio = {0}; // todos os campos zerados
// Com construtor explícito:
Produto p = new Produto(101,
"Caneta", 2.50f);
// Sem construtor:
Produto p = new Produto();
p.codigo = 101;
p.nome = "Caneta";
p.preco = 2.50f;
// C não tem construtores —
// inicializadores são o recurso mais próximo:
struct Produto p = {
.codigo = 101,
.nome = "Caneta",
.preco = 2.50f
};
// ou campo a campo após declaração
typedef — Criando Apelidos de TipoEscrever struct Aluno toda vez é verboso. O typedef cria um apelido para um tipo, eliminando a necessidade da palavra-chave struct.
typedef cria um novo nome para um tipo existente. Não cria um tipo diferente — é apenas um alias. O compilador trata os dois nomes como idênticos. Além de structs, é muito usado para int, unsigned char e outros tipos para dar semântica ao código.
/* Forma 1 — separado (mais claro para iniciantes) */ struct Aluno { int matricula; char nome[50]; float nota; }; typedef struct Aluno Aluno; // cria alias "Aluno" para "struct Aluno" /* Forma 2 — combinado (mais comum na prática) */ typedef struct { int matricula; char nome[50]; float nota; } Aluno; /* Com typedef, não precisa mais de "struct" na declaração: */ Aluno a1; // ✅ limpo struct Aluno a2; // ✅ ainda funciona na Forma 1
// Em Java o nome da classe // já é o tipo — sem prefixo: Aluno a = new Aluno(); Produto p = new Produto();
/* Sem typedef — verboso */ struct Aluno a; struct Produto p; /* Com typedef — limpo como Java */ Aluno a; Produto p;
/* Dando semântica a tipos primitivos */ typedef int Matricula; typedef float Nota; typedef char Nome[50]; Matricula id = 1001; Nota n1 = 8.5f; Nome nome = "Ana"; // cuidado: Nome é array, usar strcpy para atribuir! /* typedef com ponteiro — idioma comum em código C profissional */ typedef int *PonteiroInt; PonteiroInt p = &id; // equivale a: int *p = &id;
typedef int Metros; typedef int Kilos; não impede somar metros com quilos — o compilador os trata como int idênticos. É apenas documentação.
Structs podem ser passadas para funções por valor (cópia de todos os campos) ou por ponteiro (8 bytes, acessa o original). Para structs grandes, o ponteiro é sempre preferível.
void exibir(Aluno a) {
// Java: a é referência ao objeto
// modificações afetam o original
System.out.println(a.nome);
}
void incrementar(Aluno a) {
a.nota += 1.0f; // altera o original
}
// Por valor: cópia — lento, não altera original
void exibir(Aluno a) {
printf("%s\n", a.nome);
}
// Por ponteiro: rápido, altera original
void incrementar(Aluno *a) {
a->nota += 1.0f;
}
#include <stdio.h>
#include <string.h>
typedef struct {
int matricula;
char nome[50];
float nota1, nota2;
} Aluno;
/* Só lê — const evita modificação acidental */
void exibirAluno(const Aluno *a) {
float media = (a->nota1 + a->nota2) / 2.0f;
printf("%-6d %-20s %.1f %.1f %.1f %s\n",
a->matricula, a->nome,
a->nota1, a->nota2, media,
media >= 7.0f ? "Aprovado" : "Reprovado");
}
/* Modifica — ponteiro sem const */
void aplicarBonus(Aluno *a, float bonus) {
a->nota1 += bonus;
a->nota2 += bonus;
if (a->nota1 > 10.0f) a->nota1 = 10.0f;
if (a->nota2 > 10.0f) a->nota2 = 10.0f;
}
int main() {
Aluno turma[] = {
{1001, "Ana Oliveira", 8.0f, 7.5f},
{1002, "Bruno Santos", 5.0f, 6.0f},
{1003, "Carla Mendes", 9.5f, 9.0f}
};
int n = 3;
printf("%-6s %-20s %-5s %-5s %-5s %s\n",
"Mat.", "Nome", "N1", "N2", "Med.", "Situação");
printf("------------------------------------------------------\n");
for (int i = 0; i < n; i++)
exibirAluno(&turma[i]);
printf("\nApós bônus de 0.5:\n");
printf("------------------------------------------------------\n");
for (int i = 0; i < n; i++)
aplicarBonus(&turma[i], 0.5f);
for (int i = 0; i < n; i++)
exibirAluno(&turma[i]);
return 0;
}
const Tipo *p quando a função só lê — eficiente (8 bytes) e protegido contra modificação acidental. Use Tipo *p quando precisa modificar. Nunca passe structs grandes por valor — o custo de cópia é proporcional ao tamanho da struct.