Vous êtes sur la page 1sur 32

Chapitre 6 – LES POINTEURS

Dr N. BAME

Dr N. BAME 1
I. Introduction: notion d'adresse
• La mémoire centrale utilisée par les programmes, est découpée en
octets. Chacun de ces octets est identifié par un numéro
séquentiel. Par convention, ce numéro est noté en hexadécimal et
précédé par 0x.
• Exemple: 0x3fffd10
0x3fffd11
0x3fffd12
0x3fffd13
0x3fffd14
0x3fffd15
0x3fffd16
0x3fffd17

• Déclarer une variable consiste à réserver une zone en mémoire
occupant un certain nombre d‘octets (sa taille) et à laquelle on
donne un nom. Le numéro du premier octet de cette zone
correspond à l‘adresse de la variable.
2
Dr N. BAME
Exemple
• short int n = 18;

0x3fffd10
0x3fffd11 Dans cet exemple, la valeur
0x3fffd12 de la variable n est 18 et
0x3fffd13 son adresse est 0x3fffd14.
0x3fffd14 18 n
0x3fffd15
0x3fffd16
0x3fffd17

Dr N. BAME 3
I. Introduction: notion d'adresse
• Pour accéder à la valeur contenue dans une
variable, on utilise tout simplement son nom.

• Toutefois, il est parfois très pratique de manipuler


une variable par son adresse.

• En algorithmique, pour désigner l’adresse d’une


variable, on utilise l'expression "adresse de" alors
qu'en C, on utilise l'opérateur &

Dr N. BAME 4
II. Notion de pointeur
• II-1. Définition
• Un pointeur est une variable dont la valeur est
l'adresse d'une autre variable.
– On dit que le pointeur pointe sur la variable dont il contient
l'adresse.

• Un pointeur est associé à un type de variable sur lequel


il peut pointer.
– Par exemple, un pointeur sur entier ne peut pointer que sur
des variables entières.

• Un pointeur est lui-même une variable et à ce titre il


possède une adresse.
– Il convient donc de ne pas confondre l'adresse de la variable
pointeur et sa valeur ( qui est l'adresse de la variable
pointée). Dr N. BAME 5
II. Notion de pointeur

0x3fffd10
0x3fffd14 p p est un pointeur contient l'adresse
0x3fffd11
de la variable n ( p pointe sur n)
0x3fffd12
p est placé à l'adresse 0x3fffd10.
0x3fffd13
0x3fffd14 18 n
0x3fffd15 n est placé à l'adresse 0x3fffd14
0x3fffd16
0x3fffd17

Dr N. BAME 6
II-2. Représentation :
pointeur

variable pointée

• Exemple p

18
n
Dr N. BAME 7
II-3. Déclaration d'un pointeur
• syntaxe :
En algorithmique
variable
identificateur_pointeur : pointeur sur type

Exemple :
p: pointeur sur entier
En C

type* identificateur_pointeur ;

Exemple :
int* p ;
Dr N. BAME 8
II-4. Manipulation d'un pointeur
• Après avoir déclaré un pointeur, on peut l’initialiser
en lui donnant l’adresse d’une variable existante.
• Exemple:
En Algorithmique En C

variable int main( )


n : entier {
p: pointeur sur entier int n;
Début int* p;
n = 18 n=18;
p = adresse de n p = &n;
… …
Fin }

Dr N. BAME 9
II-4. Manipulation d'un pointeur
• Il est possible d’accéder à la zone mémoire pointée.
• Pour cela on utilise, en algorithmique et en C,
l’opérateur *.

• Ainsi, *p désigne la zone mémoire (la variable)


pointée par le pointeur p.

Dr N. BAME 10
Exemple
En Algorithmique En C

variable
n: entier int main()
p: pointeur sur entier {
Début int n = 33;
n = 33 int* p; //déclaration du
p = adresse de n // p pointe sur pointeur p
n p = &n; // p pointe sur n
Ecrire(*p) //la valeur 33 est printf("%d", *p) ; //affiche 33 à
affichée l'écran, la valeur de n
*p = 34 // n vaut maintenant *p = 34 ; // n vaut maintenant
34 34
Fin }

Dr N. BAME 11
Remarque
• Par défaut lorsque l’on déclare un pointeur, on ne
sait pas sur quoi il pointe.

• Si on veut que le pointeur pointe nulle part, il faut


l'initialiser à NULL.

Dr N. BAME 12
Exemple :

En Algorithmique En C

variable int * p = NULL ;


p: pointeur sur entier
Début
p = NULL // p ne pointe nulle part

Fin

