Les Pointeurs en Langage C

Page 1 sur 9Lecteur de document UniversityLib

Les Pointeurs en Langage C

Informatique Appliquée · course

Voir tous les documents en programmation

École Supérieure de Technologie

et d’Informatique

A.U. 2011/2012

Cours programmation en langage C

Chapitre 6 : Les pointeurs (9 pages)

Informatique Appliquée 1ère année

1. Adressage direct

Dans la programmation, nous utilisons des variables pour stocker des informations. La

valeur d'une variable se trouve à un endroit spécifique dans la mémoire interne de

l'ordinateur. Le nom de la variable nous permet alors d'accéder directement à cette valeur.

Adressage direct: Accès au contenu d'une variable par le nom de la variable.

int a=10 ;

printf(« %d »,a) ; // affichage : 10

printf(« %p »,&a) ; // affichage : F800

a

10

F800

2. Adressage indirect

Si nous ne voulons ou ne pouvons pas utiliser le nom d'une variable a, nous pouvons copier

l'adresse de cette variable dans une variable spéciale p, appelée pointeur. Ensuite, nous

pouvons retrouver l'information de la variable a en passant par le pointeur p.

Adressage indirect: Accès au contenu d'une variable, en passant par un pointeur qui

contient l'adresse de la variable.

Exemple

Soit a une variable contenant la valeur 10 et q un pointeur qui contient l'adresse de a. En

mémoire, a et q peuvent se présenter comme suit:

int a=10 ;

int *q ;

q=&a ;

q

q pointe sur a

F802H

F400H

printf(« %d »,a) ; => 10

printf(« %p », &a) ; => F802H

printf(« %p », q) ; => F802H

printf(« %p », &q) ; => F400H

printf(« %d », *q) ; => 10

lorsque q pointe sur a, alors (*q ) (cid:1) a

a

10

F802H

Mme Wiem Yaiche Elleuch

les pointeurs

Page 1

Définition: Pointeur

Un pointeur est une variable spéciale qui contient l'adresse d'une autre variable.

En C, chaque pointeur est limité à un type de données. Il peut contenir l'adresse d'une

variable simple de ce type ou l'adresse d'une composante d'un tableau de ce type.

Si un pointeur q contient l'adresse d'une variable a, on dit que 'q pointe sur a'.

Remarque

Les pointeurs et les noms de variables ont le même rôle: Ils donnent accès à un

emplacement dans la mémoire interne de l'ordinateur. Il faut quand même bien faire la

différence:

  • Un pointeur est une variable qui peut 'pointer' sur différentes adresses.
  • Le nom d'une variable reste toujours lié à la même adresse.

3. Les opérateurs de base

Lors du travail avec des pointeurs, nous avons besoin

  • d'un opérateur 'adresse de' : & pour obtenir l'adresse d'une variable.
  • d'un opérateur 'contenu de': * pour accéder au contenu d'une adresse.
  • d'une syntaxe de déclaration pour pouvoir déclarer un pointeur.

L'opérateur 'adresse de' : &

&<NomVariable> fournit l'adresse de la variable <NomVariable>

L'opérateur & nous est déjà familier par la fonction scanf, qui a besoin de l'adresse de ses

arguments pour pouvoir leur attribuer de nouvelles valeurs.

Exemple

int n;

printf("donner un nombre entier : ");

scanf("%d", &n);

Attention !

L'opérateur & peut seulement être appliqué à des objets qui se trouvent dans la mémoire

interne, c.-à-d. à des variables et des tableaux. Il ne peut pas être appliqué à des constantes

ou des expressions.

L'opérateur 'contenu de' : *

*<NomPointeur> désigne le contenu de l'adresse référencée par le pointeur <NomPointeur>

Déclaration d'un pointeur

<Type> *<NomPointeur> ; déclare un pointeur <NomPointeur> qui peut recevoir des

adresses de variables du type <Type>

Remarque

Lors de la déclaration d'un pointeur en C, ce pointeur est lié explicitement à un type de

