Essayer de coder ← Retour aux sujets

struct et typedef

struct

Une structure regroupe des variables de types différents (les champs) sous un seul nom : l'équivalent d'un enregistrement.

struct Point { int x; int y; };
Définit un nouveau type de structure
struct Point p = {3, 4};
Variable initialisée champ par champ
p.x = 10;
Accès à un champ avec le point
typedef struct { … } Eleve;
Donne un nom court au type : Eleve e;
ptr->age
Accès à un champ via un pointeur : équivaut à (*ptr).age
eleve.c
#include <stdio.h>

typedef struct {
    char nom[20];
    int age;
    double moyenne;
} Eleve;

int main(void) {
    Eleve e = {"Lina", 17, 14.5};

    printf("%s a %d ans, moyenne %.1f\n", e.nom, e.age, e.moyenne);
    return 0;
}
Affichage
Lina a 17 ans, moyenne 14.5

Tableaux et fonctions

Eleve classe[3]

Une structure se passe à une fonction par valeur (copiée) ou par adresse (pour la modifier, ou éviter une grosse copie).

Eleve classe[30];
Tableau de 30 élèves
classe[i].age
Champ age de l'élève d'indice i
void f(Eleve e)
Reçoit une copie de la structure
void f(Eleve *e)
Reçoit son adresse : on écrit e->age
sizeof(Eleve)
Taille de la structure (peut inclure du remplissage)
classe.c
#include <stdio.h>

typedef struct {
    char nom[20];
    double moyenne;
} Eleve;

int main(void) {
    Eleve classe[3] = {{"Lina", 14.5}, {"Sami", 16.0}, {"Nova", 12.25}};
    int meilleur = 0;

    for (int i = 1; i < 3; i++) {
        if (classe[i].moyenne > classe[meilleur].moyenne) {
            meilleur = i;
        }
    }
    printf("meilleure moyenne : %s (%.2f)\n", classe[meilleur].nom, classe[meilleur].moyenne);
    return 0;
}
Affichage
meilleure moyenne : Sami (16.00)

🧱 Le cours : créer ses propres types

Un tableau regroupe des valeurs du même type. Une structure regroupe des valeurs de types différents qui décrivent un même objet : un élève (nom, âge, moyenne), un point (x, y), une date (jour, mois, année). C'est l'ancêtre des classes de la programmation orientée objet, sans les méthodes.

Définir une structure

On déclare les champs entre accolades, et on termine par un point-virgule. Le type s'appelle alors struct Point. Contrairement à un tableau, une structure se copie avec = : tous les champs sont recopiés.

point.c
#include <stdio.h>

struct Point {
    int x;
    int y;
};

int main(void) {
    struct Point a = {3, 4};
    struct Point b = a;        /* copie champ par champ */

    b.x = 10;
    printf("a = (%d, %d), b = (%d, %d)\n", a.x, a.y, b.x, b.y);
    return 0;
}
Affichage
a = (3, 4), b = (10, 4)

typedef : un nom plus court

Écrire struct Point à chaque fois est lourd. typedef donne un nom au type : après typedef struct { … } Point;, on écrit simplement Point p;. Par convention, les noms de types commencent par une majuscule.

Accéder aux champs : . et ->

Avec une variable de type structure, on utilise le point : e.age. Avec un pointeur vers une structure, on utilise la flèche : p->age, qui est un raccourci de (*p).age. C'est ce qui permet à une fonction de modifier la structure de l'appelant.

anniversaire.c
#include <stdio.h>

typedef struct {
    char nom[20];
    int age;
} Eleve;

void anniversaire(Eleve *e) {
    e->age = e->age + 1;       /* (*e).age = (*e).age + 1 */
}

int main(void) {
    Eleve e = {"Lina", 17};

    anniversaire(&e);
    printf("%s a maintenant %d ans\n", e.nom, e.age);
    return 0;
}
Affichage
Lina a maintenant 18 ans

Renvoyer une structure

Une fonction peut renvoyer une structure entière : elle est copiée vers l'appelant. C'est pratique pour renvoyer plusieurs valeurs d'un coup, sans passer par des pointeurs.

