Vous êtes sur la page 1sur 31

Les structures

La réalisation de nombreuses tâches de programmation se trouve simplifiée par


les structures. Une structure est une méthode de sauvegarde des données
choisie par le programmeur; elle répond donc exactement aux besoins du
programme. Aujourd’hui, vous allez étudier :

● Ce que représente une structure simple ou complexe ;


● La définition et la déclaration des structures ;
● Le mode d’accès aux données des structures ;
● La création des structures pour stocker des tableaux et des tableaux des
structures ;
● La déclaration de pointeurs dans les structures et de pointeurs vers de
structures ;
● Le passage de structures en arguments de fonctions ;

1
Les structures simples
Une structure contient une ou plusieurs variables
groupées sous le même nom pour être traitées comme une
seule entité.

Contrairement aux variables stockées dans un tableau,


les variables d’une structure peuvent être de types
différents.

Une structure peut contenir tous les types de données


C, y compris les tableaux et les autres structures. Chaque
variable d’une structure est appelée membre de cette
structure. 2
Définition et déclaration des structures
Vous pouvez définir une structure point contenant les valeurs x et y
d’un écran de cette façon :

struct point{
int x;
int y;
};

Le mot clé struct identifie le début de la structure et informe le


compilateur que point est le type de structure.

Il y a deux façons de déclarer les structures.

3
Définition et déclaration des structures
La première consiste à faire suivre la définition d’une liste de noms de
plusieurs variables :
struct point{
int x;
int y;
} premier, second;

Ces instructions définissent la structure de type point et déclarent deux


structures appelées premier et second appartenant au type point. premier
contient deux membres entiers appelés x et y, y tout comme second.
second

La seconde méthode consiste à déclarer les variables de la structure dans une


autre partie du code du programme. Voici une autre syntaxe pour déclarer deux
structures de type point :

struct point{
int x;
int y;
};
/* instructions ... */ 4
struct point premier, second;
Accès aux membres d’une structure
Chaque membre d’une structure peut être utilisé comme une variable isolée du
même type.
Pour faire référence à un membre particulier, on sépare le nom de la structure
concernée de celui du membre visé, avec l ’opérateur (.). Pour que la structure
premier représente le point de l’écran de coordonnées x=50, y=100, on utilise la
syntaxe suivante :

premier.x = 50;
premier.y = 100;

- L’instruction suivante permet d’afficher les coordonnées d’écran stockées


dans la structure second :
printf("%d,%d", second.x, second.y);
scanf ("%d", &second.x) ; lit, suivant le code format %d
second.x ++ incrémente de 1 la valeur du champ x de la structure.

Remarque :
La priorité de l'opérateur "." est très élevée, de sorte qu'aucune des
expressions ci-dessus ne nécessite de parenthèses.
5
Exemples de structure
Exemple 1

/* déclaration d’un modèle de structure appelé SSN */

struct SSN {
int premier;
char d1;
int second;
char d2;
int dernier;
}

/* utilisation du modèle */
struct SSN client;
Le mot clé struct permet de déclarer la structure, et indique au
compilateur le début de la définition d’une structure. 6
Exemples de structure
Exemple 2

/* Déclaration complète d’une structure */

struct date {
char jour[2];
char mois[2];
char an[4];
} date_jour;

Exemple 3
/* Définition, déclaration et initialisation d’une structure */

struct heure {
int heures;
int minutes;
int seconds;
7
} heure_naissance = { 8, 45, 0 };
Exemples d'utilisation de typedef sur les
variables simples
La déclaration:

typedef int entier ;


signifie que entier est "synonyme" de int, de sorte que les déclarations
suivantes sont équivalentes:

int n, p ;
entier n, p ;

De même:
typedef int * pointeur;

signifie que pointeur est synonyme de int *. Les déclarations suivantes


sont équivalentes:

int * p1, * p2 ;
pointeur p1, p2 ;
8
Application de typedef aux structures
En faisant usage de typedef, les déclarations des structures peuvent
être réalisées comme suit:
struct enreg
{ int numero ;
int qte ;
float prix ;
};

typedef struct enreg ENR ;


ENR art1, art2 ;

ou encore, plus simplement:


typedef struct
{ int numero ;
int qte ;
float prix ;
} ENR ;
9
ENR art1, art2 ;
Copier des informations entre structures de même
type
Le principal avantage des structures sur les variables est la possibilité de
copier des informations entre structures de même type par une seule
instruction simple. Dans le cas de notre exemple précédent, l’instruction :

