18.02.2014 Views

Les types structures et les pointeurs - Université Paris 8

Les types structures et les pointeurs - Université Paris 8

Les types structures et les pointeurs - Université Paris 8

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

L1 Informatique – Université <strong>Paris</strong> 8 - 2010-2011<br />

Programmation Impérative I<br />

Rim Chaabane rchaabane@ai.univ-paris8.fr - Cours 5 -<br />

<strong>Les</strong> <strong>types</strong> <strong>structures</strong> <strong>et</strong> <strong>les</strong> <strong>pointeurs</strong><br />

1. <strong>Les</strong> <strong>types</strong> <strong>structures</strong><br />

<strong>Les</strong> obj<strong>et</strong>s de type structure est comme un tableau, constitué de la réunion d’un ensemble de<br />

valeurs. Mais à la différence des tableaux, ces valeurs ne sont pas nécessairement de même type.<br />

L’accès à une valeur de la structure ne se fait pas avec l’aide d’indice, mais grâce à son nom.<br />

Le type structure perm<strong>et</strong> de rassembler des informations sous une type que vous aurez créé. Par<br />

exemple vous créez le type Personne qui possède un nom, un prénom <strong>et</strong> un âge. Ou bien un type<br />

Point qui a une abscisse x <strong>et</strong> une ordonnée y.<br />

1.1. Déclaration de structure<br />

Pour définir un type structure personne, composée de trois champs : nom, prenom <strong>et</strong> age, il suffit<br />

d’écrire <strong>les</strong> instructions suivantes :<br />

/* définition du type struct personne */<br />

struct personne { char nom[20], prenom[15];<br />

int age ;<br />

} ;<br />

Attention : le point-virgule est nécessaire après l'accolade fermante de la déclaration de la<br />

structure.<br />

- Personne est le nom du type créé<br />

- Nom, prenom <strong>et</strong> age sont <strong>les</strong> champs de ce type<br />

Nous utilisons ensuite ce type pour déclarer des variab<strong>les</strong> :<br />

/*déclaration de variab<strong>les</strong> mere <strong>et</strong> père de type struct personne */<br />

struct personne mere;<br />

struct personne pere;<br />

/* définition du type struct point */<br />

struct point { float x, y ;<br />

} ;<br />

- point est le nom du type créé<br />

- x <strong>et</strong> y sont <strong>les</strong> champs de ce type<br />

/*déclaration de variab<strong>les</strong> A <strong>et</strong> B de type struct point */<br />

struct point A ;<br />

struct point B ;<br />

1


L1 Informatique – Université <strong>Paris</strong> 8 - 2010-2011<br />

Programmation Impérative I<br />

Rim Chaabane rchaabane@ai.univ-paris8.fr - Cours 5 -<br />

La définition d’un type structure ne peut être précédé du mot clé const. Il faut considérer la<br />

définition d’un type struct comme si vous définissez un nouveau type en C. Tout type en C ne<br />

peut être constant. Par contre une donnée d’un type quelconque peut être déclarée comme<br />

constante. Ainsi, il est autorisé de déclarer des valeurs de type struct comme constantes. Par<br />

exemple :<br />

const struct point A ;<br />

Le type des champs d’une structure :<br />

<strong>Les</strong> champs d’une structure peuvent être :<br />

- de n’importe quel type de base<br />

- des tableaux d’éléments de type quelconque<br />

- des <strong>pointeurs</strong><br />

- des <strong>structures</strong> /!\ une structure peut comporter de champs de son type mais il faut le<br />

déclarer au préalable de c<strong>et</strong>te façon :<br />

typedef struct personne pers ; /* pers est de type struct personne */<br />

struct personne { char nom[20], prenom[15];<br />

int age ;<br />

pers * pere ;<br />

};<br />

Déclaration de variable de type structure :<br />

Il existe trois manières de déclarer des variab<strong>les</strong> de type structure en C :<br />

Première méthode<br />

struct personne{<br />

char nom[20];<br />

char prenom[20];<br />

int no_employe;<br />

};<br />

struct personne p1,p2;<br />

p1=p2 ; /* OK */<br />

Deuxième méthode<br />

struct {<br />

char nom[20];<br />

char prenom[20];<br />

int no_employe;<br />

} p1,p2;<br />

struct{<br />

char nom[20];<br />

char prenom[20];<br />

int no_employe;<br />

} p3;<br />

p3 = p1 ; /* OK */<br />

Troisième méthode<br />

struct personne{<br />

char nom[20];<br />

char prenom[20];<br />

int no_employe;<br />

} p1,p2;<br />

struct personne p3;<br />

p3 = p1 ; /* NOK */<br />

La première méthode, définit un type structure dont le nom est personne. C<strong>et</strong>te structure<br />

contient trois champs : un tableau de caractères pour le champ nom, un tableau de caractères<br />

pour le champ prenom <strong>et</strong> un entier pour le champ no_employe.<br />

