Professional Documents
Culture Documents
Chap 4 Les Pointeurs
Chap 4 Les Pointeurs
Chapitre 4
Les pointeurs et l’allocation dynamique
Notion de pointeur
• Un pointeur est un objet dont la valeur est égale à l'adresse d'un
autre objet.
• Déclaration : type *nom-du-pointeur;
où type est le type de l'objet pointé. Cette déclaration déclare un
identificateur, nom-du-pointeur, associé à un objet dont la valeur est
l'adresse d'un autre objet de type type. L'identificateur nom-du-
pointeur est donc en quelque sorte un identificateur d'adresse.
Le type d'un pointeur dépend du type de l'objet vers lequel il pointe.
Cette distinction est indispensable à l'interprétation de la valeur d'un
pointeur.
En effet, pour un pointeur sur un objet de type char, la valeur donne
l'adresse de l'octet où cet objet est stocké. Par contre, pour un
pointeur sur un objet de type int, la valeur donne l'adresse du premier
des 4 octets où l'objet est stocké. Dans l'exemple suivant, on définit un
pointeur p qui pointe vers un entier i :
1
2023-05-08
2
2023-05-08
Par contre, les mêmes instructions avec des pointeurs sur des objets de type
double :
double i = 3; double *p1, *p2;
p1 = &i;
p2 = p1 + 1;
Affiche p1 = 35984 p2 = 35992. double = +8 bits
Explications
/*Exemple 1 les pointeurs */ • Dans cet exemple, on définit un entier a et deux
#include<stdio.h> pointeurs vers des entiers x et y.
int main() • a est initialisée à la valeur 90.
• Après l'instruction x=&a, x pointe vers a. x
{
contient l'adresse en mémoire où est stockée la
int a; variable a.
int *x,*y; • L'instruction *x=100; modifie le contenu de la
a=90; variable a et met la valeur 100 dans cette variable.
• L'instruction y=x copie le pointeur x dans le
x=&a; pointeur y. Après cette instruction, les deux
printf("%d \n", *x ); pointeurs x et y pointent vers la même variable a.
*x=100; • Lorsqu'on écrit *y=80, on modifie alors le
contenu de la variable a qui vaut alors 80.
printf( "a vaut %d: \n", a );
• On voit donc sur cet exemple qu'un pointeur
y=x; permet de modifier indirectement le contenu
*y=80; d'une variable.
printf( "a vaut : %d\n", a ); • Exécution : Lorsqu'on exécute le programme
voici ce qu'on obtient à l'écran : 90
return 0;
a vaut : 100
} a vaut : 80
3
2023-05-08
#include<stdio.h>
int main()
{ int a,b;
int *x,*y;
a=50;
b=80;
x=&a;
y=&b;
*x=*y;
printf( "a vaut %d: \n", a );
x=y;
*x=1000;
printf( "b vaut %d: \n", b );
return 0;}
Explications
/* Exemple 2 les pointeurs */ • Dans cet exemple, on déclare deux entiers a et b et
deux pointeurs vers des entiers x et y.
• a est initialisé à 50 et b à 80.
#include<stdio.h>
• L'instruction x=&a fait pointer x vers a.
int main() • L'instruction y=&b fait pointer y vers b.
{ int a,b; • L'instruction *x=*y copie l'entier pointé par y dans
int *x,*y; l'entier pointé par x c'est-à-dire copie b dans a. On a
copié des entiers. a vaut donc 80.
a=50; • On affiche ensuite la valeur de a c'est-à-dire 80.
b=80; • L'instruction x=y copie le pointeur y dans le pointeur
x=&a; x : x pointe maintenant vers l'entier b (tout comme y
d'ailleurs). On a copié des pointeurs.
y=&b; • L'instruction *x=1000 met la valeur 1000 dans l'entier
*x=*y; pointé par x c'est-à-dire dans b.
printf( "a vaut %d: \n", a ); b vaut alors 1000.
• On affiche ensuite la valeur de b c'est-à-dire 1000.
x=y;
• Dans cet exemple, il faut bien comprendre que
*x=1000; parfois on copie des entiers, parfois on copie des
printf( "b vaut %d: \n", b ); pointeurs.
• Exécution: Lorsqu'on exécute le programme voici
return 0;} ce qu'on obtient à l'écran : a vaut : 80
b vaut : 1000
Remarque
Soit n une variable d’adresse ad_n;
ad1 : une variable pointeur de nom ad1 qui pointe sur n;
val(ad1)=ad_n
adresse ad1=ad_ad1
L’expression &*ad1 = ad_n car
On a *ad1=n
Donc equivau a &n et comme l’adresse de n = ad_n donc
&*ad1= ad_n
4
2023-05-08
Allocation dynamique
Avant de manipuler un pointeur, et notamment de lui appliquer l'opérateur
d'indirection *, il faut l'initialiser. Sinon, par défaut, la valeur du pointeur est
égale à une constante symbolique notée NULL définie dans stdio.h. En
général, cette constante vaut 0. Le test p == NULL permet de savoir si le
pointeur p pointe vers un objet.
5
2023-05-08
On a ainsi réservé, à l'adresse donnée par la valeur de p, 8 octets en mémoire, qui permettent
de stocker 2 objets de type int.
Le programme affiche
p =11424 *p = 3 p+1 = 11428 *(p+1) = 6 .
• Il faut libérer l’espace mémoire. Ceci se fait à l'aide de l'instruction free qui a pour syntaxe
free(nom-du-pointeur);
• A toute instruction de type malloc doit être associée une instruction de type free.
#include <stdlib.h>
main() {
int n; int *tab; ...
Scanf(‘’ %d’’, &n);
tab = (int*)malloc(n * sizeof(int));
... free(tab);
}
6
2023-05-08
#include<stdio.h> if (t==NULL)
#include<stdlib.h> printf( "pas assez de mémoire\n") ;
int main() else
{ {
int *t; for(i=0;i<10;i++)
int i; t[i] = i * i;
t = (int *) malloc( 5 * sizeof(int) ); for(i=0 ; i<10 ; i++)
if (t==NULL) printf( "%d \n", t[i] );
printf("pas assez de mémoire\n" ); free(t);
else }
{ return 0;
for(i=0 ; i<5 ; i++) }
t[i] = i * i;
for(i=0 ; i<5 ; i++)
printf( "%d \n", t[i] );
free(t);
}
• Explications
• Dans cet exemple, t est un pointeur vers un entier.
• Après l'appel à la fonction malloc dans l'instruction t=(int *)malloc(5*sizeof(int)), t contient
l'adresse d'une zone mémoire dont la taille est 5 fois la taille d'un entier. La variable t devient
ainsi un tableau de 5 entiers qu'on peut utiliser comme n'importe quel tableau d'entiers.
• Si t n'est pas NULL, ce qui signifie qu'il y avait assez de mémoire disponible, alors on peut
accéder à n'importe quelle élément du tableau en écrivant t[i] (i étant bien sûr compris entre
0 et 4).
• Dans ce programme, on remplit les 5 cases du tableau t en mettant i*i dans la case i et on
affiche ce tableau. • Ensuite, on libère l'espace occupé par le tableau en appelant la fonction
free(t). t devient alors un pointeur non initialisé et on a plus le droit d'accéder aux différentes
cases du tableau qui a été détruit.
• On appelle ensuite la fonction t=(int *)malloc(10*sizeof(int)); t devient alors cette fois-ci un
tableau à 10 cases (sauf si t est NULL) et on peut accéder à la case i en écrivant t[i] (i compris
entre 0 et 9).
• Dans ce programme, on remplit les 10 cases du tableau t en mettant i*i dans la case i et on
affiche ce tableau.
• On détruit ensuite la tableau t en appelant free(t).
• Exécution
Lorsqu'on exécute le programme voici ce qu'on obtient à l'écran :
0 1 4 9 16
0 1 4 9 16 25 36 49 64 81
7
2023-05-08
Explications
• Dans cet exemple, t est un tableau statique de 10 entiers et x est un
pointeur vers un entier.
• L'instruction x=t; permet de faire pointer x vers la première case du
tableau t. Il est équivalant d'écrire x=t; que d'écrire x=&t[0];
• À l'intérieur d'une boucle for, on va afficher *x, c'est-à-dire l'entier
pointé par t et à chaque étape, on écrit x++, ce qui incrémente la
valeur de t de la taille d'un entier.
• x va donc pointer successivement t*0+, t*1+,…etc…t*9+. On va donc
afficher une à une toutes les cases du tableau.
Exécution
Lorsqu'on exécute le programme voici ce qu'on obtient à l'écran :
0 1 4 9 16 25 36 49 64 81
8
2023-05-08