premier = second;
est équivalente aux deux instructions suivantes :

premier.x = second.x;
premier.y = second.y;

Remarque :

L'affectation globale n'est pas possible entre tableaux. Elle l'est, par
contre, entre structures. Aussi est-il possible, en créant artificiellement
une structure contenant un seul champ qui est un tableau, de réaliser
une affectation globale entre tableaux.
10
Structures complexes(imbrication des structures)
Après avoir introduit les structures simples, nous pouvons étudier des types de
structures plus intéressants. Ce sont les structures dont les membres sont
d’autres structures ou des tableaux.

Structures contenant des structures


Un rectangle peut être représenté par les coordonnées de deux coins
diagonalement opposés.

struct rectangle {
struct point hautgauche; struct point {
struct point basdroite; int x;
}; int y;
} hautgauche, basdroite;

La structure de type rectangle contient deux structures appartenant au


type point : hautgauche et basdroite.
11
Structures complexes(
Ces instructions ne constituent que le modèle de la structure, pour la
déclarer, vous devez inclure une instruction du type :
struct rectangle maboite;

Vous auriez pu combiner définition et déclaration de cette façon :


struct rectangle {
struct point hautgauche;
struct point basdroite;
} maboite;

Pour accéder aux membres de type int de deux structures imbriquées, il


faut utiliser deux fois l’opérateur (.) : maboite.hautgauche.x.
Cette expression fait référence au membre x du membre hautgauche de la
structure maboite appartenant au type rectangle.
L’exemple suivant est le code qui décrit un
rectangle de coordonnées (0, 10), (100, 200) :
maboite.hautgauche.x = 0;
maboite.hautgauche.y = 10;
maboite.basdroite.x = 100;
maboite.basdroite.y = 200;
12
Exercice d’application
Ecrire un programme qui présente de structures imbriquées. Ce
programme demande à l’utilisateur les coordonnées d’un rectangle
pour en calculer l’aire et l’afficher.

/* Ce programme reçoit les coordonnées des coins d’un rectangle


et en calcule l’aire. On suppose que la coordonnée y du coin
supérieur gauche est plus grande que la coordonnée y du coin
inférieur droit, que la coordonnée x du coin inférieur droit
est plus grande que la coordonnée x du coin supérieur gauche,
et que toutes les coordonnées sont positives. */

13
#include <stdio.h>
#include <stdlib.h>
int longueur, largeur; long aire;
struct point{
int x; int y;
};
struct rectangle{
struct point hautgauche;
struct point basdroit;
} maboite;

int main() {
/* Lecture des coordonnées */
printf("\nEntrez la coord x du coin sup gche :");
scanf("%d", &maboite.hautgauche.x);
printf("\nEntrez la coordonnée y du coin supérieur gauche :");
scanf("%d", &maboite.hautgauche.y);
printf("\nEntrez la coordonnée x du coin inférieur droit :");
scanf("%d", &maboite.basdroit.x);
printf("\nEntrez la coordonnée y du coin inférieur droit :");
scanf("%d", &maboite.basdroit.y);
/* Calcul de la longueur et de la largeur */
largeur = maboite.basdroit.x – maboite.hautgauche.x;
longueur = maboite.basdroit.y – maboite.hautgauche.y;
/* Calcul et affichage de l’aire */
aire = largeur * longueur;
14
}
Les tableaux membres de structures
Vous pouvez définir une structure constituée d’un ou de plusieurs tableaux. Les tableaux
peuvent contenir tous les types de données C. Les instructions suivantes, par exemple,
définissent un modèle de structure data qui contient un tableau d’entiers de 4 éléments
appelé x, et un tableau de caractères de 10 éléments appelé y :

struct data{
int x[4];
char y[10];
};
Vous pouvez ensuite déclarer une structure record appartenant au type data
avec l’instruction : struct data record;

15
Initialisation des structures
Comme tout autre type de variable C, les structures peuvent être
initialisées quand elles sont déclarées. La procédure à suivre est la
même que pour les tableaux. La déclaration est suivie d’un signe égal
puis, entre accolades, d’une liste de valeurs d’initialisation séparées par
des virgules :

struct vente {
char client[20];
char article [20];
float montant;
} mesventes = { "ABC Industries", "PC23",1000.00};

16
Initialisation des structures
(Cas dont les membres sont des struct)

struct client {
char societe[20];
char contact[25];
}

struct vente {
struct client acheteur;
char article[20];
float montant;
} mesventes = { { "ABC Industries", “Adams"}, "PC ",1000.00 };

17
Structures et pointeurs
Les pointeurs membres d’une structure
Un pointeur qui est un membre d’une structure se déclare de la même
façon qu’un pointeur qui ne l’est pas, en utilisant l’opérateur indirect (*) :
struct data {
int *valeur;
int *taux;
} premier;
Initialisation des pointeurs

Ces instructions définissent et déclarent une structure dont les deux


membres sont des pointeurs vers des variables de type int. Cette
déclaration doit être suivie de l’initialisation de ces pointeurs avec les
adresses des variables pointées. Si nous supposons que cout et interet sont
des variables de type int, l’initialisation des pointeurs suit la syntaxe
suivante :
premier.valeur = &cout;
premier.taux = &interet; 18
Initialisation des pointeurs ( chaine
des caractères)
struct msg { Chaque pointeur membre de la
char *p1; structure pointe sur le premier
char *p2; octet d’une chaîne stockée
} myptrs; quelque part en mémoire.
myptrs.p1 = "Le langage C";
myptrs.p2 = "par Pearson Education";

19
Les pointeurs vers des structures
Voici comment un programme peut créer et utiliser des pointeurs vers des
structures. La première étape est la définition de la structure :
struct part {
int nombre;
char nom[10];
};
La seconde est la déclaration d’un pointeur vers une variable de type part.
struct part *p_part;

Pour initialiser le pointeur «p_part » sur une structure, il faut déclarer une
structure de type part avant de pouvoir pointer dessus :

struct part g ; /*(p_part représente l’adresse de la structure g )*/

Cette instruction permet d’initialiser le pointeur : 20


p_part = &g;
Les pointeurs vers des structures

g.nombre g.nom[ ]

p_part p_part = &g;

Un pointeur vers une structure pointe sur le premier octet de cette structure

Pour accéder aux membres de la structure g, on utilise l’opérateur (.)


de cette façon :
(*p_part).nombre = 100;

Les parenthèses sont nécessaires, car l’opérateur (.) est prioritaire


sur l’opérateur (*).
Cette instruction a attribué la valeur 100 au membre g.nombre.
21
Les pointeurs vers des structures

Il existe une autre technique pour accéder aux membres d’une


structure avec le pointeur vers cette structure. Cette technique utilise
l’opérateur d’indirection, représenté par le signe moins suivi du signe
"supérieur à" (–>).

Cet opérateur est placé entre le nom du pointeur et le nom du membre.


Pour accéder au membre nombre de g avec le pointeur
p_part, utilisez la syntaxe suivante : struct part {
int nombre;
p_part –> nombre char nom[10];
};
struct part *p_part;
Au lieu de (*p_part).nombre

22
Pointeurs et tableaux de structures
Reprenons, pour notre démonstration, cette définition de structure :
struct part {
int nombre;
char nom[10];
};

La structure étant définie, nous pouvons déclarer un tableau


appartenant au type part :
struct part data[100];

Nous pouvons ensuite déclarer un pointeur vers une structure de type


part, et l’initialiser pour pointer sur la première structure du tableau data :
struct part *p_part;
p_part = &data[0];

Nous aurions pu écrire la deuxième instruction de cette façon :


p_part = data;

23
Portée du modèle de structure
La "portée" d'un modèle de structure dépend de l'emplacement de sa
déclaration:
si elle se situe au sein d'une fonction (y compris, la "fonction main"), elle
n'est accessible que depuis cette fonction,

si elle se situe en dehors d'une fonction, elle est accessible de toute la


partie du fichier source qui suit sa déclaration; elle peut ainsi être utilisée
par plusieurs fonctions.
struct enreg
Exemple: { int numero ;
int qte ;
float prix ;
};
main ()
{ struct enreg x ;
....
}
fct ( ....)
{ struct enreg y, z ;
....
24
}
Transmission de la valeur d'une structure
Nous avons vu qu'en C la transmission des argument se fait "par valeur", ce qui
implique une recopie de l'information transmise à la fonction. Par ailleurs, il est
toujours possible de transmettre la "valeur d'un pointeur" sur une variable, auquel cas
la fonction peut, si besoin est, en modifier la valeur. Ces remarques s'appliquent
également aux structures

#include <stdio.h>
struct enreg {
int a ;
float b ; void fct (struct enreg s)
}; {
main() s.a = 0; s.b=1;
{ printf ("\ndans fct : %d %e", s.a, s.b);
struct enreg x ; }
void fct (struct enreg y) ;
x.a = 1; x.b = 12.5;
printf ("\navant appel fct : %d %e",x.a,x.b); avant appel fct : 1 1.250000e+001
dans fct : 0 1.000000e+000
fct (x) ;
au retour dans main : 1 1.250000e+001
printf ("\nau retour dans main : %d %e", x.a, x.b);
}
25
Transmission de l'adresse d'une structure :
l'opérateur ->
Cherchons à modifier notre précédent programme pour que la fonction fct
reçoive effectivement l'adresse d'une structure et non plus sa valeur. L'appel de
fct devra donc se présenter sous la forme:
fct (&x) ;
Cela signifie que son en-tête sera de la forme:
void fct (struct enreg * ads) ;
#include <stdio.h>
struct enreg { int a ; void fct (struct enreg * ads)
float b ; {
}; ads->a = 0 ; ads->b = 1;
main() printf ("\ndans fct : %d %e", ads->a, ads->b);
{ }
struct enreg x ;
void fct (struct enreg *) ; avant appel fct : 1 1.250000e+001
x.a = 1; x.b = 12.5; dans fct : 0 1.000000e+000
printf ("\navant appel fct : %d %e",x.a,x.b); au retour dans main : 0 1.000000e+000
fct (&x) ;
printf ("\n au retour dans main : %d %e", x.a, x.b);
26
}
Unions
Une union est un type de données qui permet de stocker des
données de types différents à la même adresse. Par exemple, on
peut définir une union dont les éléments peuvent être soit int soit
float. Dans tous les cas, la variable de ce type union prendra 4
octets en mémoire.
#include <stdio.h>
typedef union data
if (choix == 2)
{ {
int i; scanf("%f", &d.x);
float x; printf("%f", d.x);
}Data; }
return 0;
int main() {
}
Data d;
int choix;
puts("Voulez-vous entrer un entier (1) ou un réel (2) ?");
scanf("%d", &choix);
if (choix == 1)
{ Les types des champs d’une union peuvent être
scanf("%d", &d.i); quelconques, y compris des structures ou des
printf("%d", d.i); 27
pointeurs.
}
Enumération
Une énumération est un type de données qui peut prendre un nombre fini de
valeurs (2, 3,..., 15... valeurs différentes). Les différentes valeurs prises par les
variables d’un type énumération sont des constantes.

Exemple 1.
Dans l’exemple suivant, le type TypeAnimal représente différentes sortes
d’animaux. Toute variable de type TypeAnimal vaut soit SINGE, CHIEN,
ELEPHANT, CHAT ou GIRAFFE.

#include <stdio.h>
/* Déclaration du type enum : */
enum TypeAnimal {SINGE, CHIEN, ELEPHANT, CHAT, GIRAFFE};

/* Exemple de fonction utilisant ce type */


void AffichePropriete(TypeAnimal a)
{
if (a == SINGE || a == ELEPHANT || a == GIRAFFE) puts("Animal sauvage");
if (a == CHIEN || a == CHAT) puts("Animal de compagnie");
}

28
Enumération
Exemple 2.
• un type booléen. Le type booléen peut prendre deux valeurs : vrai
ou faux. Ici, on impose que VRAI vaille 1 et FAUX vaille 0 dans la
définition de l’énumération.
#include <stdio.h>
/* Déclaration du type enum */ void AfficheChoix(Booleen b) {
enum Booleen {FAUX=0, VRAI=1}; if (b)
Booleen SaisieChoix(void) { puts("Le client est d’accord");
else
char choix;
puts("Le client n’est pas d’accord");
puts("Etes-vous d’accord ? (y/n)"); }
choix = getchar();
getchar(); int main(void) {
if (choix == ’y’) Booleen b;
b = SaisieChoix();
return VRAI;
AfficheChoix(b);
else return 0;
return FAUX; }
} 29
Exercice d’application 1

Ecrire un programme de saisie de données pour


un répertoire(nom, prénom et téléphone). Ces
données doivent être placées dans un tableau de
structures, chacune d’elles contenant un
enregistrement. Le programme devra contenir une
fonction d’affichage de toutes les données.

30
Exercice

31

Vous aimerez peut-être aussi