Plus loin de c<strong>et</strong>te déclaration, nous déclarons deux variab<strong>les</strong> p1 <strong>et</strong> p2 de type struct<br />

personne.<br />

Avec c<strong>et</strong>te méthode, il est possible d’affecter à p1 la valeur de p2, ces deux variab<strong>les</strong> étant<br />

reconnues comme étant du même type.<br />

2


L1 Informatique – Université <strong>Paris</strong> 8 - 2010-2011<br />

Programmation Impérative I<br />

Rim Chaabane rchaabane@ai.univ-paris8.fr - Cours 5 -<br />

La deuxième méthode définit le même type de structure, sauf que c<strong>et</strong>te fois-ci la structure ne<br />

porte pas de nom <strong>et</strong> est immédiatement suivie des noms de variab<strong>les</strong> p1 <strong>et</strong> p2 de ce type<br />

structure. Si plus loin on écrit la même définition du type de structure (sans nom) suivi d’un nom<br />

de variable p3, alors il nous sera possible d’effectuer des opérations entre p1 ou p2 <strong>et</strong> p3.<br />

La troisième méthode définit un type structure avec le nom personne suivi immédiatement des<br />

noms de variab<strong>les</strong> p1 <strong>et</strong> p2. Dans cas si l’on crée comme à la méthode 1, une troisième variable<br />

p3 de type struct personne, il nous sera impossible d’effectuer une quelconque opération<br />

entre p1 ou p2 <strong>et</strong> p3. Ce dernier n’étant pas reconnu comme étant du même type que p1 <strong>et</strong> p2.<br />

De ces trois méthodes c'est la première qui est recommandée, car elle perm<strong>et</strong> de bien séparer la<br />

définition du type structure de ses utilisations.<br />

1.2. Représentation en mémoire<br />

La norme impose aux obj<strong>et</strong>s de type structure <strong>les</strong> deux contraintes suivantes :<br />

- <strong>les</strong> champs doivent être alloués selon leur ordre d’apparition dans la structure ;<br />

- l’adresse d’une structure correspond à l’adresse de son premier champ.<br />

Ainsi dans <strong>les</strong> définitions suivantes, l’ordre d’apparition des champs est le même :<br />

struct s1 {<br />

int n, p ;<br />

float x, y ;<br />

} ;<br />

struct s1 test ;<br />

struct s2 {<br />

int n ;<br />

int p ;<br />

float x ;<br />

float y;<br />

} ;<br />

@m @m+1 @m+2 @m+3<br />

n p x y<br />

test<br />

1.3. Initialisation<br />

Il existe deux méthodes pour initialiser une variable de type structure :<br />

Première méthode : l’initialisation se fait juste au moment de la déclaration de la variable<br />

de type structure.<br />

Deuxième méthode : l’initialisation se fait après la déclaration de la variable de type<br />

structure.<br />

struct personne{<br />

char nom[20];<br />

char prenom[20];<br />

int no_employe;<br />

};<br />

struct personne p1 = {"Dupond", "Jean", 7845}; /* méthode 1 */<br />

struct personne p2 ;<br />

3


L1 Informatique – Université <strong>Paris</strong> 8 - 2010-2011<br />

Programmation Impérative I<br />

Rim Chaabane rchaabane@ai.univ-paris8.fr - Cours 5 -<br />

p2.nom = " Dupond";<br />

p2.prenom = "Jean" ; /* méthode 2 */<br />

p2.no_employe = 7845 ;<br />

Pour accéder aux champs de la variable p2, il suffit de faire suivre le nom de la variable d’un point<br />

suivi du nom du champ.<br />

Nous déclarons <strong>et</strong> initialisons maintenant un tableau de 3 éléments de type struct<br />

personne :<br />

- Avec la méthode 1 :<br />

struct personne tab[3] = { {"Dupond", "Jean", 7845},<br />

{"Le Notre", "Alfred", 4321},<br />

{"Le Gall", "Marc", 5678}} ;<br />

- Ou bien nous l’initialisons avec la méthode 2 :<br />

struct personne tab[3] ;<br />

tab[0].nom = "Dupond";<br />

tab[0].prenom = "Jean";<br />

tab[0].no_employe = 7845;<br />

tab[1].nom = "Le Notre";<br />

tab[1].prenom = "Alfred";<br />

tab[1].no_employe = 1234;<br />

tab[2].nom = "Le Gall";<br />

tab[2].prenom = "Marc";<br />

tab[2].no_employe = 5678;<br />

Nous pouvons, alors noter qu’il est plus simple d’initialiser un tableau de <strong>structures</strong> avec la<br />

première méthode. La seconde méthode est plutôt préconisée dans le cas ou <strong>les</strong> données du<br />

tableau ne sont pas connues en début de programme. Exemple : le programme lit <strong>les</strong> données du<br />