Dr N. BAME 13
II-5. Double indirection
• Le fait qu'un pointeur pointe sur une variable s'appelle
indirection (comme accès indirect). Quand un pointeur
pointe sur un autre pointeur, il y a double indirection.

… 0x3fffd10 p2 pointe sur p1 qui pointe sur n
p2


0x3fffd10
0x3fffd11 0x3fffd14 p1 On peut accèder à n par p2 en
0x3fffd12 utilisant deux fois l'opérateur *
0x3fffd13 * *p2 est équivalent à *p1, c'est à dire à n
0x3fffd14
0x3fffd15 18 n
0x3fffd16
0x3fffd17
Dr N. BAME 14
III-1. Allocation dynamique en Algorithmique
• L’allocation dynamique se fait par l’instruction :

identificateur_pointeur = allouer(unType)

identificateur_pointeur est l'identificateur du pointeur
unType est le type de l’objet pointé.

• Exemple:

variable
p: pointeur sur entier
Début
p = allouer(entier)
...
Fin Dr N. BAME 15
III-1. Allocation dynamique en Algorithmique
• Enfin, lorsque l'on n'a plus besoin de l'espace
mémoire alloué dynamiquement (c'est-à-dire
quand on n'utilise plus le pointeur nom_pointeur), il
faut libérer cette place en mémoire.

• Cela se fait par l'instruction :

– désallouer(identificateur_pointeur)

Dr N. BAME 16
III-2. Allocation dynamique de mémoire en C
• En C, l’allocation dynamique de mémoire peut se faire
avec les fonctions malloc et calloc de la bibliothèque
standard stdlib.h:

• La fonction malloc prend comme paramètre la taille de


la zone qu’on veut allouer et retourne, en cas de
succès, l’adresse de la zone allouée.
– Le type de l’adresse retournée par malloc est void*. Il faut
alors le convertir au type du pointeur auquel on va l‘affecter.
– Par exemple, si on veut réserver un nouvel emplacement
pour un caractère, on peut faire:
char * pcar;
pcar = (char * )malloc(sizeof(char ));

En cas d’échec, la fonction malloc


Dr N. BAME
retourne NULL. 17
III-2. Allocation dynamique de mémoire en C
• La fonction calloc prend en paramètre un nombre
d’éléments nb et la taille t d’un élément et permet
d’allouer une zone contiguë de nb éléments de taille t
octets.
• Elle retourne, en cas de succès, l’adresse de la zone
allouée.
• Le type de l’adresse retournée par calloc est void*. Il
faut alors le convertir au type du pointeur auquel on va
l‘affecter.
• Par exemple, si on veut allouer un emplacement pour
10 éléments de type int, on peut faire:
– int * p;
– p = ( int * )calloc(10, sizeof(int));

• En cas d’échec, la fonction calloc retourne NULL.


Dr N. BAME 18
Remarque
• La libération d’une zone mémoire allouée de
manière dynamique n’est pas automatique en C.
• Une telle zone continue à occuper de l’espace
mémoire jusqu’à la fin de l’exécution du programme
si on ne la libère pas de manière explicite.
• Pour ce faire, il faut utiliser la fonction free de la
bibliothèque standard stdio.h selon la syntaxe
suivante:
free(identificateur_pointeur);

• Exemple
free(p) ; // permet de libérer la zone mémoire pointée
par p. Dr N. BAME 19
IV. Pointeurs et structures
• Il est très courant d'utiliser un pointeur pour
mémoriser l'adresse d'une variable structure.
• Si p est un pointeur sur une structure, *p désigne la
structure pointée.
• On peut donc accéder à un champ de la structure
pointée par l'expression : (*p).champ
• L'usage de parenthèses est ici indispensable car
l'opérateur * a une priorité moins élevée que
l'opérateur point (.).
• Cette notation peut être simplifiée grâce à
l'opérateur .
• L'expression précédente est strictement équivalente
à : p  champ Dr N. BAME
20
Exemple
struct date
{
int jour;
int mois;
int annee;
};

struct date d; // d est une variable structure


struct date * p; //p est un pointeur sur une structure

p = &d ; // p pointe sur la structure d et, par conséquent,


d.jour est équivalent à pjour
Dr N. BAME 21
V. Arithmétique des pointeurs en C
• Si i est un entier et p est un pointeur sur un objet de
type unType, l'expression p + i désigne un pointeur sur
un objet de type unType dont la valeur est égale à la
valeur de p incrémentée de i*sizeof(unType).

• Il en va de même pour la soustraction d'un entier à un


pointeur, et pour les opérateurs d'incrémentation et de
décrémentation ++ et --.

• Ainsi, pour un pointeur sur un char, l’incrémentation de


ce pointeur correspond à un décalage de 1 octet de la
zone mémoire pointée, alors que pour un pointeur sur
un float, la même incrémentation correspondra à un
décalage de 4 octets. Dr N. BAME 22
V. Arithmétique des pointeurs en C
• Soient p1 et p2 deux pointeurs de même type.
L’instruction

• p1 = p2;

• signifie qu’on copie dans p1 l’adresse contenue dans


p2 et, donc, que p1 va pointer au même endroit
que p2.

Dr N. BAME 23
VI. Pointeurs et tableaux en C
• L'usage des pointeurs en C est, en grande partie,
orienté vers la manipulation des tableaux.

• En C, le nom d’un tableau est en fait un pointeur sur le


premier élément du tableau.

• Par exemple, dans la déclaration


int tab[10];

• tab est un pointeur constant dont la valeur est l'adresse


du premier élément du tableau.
• Autrement dit, tab a pour valeur &tab[0]. Cette valeur
n’est pas modifiable, néanmoins elle peut être utilisée
pour initialiser un pointeur sur le premier élément du
tableau. Dr N. BAME 24
VI. Pointeurs et tableaux en C
• Exemple
int tab[5]={1,2,3,4,5};
int * p = tab; // p pointe au même endroit que tab c’est
à dire sur le premier élément de tab

• tab étant un pointeur sur le premier élément (élément


d’indice 0) du tableau, tab+i donne le pointeur vers
l’élément d’indice i du tableau.

• Un tableau correspond en mémoire à une zone


contiguë dont la taille est le produit du nombre
d’éléments du tableau par l’espace nécessaire pour
stocker un élément.
• On peut donc utiliser un pointeur pour accéder aux
différents éléments d’un tableau.
Dr N. BAME 25
Exemple
• Programme qui affiche un tableau d’entiers

#include <stdio.h>
#define N 5

int main( )
{
int tab[5] = {1, 2, 6, 0, 7};
int * p;
for (p=tab; p<=tab+N-1; p++)
printf(" %d \n",*p);
}

Dr N. BAME 26
Remarque
• On peut déclarer un tableau comme un pointeur sur le
type de ses éléments.

• Exemple:
int * tab;

• Mais dans ce cas, aucune place n’est réservée en


mémoire pour le tableau et le pointeur tab n’est pas un
pointeur constant.

• Dans ce cas, pour faire la réservation en mémoire, on


peut utiliser les fonctions d’allocation dynamique
malloc ou calloc. Dr N. BAME 27
Exemple
int * tab;
int nb=10;

tab = (int *)malloc(nb*sizeof(int));

ou bien

tab = (int *)calloc(nb, sizeof(int));


• On peut ensuite utiliser tab comme un tableau
normal.
• Par exemple, pour désigner l’élément i de ce
tableau, on peut écrire tab[i] ou *(tab+i);
Dr N. BAME 28
VII. Pointeurs et chaînes de caractères en C
• On a vu précédemment qu'une chaîne de caractères
était un tableau à une dimension d'éléments de
type char, se terminant par le caractère nul '\0'.
• Le nom d’un tableau étant un pointeur sur le
premier élément, on peut donc manipuler toute
chaîne de caractères à l'aide d'un pointeur sur un
élément de type char.
• Ainsi, il existe deux manières de déclarer une chaîne
de caractères :

Dr N. BAME 29
VII. Pointeurs et chaînes de caractères en C
• Comme un tableau de caractères:
• Exemple :

char ch[10];

• Dans ce cas il y a réservation d’espace mémoire


pour la chaîne et le nom de la chaîne (ch) est un
pointeur constant et ne peut donc pas apparaître
dans le membre gauche d'une affectation. On dit
dans ce cas que l'espace mémoire nécessaire au
stockage des caractères de la chaîne est réservé
"statiquement".
Dr N. BAME 30
VII. Pointeurs et chaînes de caractères en C
• Comme un pointeur sur un caractère:
• Exemple

– char * ch;

• Dans ce cas il n’y a pas de réservation d’espace


mémoire pour la chaîne. Pour faire la réservation en
mémoire, on peut utiliser les fonctions d’allocation
dynamique malloc ou calloc.
• Le pointeur ch n’est pas un pointeur constant et
peut apparaître dans le membre gauche d'une
affectation. On peut faire, par exemple, ch =
"bonjour"; Dr N. BAME 31
Dr N. BAME 32

Vous aimerez peut-être aussi