Nous avons utilisé des tableaux pour désigner, avec un nom unique, un ensemble de variables. Par exemple, un tableau T à n éléments est un ensemble n de variables désignées par la lettre T. Dans un tableau, les variables doivent être de type homogène, cela signifiant qu’il n’est pas possible de juxtaposer des char et des int dans un tableau. Lorsque l’on souhaite faire cohabiter dans une variable non scalaire des types hétérogènes, on utilise des structures.
Une structure, appelé enregistrement dans d’autres langages, est une variable contenant plusieurs variables, appelées champs. Si une structure t contient un char et un int, chacun de ces champs portera un nom, par exemple i et c. Dans ce cas, t.c désignera le char de t et t.i l’int de t.
Pour créer un type structuré, on utilise la syntaxe suivante :
struct nomdutype { typechamp_1 nomchamp_1; typechamp_2 nomchamp_2; ... typechamp_n nomchamp_n; };
On précise donc le nom de ce type structuré, et entre les accolades, la liste des champs avec pour chacun d’eux son type. Vous remarquez que le nombre de champs est fixé d’avance. On n’accède pas à un champ avec un indice mais avec un nom. Considérons par exemple le type structuré suivant :
struct point { double abs; double ord; };
Ce type permet de représenter un point dans R2, avec respectivement uns abscisse et une ordonnée. struct point est maintenant un type, il devient possible de déclarer un point p comme tout autre variable :
struct point p;
On accède aux champs d’une variable structurée à l’aide de la notation pointée
nomvariable.nomduchamp
Ainsi, le champ ord de notre variable p sera accessible avec p.ord et le champ abs de notre variable p sera accessible avec p.abs. Voici un exemple de programme illustrant ce principe :
#include<stdio.h> struct point { double abs; double ord; }; main() { struct point p; p.ord = 2; p.abs = p.ord + 1; printf("p = (%f, %f)\n", p.abs, p.ord); }
Ce programme affiche :
p = (3.000000, 2.000000)
Attention, l’opérateur d’accès au champ
.
est prioritaire sur
tous les autres opérateurs unaires, binaires et ternaires ! Il faudra
vous en rappeler quand on étudiera les listes chaînées.
Typedef
On se débarasse du mot clé struct en renommant le type, on utilisera par exemple la syntaxe suivante :
#include<stdio.h> typedef struct point { double abs; double ord; }point; main() { point p; p.ord = 2; p.abs = p.ord + 1; printf("p = (%f, %f)\n", p.abs, p.ord); }
point est donc le nom de ce type structuré.
Rien de nous empêche de créer des tableaux de structures, par exemple :
#include<stdio.h> #define N 10 typedef struct point { double abs; double ord; }point; main() { point p[N]; int i; p[0].ord = 0; p[0].abs = 1; for(i = 1 ; i < N ; i++) { p[i].ord = p[i - 1].ord + 1.; p[i].abs = p[i - 1].abs + 2.; } for(i = 0 ; i < N ; i++) { printf("p[%d] = (%f, %f)\n", i, p[i].abs, p[i].ord); } }
Ce programme affiche :
p[0] = (1.000000, 0.000000) p[1] = (3.000000, 1.000000) p[2] = (5.000000, 2.000000) p[3] = (7.000000, 3.000000) p[4] = (9.000000, 4.000000) p[5] = (11.000000, 5.000000) p[6] = (13.000000, 6.000000) p[7] = (15.000000, 7.000000) p[8] = (17.000000, 8.000000) p[9] = (19.000000, 9.000000)
Lorsqu’on les passe en paramètre, les structures se comportent comme des variables scalaires, cela signifie qu’on ne peut les passer en paramètre que par valeur. Par contre, un tableau de structures est nécessairement passé en paramètre par référence. Réecrivons le programme précédent avec des sous-programmes :
#include<stdio.h> #define N 10 typedef struct point { double abs; double ord; }point; void initTableauPoints(point p[], int n) { int i; p[0].ord = 0; p[0].abs = 1; for(i = 1 ; i < n ; i++) { p[i].ord = p[i - 1].ord + 1.; p[i].abs = p[i - 1].abs + 2.; } } void affichePoint(point p) { printf("(%f, %f)", p.abs, p.ord); } void afficheTableauPoints(point p[], int n) { int i; for(i = 0 ; i < n ; i++) { printf("p[%d] = ", i); affichePoint(p[i]); printf("\n"); } } main() { point p[N]; initTableauPoints(p, N); afficheTableauPoints(p, N); }
Comme une structure se comporte comme une variable scalaire, il est possible de retourner une structure dans une fonction, il est donc possible de modifier le programme ci-avant de la sorte :
#include<stdio.h> #define N 10 typedef struct point { double abs; double ord; }point; point nextPoint(point previous) { point result; result.ord = previous.ord + 1.; result.abs = previous.abs + 2.; return result; } void initTableauPoints(point p[], int n) { int i; p[0].ord = 0; p[0].abs = 1; for(i = 1 ; i < n ; i++) p[i] = nextPoint(p[i - 1]); } void affichePoint(point p) { printf("(%f, %f)", p.abs, p.ord); } void afficheTableauPoints(point p[], int n) { int i; for(i = 0 ; i < n ; i++) { printf("p[%d] = ", i); affichePoint(p[i]); printf("\n"); } } main() { point p[N]; initTableauPoints(p, N); afficheTableauPoints(p, N); }