données. Ainsi, la variable q déclarée comme pointeur sur int ne peut pas recevoir l'adresse

d'une variable d'un autre type que int.

4. Les opérations élémentaires sur pointeurs

En travaillant avec des pointeurs, nous devons observer les règles suivantes:

Priorité de * et &

Mme Wiem Yaiche Elleuch

les pointeurs

Page 2

• Les opérateurs * et & ont la même priorité que les autres opérateurs unaires (la

négation !, l'incrémentation ++, la décrémentation --). Dans une même expression,

les opérateurs unaires *, &, !, ++, -- sont évalués de droite à gauche.

• Si un pointeur P pointe sur une variable X, alors *P peut être utilisé partout où on

peut écrire X.

Exemple

Après l'instruction P = &X;

Publicité

les expressions suivantes, sont équivalentes:

Y = *P+1

Y = X+1

P = P+10

X = X+10

*P += 2

X += 2

++*P

++X

(*P)++

X++

Dans le dernier cas, les parenthèses sont nécessaires:

On peut uniquement affecter des adresses à un pointeur.

Les pointeurs sont aussi des variables et peuvent être utilisés comme telles. Soit P1 et P2

deux pointeurs sur int, alors l'affectation

P1 = P2;

copie le contenu de P2 vers P1. P1 pointe alors sur le même objet que P2.

5. Pointeurs et tableaux

En C, il existe une relation très étroite entre tableaux et pointeurs. Ainsi, chaque opération

avec des indices de tableaux peut aussi être exprimée à l'aide de pointeurs. En général, les

versions formulées avec des pointeurs sont plus compactes et plus efficientes.

Adressage des composantes d'un tableau

Le nom d'un tableau représente l'adresse de son premier élément. En d'autre termes:

&tableau[0] et tableau sont une seule et même adresse.

En simplifiant, nous pouvons retenir que le nom d'un tableau est un pointeur constant sur

le premier élément du tableau.

int tab[5]={11,12,13,14,15} ;

tab[i] (cid:1) *(tab+i)

&tab[i] (cid:1) (tab+i)

tab

11

12

13

14

15

F800

F810

F820

F830

F840

indice

0

1

2

3

4

Dans cet exemple :

tab (cid:1) tab+0 (cid:1) &tab[0] : F800

tab+1 (cid:1) &tab[1] : F810

tab+2 (cid:1) &tab[2] : F820

tab+3 (cid:1) &tab[3] : F830

tab+4 (cid:1) &tab[4] : F840

tab (cid:1) (tab+0) (cid:1) tab[0] : 11

*(tab+1) (cid:1) tab[1] : 12

*(tab+2) (cid:1) tab[2] : 13

*(tab+3) (cid:1) tab[3] : 14

*(tab+4) (cid:1) tab[4] : 15

&tab[i] (cid:1)(cid:1)(cid:1)(cid:1) (tab+i)

tab[i] (cid:1)(cid:1)(cid:1)(cid:1) *(tab+i)

Mme Wiem Yaiche Elleuch

les pointeurs

Page 3

ATTENTION

Dans les exemples ci-dessus, tab n’a pas changé de valeur (sa valeur est toujours F800).

Exemple 2 : utilisation d’un tableau tab et d’un pointeur q

int tab[5]={11,12,13,14,15} ;

int *q ;

q=tab ;

q

F800

tab

11

12

13

14

15

F800

0

F810

1

F820

F830

F840

2

3

4

q (cid:1)(cid:1)(cid:1)(cid:1) &tab[0] (cid:1)(cid:1)(cid:1)(cid:1) tab+0 (cid:1)(cid:1)(cid:1)(cid:1) tab :F800

*q : 11

q+1 : F810 // q pointe toujours sur la case d’indice 0

*(q+1) : 12

q+4 : F840 // q pointe toujours sur la case d’indice 0

*(q+4) : 15

Publicité

Exemple 3

int tab[5]={11,12,13,14,15} ;

int *q ;

q=tab+2 ;

q

F820

tab

11

12

13

14

15

F800

0

F810

1

F820

F830

F840

2

3

4

q :F820

*q : 13

q+1 : F830 // q pointe toujours sur la case d’indice 2

*(q+1) : 14

q-2 : F800 // q pointe toujours sur la case d’indice 2

*(q-2) : 11

Exemple 4

int tab[5]={11,12,13,14,15} ;

int *q ;

q=tab ;

q++ ;

q

F810

tab

11

12

13

14

15

F800

0

F810

1

F820

F830

F840

2

3

4

Mme Wiem Yaiche Elleuch

les pointeurs

Page 4

q :F810

*q : 12

q+1 : F820 // q pointe toujours sur la case d’indice 1

*(q+1) : 13

q-1 : F800 // q pointe toujours sur la case d’indice 1

*(q-1) : 11

Exemple 5 : Dans les exemples suivants, q pointe sur les différentes cases du tableau.

int tab[5]={11,12,13,14,15} ;

int *q ;

q=tab ;

q :F810

q++ ;

q

F810

q

F810

q :F810

q+=3 ; (cid:1)(cid:1)(cid:1)(cid:1) q=q+3 ;

q

F810

q :F810

q-=2 ; (cid:1)(cid:1)(cid:1)(cid:1) q=q-2 ;

q

F810

tab

11

12

13 14 15

F800

0

F810

1

F820

F830

F840

2

3

4

Publicité

tab

11

12

13 14 15

F800

0

F810

1

F820

F830

F840

2

3

4

tab

11

12

13 14 15

F800

0

F810

1

F820

F830

F840

2

3

4

tab

11

12

13 14 15

F800

0

F810

1

F820

F830

F840

2

3

4

Mme Wiem Yaiche Elleuch

les pointeurs

Page 5

Résumé

En déclarant un tableau tab de type int et un pointeur q sur int,

int tab[10];

int *q;

l'instruction:

q = tab; est équivalente à q = &tab[0];

Si q pointe sur une composante quelconque d'un tableau, alors q+1 pointe sur la composante

suivante. Plus généralement,

q+i pointe sur la i-ième composante après q et

q-i pointe sur la i-ième composante avant q.

Ainsi, après l'instruction,

q = tab;

le pointeur q pointe sur tab[0], et

*(q+1) désigne le contenu de tab[1]

*(q+2) désigne le contenu de tab[2]

...

*(q+i) désigne le contenu de tab[i]

...

Remarque

q+i n'adresse pas le i-ième octet après q, mais la i-ième composante après q.

En C, le compilateur peut calculer automatiquement l'adresse de l'élément q+i en ajoutant à

q la grandeur d'une composante multipliée par i. Ceci est possible, parce que:

  • chaque pointeur est limité à un seul type de données, et
  • le compilateur connaît le nombre d'octets des différents types.

Exemple

Soit A un tableau contenant des éléments du type float et P un pointeur sur float:

float tab[20], X;

float *q;

Après les instructions,

q = tab;

X = *(q+9);

X contient la valeur du 10-ième élément de tab, (c.-à-d. celle de tab[9]). Une donnée du

type float ayant besoin de 4 octets, le compilateur obtient l'adresse q+9 en ajoutant 9 * 4 =

36 octets à l'adresse dans q.

Attention !

Il existe toujours une différence essentielle entre un pointeur et le nom d'un tableau:

  • Un pointeur est une variable, donc des opérations comme q = tab ou q++ sont permises.
  • Le nom d'un tableau est une constante, donc des opérations comme tab = q ou tab++ sont

impossibles.

6. Formalisme tableau et formalisme pointeur

Il est facile de 'traduire' un programme écrit à l'aide du 'formalisme tableau' dans un

programme employant le 'formalisme pointeur'.

Mme Wiem Yaiche Elleuch

les pointeurs

Page 6

Exemple

programme de remplissage et d’affichage d’un tableau d’entiers

#include <stdio.h>

void main ( )

Publicité

{

int tab[50];

int i,n;

printf("saisir la taille du tableau ");

scanf("%d", &n);

for (i=0; i<n; i++)

scanf("%d", &tab[i]);

for (i=0; i<n; i++)

printf("l'element d'indice %d est %d \n",i, tab[i]);

}

Nous pouvons remplacer systématiquement la notation tab [i] par *(tab + i), ce qui conduit

à ce programme:

Formalisme pointeur

#include <stdio.h>

void main ( )

{

int tab[50];

int i,n;

printf("saisir la taille du tableau ");

scanf("%d", &n);

for (i=0; i<n; i++)

scanf("%d", tab+i);

for (i=0; i<n; i++)

printf("l'element d'indice %d est %d \n",i, *(tab+i));

}

7. Arithmétique des pointeurs

Comme les pointeurs jouent un rôle si important, le langage C soutient une série

d'opérations arithmétiques sur les pointeurs. Le confort de ces opérations en C est basé sur

le principe suivant:

Toutes les opérations avec les pointeurs tiennent compte automatiquement du type et de

la grandeur des objets pointés.

  • Affectation par un pointeur sur le même type

Soient P1 et P2 deux pointeurs sur le même type de données, alors l'instruction

P1 = P2;

fait pointer P1 sur le même objet que P2

  • Addition et soustraction d'un nombre entier

Si P pointe sur l'élément A[i] d'un tableau, alors

P+n pointe sur A[i+n]

Mme Wiem Yaiche Elleuch

les pointeurs

Page 7

P-n pointe sur A[i-n]

  • Incrémentation et décrémentation d'un pointeur

Si P pointe sur l'élément A[i] d'un tableau, alors après l'instruction

P++; P pointe sur A[i+1]

P+=n; P pointe sur A[i+n]

P--; P pointe sur A[i-1]

P-=n; P pointe sur A[i-n]

Domaine des opérations

L'addition, la soustraction, l'incrémentation et la décrémentation sur les pointeurs sont

seulement définies à l'intérieur d'un tableau. Si l'adresse formée par le pointeur et l'indice

sort du domaine du tableau, alors le résultat n'est pas défini.

Exemples

int A[10];

int *P;

P = A+9; / dernier élément -> légal /

P = A+11; / dernier élément + 2 -> illégal /

P = A-1; / premier élément - 1 -> illégal /

  • Soustraction de deux pointeurs

Soient P1 et P2 deux pointeurs qui pointent dans le même tableau:

P1-P2 fournit le nombre de composantes comprises entre P1 et P2.

Le résultat de la soustraction P1-P2 est

  • négatif, si P1 précède P2
  • zéro,
  • positif, si P2 precède P1
  • indéfini, si P1 et P2 ne pointent pas dans le même tableau

si P1 = P2

Plus généralement, la soustraction de deux pointeurs qui pointent dans le même tableau est

équivalente à la soustraction des indices correspondants.

  • Comparaison de deux pointeurs

On peut comparer deux pointeurs par <, >, <=, >=, ==, !=.

La comparaison de deux pointeurs qui pointent dans le même tableau est équivalente à la

comparaison des indices correspondants. (Si les pointeurs ne pointent pas dans le même

tableau, alors le résultat est donné par leurs positions relatives dans la mémoire).

Programme de remplissage et d’affichage d’un tableau, en utilisant un pointeur q

#include <stdio.h>

void main ( )

{

int tab[50];

int i,n, *q;

printf("saisir la taille du tableau ");

scanf("%d", &n);

Mme Wiem Yaiche Elleuch

les pointeurs

Page 8

for (q=tab; q<tab+n; q++)

scanf("%d", q);

for (q=tab; q<tab+n; q++)

printf("l'element d'indice %d est %d \n",i, *q);

}

Mme Wiem Yaiche Elleuch

les pointeurs

Page 9