Un type structure
(appelé record dans certains langages) regroupe un ou plusieurs
champs qui peuvent
être de types différents.
Dans une banque, par exemple, un compte est caractérisé par un
numéro, le nom du client, son prénom, son adresse, etc.
L’adresse, elle-même, est composée de plusieurs éléments de
nature différente.
Une structure peut être initialisée (avant la norme ANSI, on ne
pouvait initialiser que des objets structures, externes ou
statiques), soit à partir d’une autres structure de même type, soit en
utilisant un agrégat. Les champs manquants
sont initialisés à 0.
L’opérateur . permet de d’accéder à un champ d’un objet
structure.
struct famille fam3 ;
fam3.nom = "Kerdraon" ;
fam3.nbrenfant = 4 ;
struct compte compte1 ;
compte1.adresse.codepostal = 29200 ; /* en Français, de lit de
droite à gauche */
L’opérateur -> permet d’accéder à un champ d’un objet
structure, via un pointeur sur
l’objet.
struct compte * ptcompte = & compte1 ; /* déclaration d'un
piointeur qui pointe sur le compte compte1. On utilise
l'opérateur & : adresse de */
ptcompte -> adresse.codepostal = 35100 ; /* on modifie
l'adresse postale de l'adresse du compte pointé par ptcompte */
Ces deux lignes sont équivalentes :
(*ptcompte). numero = compte2.numero ; /* (*ptcompte) : l'objet
pointé par ptcompte */
ptcompte -> numero = compte2.numero ;
Exemple de représentation de type
complexe par un type
structure
Les opérations sur les structures
Il n’y a que trois opérations autorisées sur les structures :
Obtenir l’adresse d’une structure avec l’opérateur &
Accéder à un champ d’une
structure avec les opérateurs . et ->
Affecter une structure à une autre (c'est bien une affectation de
valeurs structure, pas d'adresse).
Exemple de passage de structures en paramètres à
des fonctions
On demande d'écrire un programme qui lit les données
(nom, âge et taille) concernant 2 personnes, puis compare
leur âge (Dupont est plus vieux que Dupond), et
fianlement leur taille (Dupont et Dupond ont la même
taille.
struct {int nombre ; int taille ; int compteur} ma_structure ;
Soit dim la taille la taille des entiers, en général 16 bits ou
32 bits.
Les différents champs sont placés
de manière consécutive dans la mémoire dans
l’ordre de leurs déclarations.
Ce type
d’implémentation ne pose pas de réels problèmes. Par contre, il
n’en est pas de même si on déclare des champs avec des
contraintes d’alignement différents.
Le champ le_vecteur
utilise 5 octets. Mais du fait de la contrainte d’alignement pour
les entiers, il n’est pas possible de faire démarrer l’objet
compteur au 6ème octet. 3 octets du deuxième mot ne sont pas
utilisés.
L’implémentation de la structure précédente est :
Soit dim (32 bits) la taille des entiers :
L’existence de ces octets de bourrage explique en partie que la
norme interdit le test d’égalité entre structures.
En partie seulement, car le compilateur aurait
pu utiliser des instructions
manipulant efficacement des blocsmémoire quand il
n’y a pas d’octets de bourrage, et sinon effectuer des
comparaisons champ par champ.