CPGE Oujda                                                                                                                                 Spe

Structures, unions et énumérations

 

Les structures

Une structure est une variable qui regroupe une ou plusieurs variables, non nécessairement de même type (contrairement aux tableaux), appelées champs. L'accès à un champ d'une structure se fait par l'intermédiaire de l'opérateur point. Par exemple :

struct {char nom[20]; int age;} marc, luc, jean;
...
strcpy(marc.nom, "Marc");
marc.age = 24 ;
...

D'habitude on renomme tout d'abord une structure avant de l'utiliser. Par exemple :

typedef struct {char nom[20]; int age;} PERSONNE;
...
PERSONNE marc, luc, jean;
...

Une structure peut être également nommée. Par exemple :

struct personne_s {char nom[20]; int age;} marc, luc, jean;

Dans ce cas, marc, luc et jean sont de type struct personne_s. On aurait également pu écrire :

struct personne_s {
    char nom[20];
    int age;
};

Puis :

struct personne_s marc, luc, jean;

Et bien entendu, du moment qu'une structure a été nommée, on peut très bien écrire :

typedef struct personne_s PERSONNE;

L'opérateur = (affectation) peut être utilisé avec des structures (pour copier une structure) mais dans la pratique on n'en a rarement besoin. En effet, puisque l'espace occupée en mémoire par une structure peut être gigantesque, copier une structure vers une autre pénalisera considérablement, non seulement en termes de performances mais aussi en termes de vitesse d'exécution (à cause du temps d'accès à une cellule mémoire). C'est pourquoi on utilise généralement des pointeurs pour manipuler les structures. L'opérateur -> permet d'accéder à un champ d'une structure via un pointeur. Par exemple :

#include <stdio.h>
#include <string.h>
 
struct personne_s {
    char nom[20];
    int age;
};
 
void affiche_personne(struct personne_s * p);
 
int main()
{
    struct personne_s jean;
 
    strcpy(jean.nom, "Jean");
    jean.age = 24;
 
    affiche_personne(&jean);
 
    return 0;
}
 
void affiche_personne(struct personne_s * p)
{
    printf("Nom : %s\n", p->nom);
    printf("Age : %d\n", p->age);
}

L'initialisation d'une structure se fait de la même manière que pour un tableau, avec les mêmes règles. Par exemple :

struct personne_s jean = {"Jean", 24};

 

V-B. Les unions

Une union est, en première approximation, une variable dont le type n'est pas figé (c'est-àdire une variable « caméléon »). En fait, une variable de type union est une variable composée de champs de types différents et non nécessairement de même taille, mais à la différence d'une structure, les champs d'une union partagent le même emplacement mémoire. Les unions permettent donc de faire une économie de mémoire. Du point de vue syntaxique, elles ressemblent beaucoup aux structures, il suffit de remplacer struct par union.
Le programme suivant montre un exemple d'utilisation de cette union, u, entre trois variables de types différents (n, x et p).

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
union trois_en_un {
    int n;
    double x;
    char * p;
};
 
int main()
{
    union trois_en_un u;
    
    printf("Entrez un entier : ");
    scanf("%d", &(u.n));
    printf("Vous avez entre : %d\n\n", u.n);
    
    printf("Entrez un nombre flottant : ");
    scanf("%lf", &(u.x));
    printf("Vous avez entre : %f\n\n", u.x);
    
    u.p = malloc(20);
    if (u.p != NULL)
    {
        strcpy(u.p, "Au revoir.");
        printf("%s\n\n", u.p);
        free(u.p);
    }
    
    return 0;
}

Puisque les champs d'une union utilisent le même espace mémoire, les unions sont également utilisées pour interpréter un même motif binaire dans différents contextes (par exemple pour interpréter le contenu d'une mémoire comme un flottant, ou comme un entier, ...), mais cette pratique est généralement utilisée dans les programmes de très bas niveau plutôt que dans des programmes portables.

Les énumérations

Une énumération est un sous-ensemble énuméré du type int. La déclaration d'une énumération ressemble un peu à celle d'une structure Par exemple :

typedef enum {
    PION,
    CAVALIER,
    FOU,
    TOUR,
    REINE,
    ROI
} CLASSE;
...
CLASSE classe = FOU; /* Ou egalement int classe = FOU; */
...

Qu'on aurait également pu écrire :

#define PION 0
#define CAVALIER PION + 1
#define FOU CAVALIER + 1
#define TOUR FOU + 1
#define REINE TOUR + 1
#define ROI REINE + 1
...
int classe = FOU;
...

L'opérateur = peut également être utilisé dans une déclaration d'un type énuméré pour assigner explicitement une valeur à une constante.