milieu.c
#include <stdio.h>

typedef struct {
    int x;
    int y;
} Point;

Point milieu(Point a, Point b) {
    Point m = {(a.x + b.x) / 2, (a.y + b.y) / 2};
    return m;
}

int main(void) {
    Point a = {0, 0}, b = {6, 10};
    Point m = milieu(a, b);

    printf("milieu = (%d, %d)\n", m.x, m.y);
    return 0;
}
Affichage
milieu = (3, 5)

Structures imbriquées et tableaux de structures

Un champ peut lui-même être une structure ou un tableau. On enchaîne alors les accès : segment.debut.x, classe[2].nom[0]. Un tableau de structures (voir la deuxième carte) est l'équivalent d'un tableau d'objets : on le parcourt avec une boucle, comme n'importe quel tableau.

segment.c
typedef struct { int x; int y; } Point;

typedef struct {
    Point debut;
    Point fin;
} Segment;

Segment s = {{0, 0}, {4, 3}};
/* s.fin.x vaut 4, s.debut.y vaut 0 */

Énumérations : des noms pour des entiers

enum associe des noms aux entiers 0, 1, 2… Le code devient plus lisible qu'avec des nombres « magiques » : on écrit MARDI au lieu de 1.

enum.c
#include <stdio.h>

enum Jour { LUNDI, MARDI, MERCREDI };

int main(void) {
    enum Jour j = MARDI;

    printf("%d\n", j);
    if (j == MARDI) {
        printf("c'est mardi\n");
    }
    return 0;
}
Affichage
1
c'est mardi

Aperçu : une structure qui se référence elle-même

Une structure peut contenir un pointeur vers une structure du même type. C'est la base des listes chaînées et des arbres : chaque maillon connaît le suivant. Ces structures s'allouent avec malloc (voir Mémoire dynamique).

noeud.c
struct Noeud {
    int valeur;
    struct Noeud *suivant;   /* NULL pour le dernier maillon */
};

⚠️ Erreurs fréquentes

Oublier le point-virgule après l'accolade fermante

struct Point { int x; int y; } sans ; final provoque une erreur de compilation souvent signalée à la ligne *suivante*, ce qui déroute. Pense à };.

Utiliser le point au lieu de la flèche (ou l'inverse)

À éviter
faux.c
Eleve *p = &e;
p.age = 18;       /* p est un pointeur : erreur */
Correct
correct.c
Eleve *p = &e;
p->age = 18;      /* flèche pour un pointeur */

Affecter une chaîne à un champ tableau

À éviter
faux.c
Eleve e;
e.nom = "Lina";          /* on ne peut pas affecter un tableau */
Correct
correct.c
Eleve e;
strcpy(e.nom, "Lina");   /* copie le texte (string.h) */

On ne peut écrire {"Lina", 17} qu'à la déclaration de la variable. Ensuite, un champ de type tableau se remplit avec strcpy (ou snprintf).

Comparer deux structures avec ==

a == b est refusé par le compilateur pour des structures. Compare champ par champ : a.x == b.x && a.y == b.y.

Oublier struct sans typedef

Après struct Point { … }; seul, le type s'écrit struct Point : Point p; donne une erreur. Soit tu écris struct Point p;, soit tu utilises typedef.

Passer de grosses structures par valeur

Chaque appel copie toute la structure. Pour une structure volumineuse que la fonction ne fait que lire, passe son adresse avec const : void afficher(const Eleve *e).

📋 Aide-mémoire

  • struct Nom { type champ; … }; (avec le ; final) ; typedef struct { … } Nom; pour écrire Nom v;.
  • v.champ sur une variable, p->champ sur un pointeur (≡ (*p).champ).
  • = copie une structure entière ; == est interdit : compare champ par champ.
  • Un champ tableau se remplit avec strcpy / snprintf, pas avec = (sauf à la déclaration).
  • Passer Type *p pour modifier ou éviter la copie, const Type *p pour seulement lire.
  • enum donne des noms aux entiers 0, 1, 2… ; un pointeur vers le même type permet de chaîner des maillons.