Pointeurs et structures en C
Combiner pointeurs et structures est une technique fondamentale en C pour manipuler des données composites efficacement, notamment pour les listes chaînées, les arbres, et les tableaux dynamiques de structures.
struct, accès par .). Consulter les cours correspondants avant de poursuivre.1. Déclarer un pointeur sur une structure
struct. Sa déclaration suit la même syntaxe que tout pointeur : struct NomType *ptr;.struct NomType *ptr; /* déclaration seule */
struct NomType *ptr = &var; /* déclaration + initialisation */Exemple n°1 — Déclarer un pointeur sur struct
#include <stdio.h>
struct etudiant {
char prenom[20];
int age;
};
int main(void)
{
struct etudiant *et1; /* pointeur sur struct etudiant — non initialisé */
struct etudiant et2; /* variable struct normale */
et1 = &et2; /* et1 pointe maintenant sur et2 */
return 0;
}struct etudiant *p;
p->age = 20; /* Danger — p non initialisé */
struct etudiant e;
struct etudiant *p = &e;
p->age = 20; /* Correct — p pointe sur e */2. Accéder aux membres via un pointeur
Deux notations permettent d'accéder aux membres d'une structure via un pointeur :
| Notation | Syntaxe | Description |
|---|---|---|
| Flèche (recommandée) | ptr->membre | Accès direct via pointeur — forme idiomatique |
| Point + déréférencement | (*ptr).membre | Déréférencement puis accès — parenthèses obligatoires |
-> et (*ptr). L'opérateur -> est un raccourci syntaxique : ptr->membre est strictement équivalent à (*ptr).membre. La flèche est préférée car plus lisible et moins sujette aux erreurs de priorité des opérateurs.et1->prenom ≡ (*et1).prenom
et1->age ≡ (*et1).age
/* Attention : *et1.age serait une erreur — équivaut à *(et1.age) */Exemple n°2 — Saisie et affichage via pointeur
#include <stdio.h>
struct etudiant {
char prenom[20];
int age;
};
int main(void)
{
struct etudiant et2;
struct etudiant *et1 = &et2; /* et1 pointe sur et2 */
printf("Saisir votre prénom : ");
scanf("%s", et1->prenom); /* pas de & — prenom est déjà un tableau */
printf("Saisir votre âge : ");
scanf("%d", &et1->age);
printf("\n--- Informations ---\n");
printf("Prénom : %s\n", et1->prenom);
printf("Âge : %d\n", et1->age);
/* Vérification : les deux notations donnent le même résultat */
printf("\nVia (*et1).prenom : %s\n", (*et1).prenom);
return 0;
}Saisir votre prénom : Mostafa Saisir votre âge : 32 --- Informations --- Prénom : Mostafa Âge : 32 Via (*et1).prenom : Mostafa
scanf et les tableaux de caractères Pour un champ de type tableau (char prenom[20]), le nom du tableau est déjà une adresse — il ne faut pas ajouter & devant et1->prenom. Pour un champ scalaire (int age), il faut &et1->age:scanf("%s", et1->prenom); /* tableau — sans & */
scanf("%d", &et1->age); /* scalaire — avec & */3. Allocation dynamique d'une structure
Allouer une structure sur le tas avec malloc permet de créer des structures dont la durée de vie n'est pas liée à la portée d'une fonction et de construire des structures de données dynamiques (listes chaînées, arbres…).
#include <stdlib.h>
struct NomType *ptr;
ptr = (struct NomType *) malloc(sizeof(struct NomType));
if (ptr == NULL) {
/* gestion de l'échec d'allocation */
}
/* ... utilisation ... */
free(ptr);
ptr = NULL;Exemple n°3 — Allocation dynamique d'un étudiant
#include <stdio.h>
#include <stdlib.h>
struct etudiant {
char prenom[20];
int age;
};
int main(void)
{
struct etudiant *et1;
/* Allocation sur le tas */
et1 = (struct etudiant *) malloc(sizeof(struct etudiant));
if (et1 == NULL) {
printf("Erreur d'allocation mémoire\n");
return 1;
}
printf("Saisir votre prénom : ");
scanf("%s", et1->prenom);
printf("Saisir votre âge : ");
scanf("%d", &et1->age);
printf("\nPrénom : %s\n", et1->prenom);
printf("Âge : %d\n", et1->age);
/* Libération indispensable */
free(et1);
et1 = NULL;
return 0;
}Saisir votre prénom : Mostafa Saisir votre âge : 24 Prénom : Mostafa Âge : 24
free Tout appel à malloc doit être suivi d'un appel à free lorsque la mémoire n'est plus nécessaire. Oublier le free provoque une fuite mémoire — la mémoire reste occupée jusqu'à la fin du programme. Mettre systématiquement ptr = NULL après free pour éviter le double free et l'utilisation d'un pointeur fantôme.4. Tableau dynamique de structures
Allouer un tableau de N structures en une seule opération est le cas d'usage le plus courant des pointeurs sur structures — par exemple pour gérer une liste d'étudiants dont le nombre n'est connu qu'à l'exécution.
struct NomType *tab;
tab = (struct NomType *) malloc(n * sizeof(struct NomType));
/* Accès à l'élément i — deux notations équivalentes */
tab[i].membre /* notation tableau — recommandée */
(tab + i)->membre /* notation pointeur */Exemple n°4 — Tableau dynamique de N étudiants
#include <stdio.h>
#include <stdlib.h>
struct etudiant {
char prenom[20];
int age;
};
int main(void)
{
struct etudiant *tab;
int n, i;
printf("Nombre d'étudiants : ");
scanf("%d", &n);
/* Allocation de n structures contiguës */
tab = (struct etudiant *) malloc(n * sizeof(struct etudiant));
if (tab == NULL) {
printf("Erreur d'allocation\n");
return 1;
}
/* Saisie */
for (i = 0 ; i < n ; i++) {
printf("\n--- Étudiant N°%d ---\n", i + 1);
printf("Prénom : ");
scanf("%s", tab[i].prenom); /* notation tableau */
printf("Âge : ");
scanf("%d", &tab[i].age);
}
/* Affichage */
printf("\n=== Liste des étudiants ===\n");
for (i = 0 ; i < n ; i++) {
printf("Étudiant N°%d : %s, %d ans\n",
i + 1, tab[i].prenom, tab[i].age);
}
free(tab);
tab = NULL;
return 0;
}Nombre d'étudiants : 3 --- Étudiant N°1 --- Prénom : Mostafa Âge : 23 --- Étudiant N°2 --- Prénom : Ismail Âge : 20 --- Étudiant N°3 --- Prénom : Dounia Âge : 22 === Liste des étudiants === Étudiant N°1 : Mostafa, 23 ans Étudiant N°2 : Ismail, 20 ans Étudiant N°3 : Dounia, 22 ans
tab[i].prenom /* notation tableau — recommandée */
(tab + i)->prenom /* notation pointeur — équivalente */Exemple n°5 — Passage d'un tableau de structures en fonction
#include <stdio.h>
#include <stdlib.h>
struct etudiant {
char prenom[20];
int age;
};
/* La fonction reçoit un pointeur — le tableau n'est pas copié */
void afficher(struct etudiant *tab, int n)
{
int i;
for (i = 0 ; i < n ; i++) {
printf("%d. %-15s %d ans\n", i + 1, tab[i].prenom, tab[i].age);
}
}
int main(void)
{
struct etudiant *tab;
int n = 3;
tab = (struct etudiant *) malloc(n * sizeof(struct etudiant));
/* Initialisation directe pour l'exemple */
tab[0] = (struct etudiant){"Mostafa", 23};
tab[1] = (struct etudiant){"Ismail", 20};
tab[2] = (struct etudiant){"Dounia", 22};
afficher(tab, n);
free(tab);
tab = NULL;
return 0;
}1. Mostafa 23 ans 2. Ismail 20 ans 3. Dounia 22 ans
Récapitulatif
| Opération | Syntaxe | Remarque |
|---|---|---|
| Déclaration | struct T *p; | Non initialisé — dangereux à utiliser |
| Affectation d'adresse | p = &var; | p pointe sur une variable existante |
| Accès membre (flèche) | p->membre | Recommandé — idiomatique |
| Accès membre (point) | (*p).membre | Équivalent — parenthèses obligatoires |
| Allocation d'une struct | malloc(sizeof(struct T)) | Vérifier NULL + appeler free() |
| Tableau dynamique | malloc(n * sizeof(struct T)) | Accès par tab[i].membre |
| Libération | free(p); p = NULL; | Obligatoire — évite fuite mémoire |
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.