tableau de <strong>structures</strong> à partir d’un fichier de données.<br />

Pour initialiser une variable de type structure, il n’est pas nécessaire de renseigner tous <strong>les</strong> champs<br />

de la structure. Par exemple :<br />

struct personne tab[3] = { {"Dupond", "Jean", 7845}, /* Correct */<br />

{"Le Notre",}, /* Correct */<br />

/* le troisième élément du<br />

tableau n’apparait pas mais<br />

étant donné que c’est le dernier<br />

son absence ne gêne pas la<br />

compilation */<br />

};<br />

Il est également possible d’affecter une valeur de structure à une autre, exemple :<br />

struct personne p1, p2 = {"Dupond", "Jean", 7845};<br />

p1=p2 ;<br />

1.4. Exemple d’utilisation<br />

4


L1 Informatique – Université <strong>Paris</strong> 8 - 2010-2011<br />

Programmation Impérative I<br />

Rim Chaabane rchaabane@ai.univ-paris8.fr - Cours 5 -<br />

2. Introduction à la notion de pointeur<br />

<strong>Les</strong> <strong>pointeurs</strong> perm<strong>et</strong>tent de manipuler directement <strong>les</strong> adresses mémoire des obj<strong>et</strong>s crées ; tels<br />

que <strong>les</strong> variab<strong>les</strong>, <strong>les</strong> <strong>pointeurs</strong> ou encore <strong>les</strong> <strong>structures</strong>.<br />

Soit <strong>les</strong> déclarations suivantes :<br />

int n, t[5] ;<br />

n est une variable de type int <strong>et</strong> t est un tableau de 5 éléments de type int.<br />

Pour obtenir l’adresse de la variable n ou du tableau t il suffit de faire précéder le nom de<br />

l’obj<strong>et</strong> par un & :<br />

&n ;<br />

&t ;<br />

Un pointeur en C contient l’adresse mémoire d’un obj<strong>et</strong>. Pour déclarer par exemple un pointeur<br />

sur l’adresse mémoire de la variable n il suffit d’écrire :<br />

int *pn ; /* on dit que pn est le pointeur sur un obj<strong>et</strong> de type int */<br />

ou<br />

int * pn ;<br />

Il peut donc aussi bien contenir l’adresse de la variable n (qui est destinée à contenir un int)<br />

que l’adresse d’un élément du tableau t comme par exemple &t[2]:<br />

pn = &n ;<br />

ou<br />

5


L1 Informatique – Université <strong>Paris</strong> 8 - 2010-2011<br />

Programmation Impérative I<br />

Rim Chaabane rchaabane@ai.univ-paris8.fr - Cours 5 -<br />

pn=&t[2] ;<br />

Nous initialisons donc de c<strong>et</strong>te façon une variable de type pointeur avec des adresses mémoire<br />

d’obj<strong>et</strong>s de <strong>types</strong> int.<br />

Pour accéder au contenu d’une adresse mémoire, il faut faire appel au pointeur précédé d’une<br />

étoile comme ci-dessous :<br />

*pn = 20 ; /* on place l’entier 20 dans l’adresse mémoire contenue dans pn */<br />

Instruction C description Valeur Résultat<br />

contenue<br />

dans @m<br />

int n = 3; Réserve une adresse 3<br />

mémoire @m qui<br />

contient l’entier 3.<br />

int * pn ; Déclare un pointeur pn 3<br />

sur un entier.<br />

pn = &n ;<br />

Initialise le pointeur pn 3 pn = @m<br />

à l’adresse de n.<br />

int l = *pn ; La variable l prend 3 l = 3<br />

comme valeur le<br />

contenu de l’adresse<br />

pointée par pn.<br />

*pn = 9 ;<br />

L’adresse pointée par 9 pn = @m<br />

pn contient<br />

n = 9<br />

*(@m)= 9<br />

printf("%d\n",<br />

*pn) ;<br />

maintenant la valeur 9.<br />

Affiche le contenu de<br />

@m<br />

Affectation de pointeur :<br />

9 9<br />

p=NULL ; //on crée un pointeur vide qui ne contient aucune adresse<br />

mémoire<br />

p = q ; //p <strong>et</strong> q pointent sur le même obj<strong>et</strong><br />

*p = *q ; //l’adresse pointée par p contiendra l’obj<strong>et</strong> pointé par q<br />

if (p==q) {…} // si p <strong>et</strong> q pointent sur le même obj<strong>et</strong>…<br />

if (p !=q) {…} //si p <strong>et</strong> q ne pointent pas sur le même obj<strong>et</strong>…<br />

p+1 ; //pointe sur l’obj<strong>et</strong> suivant de type t (idem pour p++).<br />

p-q ;<br />

//r<strong>et</strong>ourne le nombre d’obj<strong>et</strong>s de type pointé entre <strong>les</strong><br />

adresses pointées par p <strong>et</strong> q.<br />

6

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!