Travaux dirigés 5

  • Allocation mémoire
  • Structures
  • Pointeurs et structures


Rappels de cours

Lorsqu'on déclare int *p; on déclare un pointeur vers un entier, c'est-à-dire que p contient l'adresse de la zone mémoire oł est stocké cet entier.

Par exemple, la séquence suivante :
int v,*p;
v = 5;
p = &v;
peut avoir la représentation suivante en mémoire (en supposant que l'adresse de v est 30 et que l'adresse de p est 10) :

adresse   contenu
     
...   ...
&p=10   p=&v=30
...   ...
p=&v=30   *p=v=5
...   ...

Allocation "dynamique" de la mémoire

La réservation "dynamique" de la mémoire s'effectue grâce aux fonctions suivantes :

Attention : ne jamais libérer une zone mémoire déjà libérée. Le système pourrait alors générer des erreurs de nature imprévisible.

Structures

Une structure est un ensemble de variables de types éventuellement différents adapté à une gestion spécifique des données.

Définition d'une structure

Par exemple, pour gérer les coordonnées d'un point en abscisse et ordonnée, on pourra créer la structure suivante :

struct point {
int x;
int y;
};

Attention : le point-virgule est nécessaire après l'accolade fermante de la déclaration de la structure.

Déclaration d'une variable de type structure

Exemple :

struct point pt; /* Le type de la variable pt est struct point */

Initialisation d'un tableau à la déclaration

Un tableau peut être initialisé au moment de sa déclaration en indiquant la liste de ses valeurs.

Exemples :

Initialisation d'une structure

Pour initialiser la variable pt de type struct point déclarée précédemment, on peut utiliser la syntaxe suivante :

pt.x = 20;
pt.y = 30;

Il est également possible d'initialiser une structure au moment de sa déclaration, en donnant la liste des valeurs de ses champs, de la même manière que pour un tableau. En reprenant l'exemple précédent, au moment de déclarer la variable pt, on peut écrire :

struct point pt={20,30};

ATTENTION : Ce type d'initialisation n'est correct qu'au moment de la déclaration d'une variable. Il ne peut pas être utilisé ailleurs dans un programme.


Exercice 1

Définir une structure permettant de gérer une adresse du type :
nom, prénom, numéro de rue, nom de rue, code postal, ville.
Déclarer une variable ayant pour type cette structure et demander à l'utilisateur de l'initialiser.


Pointeurs et structures

Priorité des éléments syntaxiques

L'opérateur '.' est prioritaire sur l'opérateur '*'.

Exemple :

struct point pt,*pp;
pp = &pt;

On a alors les identités suivantes :

(*pp).x == pt.x et (*pp).y == pt.y

Par contre, l'identité *pp.x == pt.x est illégale puisqu'elle est équivalente à *(pp.x)==pt.x et que pt.x n'est pas un pointeur.

On peut utiliser une notation permettant d'éviter les confusions :

p->a : "contenu du champ a de la structure pointée par p"

Exemple : pp->x == (*pp).x

Conformément à l'exemple ci-dessus, pt.x est une notation correcte, mais pt->x ne l'est pas (pt n'est pas un pointeur vers une structure).

Listes chaînées

Une liste chaînée est composée d'éléments de type structure reliés entre eux par des pointeurs.

Par exemple, on peut choisir de représenter une courbe par une liste de points :

struct courbe {
struct point pt;
struct courbe *suivant;
};


Exercice 2

Soit trois points p1, p2 et p3 de coordonnées respectives (10,20), (30,20), (20,10). Donner l'initialisation du triangle construit à partir de p1,p2,p3 en initialisant trois variables (respectivement c1,c2 et c3) du type "struct courbe" défini précédemment.

Questions complémentaires :

  1. A partir de c1, et en utilisant les pointeurs, donner la valeur de l'abcisse du troisième point.
  2. Que valent :
    a. (*(*c1.suivant).suivant).pt.x
    b. c3.suivant->suivant.pt.x
    c. (*c2.suivant).suivant->pt.x

Représentation en mémoire

Afin de donner une représentation de la manière dont les structures sont liées les unes aux autres dans la mémoire centrale d'un ordinateur lors de l'exécution d'un programme, on produit un graphique respectant les conventions suivantes :

Exemples :

représentation de structures chaînées


Exercice 3

Soit le programme suivant :

#include "stdio.h"

struct s1 {
char c[4];
char *s;
};

struct s1 st1 = {"abc","def"};

struct s2 {
char *cp;
struct s1 ss1;
} st2 = {"ghi",{"jkl","mno"}};

main()
{
printf("%c %c\n",st1.c[0],*st1.s);
printf("%s %s\n",st1.c, st1.s);
printf("%s %s\n",st2.cp,st2.ss1.s);
st2.cp=st2.cp+1;
st2.ss1.s=st2.ss1.s+1;
printf("%s %s\n",st2.cp,st2.ss1.s);
}

Donner la représentation des données dans la mémoire centrale et les résultats affichés sur stdout.


Exercice 4

Soit le programme suivant :

#include "stdio.h"

struct s1 {
char *s;
int i;
struct s1 *s1p;
};

struct s1 a[3] = {{"abcd",1,a+1},{"efgh",2,a+2},{"ijkl",3,a}};

main()
{
struct s1 *p = a;
printf("%s %s %s\n", a[0].s, p->s, a[2].s1p->s);
}

Donner les résultats affichés sur stdout et la représentation des données dans la mémoire centrale.


Ces pages ont été adaptées à partir de celles réalisées par J.D. Durou et Ph. Joly avec leur aimable autorisation.