Chapitre II
Les pointeurs
1
1. L’importance des pointeurs
On peut accéder aux données en mémoire à l’aide de pointeurs i.e.
des variables pouvant contenir des adresses d’autres variables.
Comme nous le verrons dans le chapitre suivant, en C, les pointeurs
jouent un rôle primordial dans la définition de fonctions :
Les pointeurs sont le seul moyen de changer le contenu
de variables déclarées dans d’autres fonctions.
Le traitement de tableaux et de chaînes de caractères dans des
fonctions serait impossible sans l’utilisation de pointeurs.
Les pointeurs nous permettent de définir de nouveaux types de
données : les piles, les files, les listes, ....
Les pointeurs nous permettent d’écrire des programmes plus
compacts et plus efficaces.
Mais si l’on n’y prend pas garde, les pointeurs sont une excellente
technique permettant de formuler des programmes
incompréhensibles.
2
2. Mode d’adressage direct des variables
Adressage direct :
Jusqu’à maintenant, nous avons surtout utilisé des variables pour stocker
des informations.
La valeur d’une variable se trouve à un endroit spécifique dans la mémoire
de l’ordinateur.
A
short A;
A = 10; ... 10 ... ...
Adresse : 1E04 1E06 1E08 1E0A
Le nom de la variable nous permet alors d’accéder directement à cette
valeur.
Dans l’adressage direct, l’accès au contenu d’une variable se fait via
le nom de la variable.
3
1. Mode d’adressage indirect des variables
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,
disons P, appelée pointeur.
Nous pouvons alors retrouver l’information de la variable A en passant par
le pointeur P.
Dans l’adressage indirect, l’accès au contenu d’une variable se fait via
un pointeur qui renferme l’adresse de la variable.
Exemple : Soit A une variable renfermant la valeur 10, et P un pointeur qui
contient l’adresse de A. En mémoire, A et P peuvent se présenter
comme suit :
4
3. Définition d’un pointeur
Un pointeur est une variable spéciale pouvant contenir
l’adresse d’une autre variable.
En C, chaque pointeur est limité à un type de données. Il ne peut contenir que
l’adresse d’une variable de ce type. Cela élimine plusieurs sources d’erreurs.
Syntaxe permettant de déclarer un pointeur :
type de donnée * identificateur de variable pointeur;
Ex. : int * pNombre; pNombre désigne une variable pointeur pouvant contenir
uniquement l’adresse d’une variable de type int.
Si pNombre contient l’adresse d’une variable entière A,
on dira alors que pNombre pointe vers A.
Les pointeurs et les noms de variables ont le même rôle : ils donnent accès
à un emplacement en mémoire.
Par contre, un pointeur peut contenir différentes adresses mais le nom d’une
variable (pointeur ou non) reste toujours lié à la même adresse.
Bonne pratique de programmation : choisir des noms de variable appropriés
(Ex. : pNombre, NombrePtr). 5
3.1 Comment obtenir l’adresse d’une variable ?
Pour obtenir l’adresse d’une variable, on utilise l’opérateur & précédant le
nom de la variable.
Syntaxe permettant d’obtenir l’adresse d’une variable :
& nom de la variable
Ex. : int A; ou encore, int A;
int * pNombre = &A; int * pNombre;
pNombre = &A;
pNombre désigne une variable pointeur initialisée
à l’adresse de la variable A de type int.
Ex. : int N;
printf("Entrez un nombre entier : ");
scanf("%d", &N);
scanf a besoin de l’adresse de chaque paramètre
pour pouvoir lui attribuer une nouvelle valeur.
Note : L’opérateur & ne peut pas être appliqué à des constantes ou des expressions.
6
3.2 Comment accéder au contenu d’une adresse ?
Pour avoir accès au contenu d’une adresse, on utilise l’opérateur * précédant
le nom du pointeur.
Syntaxe permettant d’avoir accès au contenu d’une adresse :
* nom du pointeur
Ex. : int A = 10, B = 50;
int * P;
P = &A;
B = *P;
*P = 20;
*P et A désigne le même emplacement mémoire et *P peut être utilisé
partout où on peut écrire A.
7
3.3 Priorité des opérateurs * et &
Ces 2 opérateurs ont la même priorité que les autres opérateurs unaires
(!, ++, --).
Dans une même expression, les opérateurs unaires *, &, !, ++, -- sont
évalués de droite à gauche.
Parenthèses
obligatoires sans quoi, cela donne lieu à un accès non autorisé.
8
3.4 Le pointeur NULL
Pour indiquer qu’un pointeur pointe nulle part, on utilise l’identificateur NULL
(On doit inclure stdio.h ou iostream.h).
On peut aussi utiliser la valeur numérique 0 (zéro).
int * P = 0;
if (P == NULL) printf("P pointe nulle part");
9
En résumé
A == *P P == &A
A == *&A et P == &*P
10
4. Pointeurs et tableaux
Chaque opération avec des indices de tableaux peut aussi être exprimée à
l’aide de pointeurs.
Comme nous l’avons déjà constaté, le nom d’un tableau représente l’adresse
de la première composante.
&tableau[0] et tableau sont une seule et même adresse.
Le nom d’un tableau est un pointeur constant sur le premier élément du
tableau.
int A[10];
int * P;
P = A; est équivalente à P = &A[0];
11
4.1 Adressage des composantes d’un tableau
Si P pointe sur une composante quelconque d’un tableau, alors P + 1 pointe
sur la composante suivante.
P + i pointe sur la iième composante à droite de *P.
P - i pointe sur la iième composante à gauche de *P.
Ainsi, après l’instruction P = A;
Incrémentation et décrémentation d’un pointeur
Ces opérateurs (+, -, ++, --, +=, -=) sont
définis seulement à l’intérieur d’un
tableau car on en peut pas présumer que
2 variables de même type sont stockées
de façon contiguë en mémoire.
12
4.2 Calcul d’adresse des composantes d’un tableau
Note : Il peut paraître surprenant que P + i n’adresse pas le iième octet après
P, mais la iième composante après P.
Pourquoi ? Pour tenter d’éviter des erreurs dans le calcul d’adresses.
Comment ? Le calcul automatique de l’adresse P + i est possible car,
chaque pointeur est limité à un seul type de données, et
le compilateur connaît le nombre d’octets des différents types.
X contient la valeur du dixième élément de A, celle de A[9].
Une donnée de type float ayant besoin de 4 octets, le compilateur obtient
l’adresse P + 9 en ajoutant 9 * 4 = 36 octets à l’adresse dans P. 13
4.3 Soustraction et comparaison de 2 pointeurs
Mêmes tableaux : Comparaison des indices correspondants.
Tableaux différents : Comparaison des positions relatives en mémoire. 14
4.4 Différence entre un pointeur et le nom d’un tableau
15
Exemples
16
Résumons
Soit un tableau A de type quelconque et i un indice d’une composante de A,
17
Activité
Ecrire un programme C permettant de charger un
tableau de 5 entiers et d’inverser les éléments du
tableau.
Utiliser la notion de pointeur.
18