Vous êtes sur la page 1sur 14

Chapitre 2 :

Les pointeurs et l’allocation de la mémoire


Sommaire

I‐ Les pointeurs
Mise en situation
1- Les variables et emplacements mémoire
2- Les méthodes d’accès au contenu d'une variable
a) L’adressage direct
b) L’adressage indirect
3- Les pointeurs
a) La déclaration d’un pointeur
b) Le référencement de variables / le déréférencement de pointeurs
i. Le référencement d’une variable
ii. Le déréférencement d’un pointeur

II‐ Le passage par valeur et le passage par référence


Objectif / intérêts
1- Le passage par valeur
2- Passage par référence

III‐ L’allocation de la mémoire


Mise en situation
1) L’allocation automatique/statique de la mémoire
2) L’allocation manuelle/ dynamique de la mémoire
a) L’allocation de la mémoire avec malloc()
b) La libération de la mémoire avec free()
c) D'autres fonction d'allocation de la mémoire
i. La fonction calloc()
ii. La fonction realloc()

I‐ Les pointeurs

Mise en situation :
Dans la programmation, nous utilisons des variables pour stocker des
informations. le compilateur assure la gestion de la mémoire en affectant
à chaque variable un emplacement déterminé. (La mémoire RAM de
l'ordinateur est vue comme un long tableau continu.).

9
1‐ Les variables et emplacements mémoire

L’emplacement mémoire d’une variable est caractérisé par :


 Son nom
 Sa longueur (char 1 octet, int 2 octets, float 4 octets ...)
 Son adresse ( en hexadécimal %x)
Exemple :

int A ; // le compilateur réserve un place de 2 octes

2‐ Les méthodes d’accès au contenu d'une variable

a) L’adressage direct

L’adressage direct c’est l’accès au contenu d'une variable par le nom de la variable.

Exemple :
int A= 10 ;

b) L’adressage indirect

L’adressage indirect ‘c’est l’Accès au contenu d'une variable en passant par l'adresse de la
variable.
Exemple :

int A= 10 ;

Application :
scanf() : on utilise l’adresses des variables pour éviter toutes confusion. (Variables locales
vs. Variables globales).

10
3‐ Les pointeurs
Soit A et P deux variables (deux espaces mémoires) :.
 A contenant une valeur (par exemple 10)
 P contient l'adresse mémoire (héxadicimal / int) de A.

A et P peuvent se présenter par exemple comme suit :

La variable « spéciale » P indique l’adresse de la variable A.


on dit que 'P pointe sur A'.

a) La déclaration d’un pointeur

Un pointeur est une variable qui permet de stocker l’adresse mémoire d’une autre
variable.

Syntaxe : Pour déclarer un pointeur :


type * nom_du_pointeur;

Exemple :

Attention :
La déclaration d'un pointeur alloue un espace mémoire pour le pointeur
mais pas pour la variable pointée.

b) Le référencement de variables / le déréférencement de pointeurs :

i. Le référencement d’une variable

Le référencement d’une variable c’est obtenir son adresse mémoire.

11
Information :

Le référencement d’une variable se fait avec l’opérateur &.

Exemple :

ii. Le déréférencement d’un pointeur

Le déréférencement d’un pointeur c’est obtenir le contenu de l’adresse mémoire


stocké dans ce pointeur.

Information :

Le déréférencement d’un pointeur se fait avec l’opérateur . *

Exemple :

Exercice :
int a;
int* p;
p=&a;

que peut-on dire de *p et a ?

12
Solution :
*p et a correspondent au même emplacement mémoire
p et a ont donc la même valeur.

Ce qui il faut retenir :

Après les instructions :

int A ;
int * P ;
P = &A

 A désigne le contenu de A
 &A désigne l’adresse de A
 P désigne l’adresse de A
 *P désigne le contenu de A
 En outre &P désigne l’adresse du pointeur P (peu utilisé)
 *A n’a pas de sens, puisque A n’est pas un pointeur.

II‐ Le passage par valeur et le passage par référence

Objectif / intérêts :
Les arguments d'une fonction sont des variables locales qui sont utilisées
lors de son appel. On a intérêt que les modifications effectuées sur des
variables à l’intérieur d’une fonction ont également effets en dehors de la
fonction.

Une solution : utiliser des variables globales


Inconvénient : variables S

Comment écrire une fonction qui modifie les variables de la fonction


appelante sans que celles-ci soient définies comme globales ?

Il existe deux manières de transmettre des paramètres aux fonctions :


- Passage par valeur
- Passage par référence

13
1‐ Le passage par valeur

Discussion d'un exemple :


Nous voulons écrire une fonction PERMUTER qui échange le contenu
de deux variables du type int.

void PERMUTER (int A, int B)


{
int AIDE;
AIDE = A;
A = B;
B = AIDE;
}

Donc soit le programme suivant :

Nous avons appelé la fonction pour deux variables X et Y par:


X=3 ;Y=4 ;
PERMUTER(X, Y);

Exécution :

Résultat :

X=3 et Y=4.
X et Y restent inchangés !

14
Explication :
Lors de l'appel, les valeurs de X et de Y sont copiées dans les paramètres A et B.
PERMUTER échange bien contenu des variables locales A et B, mais les valeurs de X et
Y restent les mêmes.

A retenir :
- Dans un passage par valeur, juste une copie de la variable est transmise à la fonction.
- Dans un passage par valeur, les modifications effectuées à l’intérieur de la fonction
n’ont pas d’effets en dehors de la fonction.

2‐ Passage par référence

Besoin :
Garder les modifications des contenus des variables en dehors des fonctions ou elles sont
modifiées.

Discussion d'un exemple :


Pour pouvoir modifier le contenu de X et de Y, la fonction PERMUTER
à besoin des adresses de X et Y. En utilisant des pointeurs :

Nous voulons écrire une fonction PERMUTER qui échange le contenu


de deux variables du type int.

void PERMUTER (int *A, int *B)


{
int AIDE;
AIDE = *A;
*A = *B;
*B = AIDE;
}

Donc soit le programme suivant :

15
Nous appelons la fonction par :
X=3 ;
Y=4 ;
PERMUTER(&X, &Y);

Exécution :

Résultat :

Le contenu des variables X et Y est échangé !

Explication :

Lors de l'appel, les adresses de X et de Y sont copiées dans les pointeurs A et B.


PERMUTER échange ensuite le contenu des adresses indiquées par les pointeurs A et B.

16
Ce qui il faut retenir :
- Dans un passage par référence, l’adresse de la variable elle-même est transmise à la
fonction.
- Dans un passage par référence, les modifications effectuées à l’intérieur d’une
fonction ont également effets en dehors de la fonction.

Conclusion :
Si vous souhaitez ne transmettre que la valeur du variable utilisez le «Passage par valeur»
et si vous souhaitez voir la modification de la valeur originale du variable, utilisez le
«Passage par référence».

Passage par valeur VS passage par référence

17
III‐ L’allocation de la mémoire

Mise en situation :
Architecture de la mémoire :
La mémoire RAM est découpée en deux zones Heap (Le tas) et Stack (ou
La pile) qui ont chacune leur leur fonctionnement et leur utilisation.

c) Stack :pour l’allocation de mémoire automatique/statique.


La stack. est de taille fixe.
d) Heap pour l’allocation de mémoire manuelle/dynamique .
 Le tas est de taille non limitée (délivrée par l’OS).

Différence clé entre Tas vs. et Pile

Quand utiliser le tas et quand utiliser la pile?

la pile : Pour des variables relativement petites qui ne doivent persister que tant que la
fonction qui les utilise est active.

le tas : Pour des gros bloc de mémoire (un grand tableau ou une grande structure pouvant
changer de taille) et que vous devez conserver cette variable pendant une longue période
(comme une variable globale).

18
1) L’allocation automatique/statique de la mémoire

Se fait automatiquement par le compilateur : Lorsque vous déclarez une variable à l’aide
d’un type de données de base, le compilateur alloue automatiquement de l’espace
mémoire pour la variable dans la zone mémoire « Stack »

2) L’allocation manuelle/ dynamique de la mémoire

Le compilateur alloue ou libère manuellement de l’espace mémoire en fonction des


besoins de programmation. La mémoire dynamique est gérée dans la zone « Heap ».

Objectif / intérêts :
▶ Définir de « grosses » structures de données dont la taille n’est connue
qu'à l’exécution.
Exemple : Tableaux de dimensions variables, listes chaînées.
▶ Libérer l'espace mémoire alloué lorsqu’il n'est plus nécessaire.

La gestion dynamique de la mémoire se passe en deux étapes :

Etapes
▶ l'allocation de la mémoire, réalisée par la fonction : malloc
…. sizeof pour calculer l’espace mémoire nécessaire
▶ la libération de la mémoire, réalisée par la fonction free ;

Rappel : La déclaration d'un pointeur alloue un espace mémoire pour le pointeur mais
pas pour l'objet pointé.

a) l’allocation de la mémoire avec malloc()


L’allocation de la mémoire se fait avec la fonction malloc() qui sert à réserver nb_octes :

Syntaxe :
type_var* ptr;
ptr = malloc( nb_octes );

malloc() renvoie l’adresse (un pointeur) du premier octet de l’espace alloué

Exemple :

19
L'opérateur sizeof (taille en octets)

L’opérateur sizeof() sert à calculer le nombre d'octets occupés par une variable :

Syntaxe :

sizeof ( type ou nom de variable) ;

Donc malloc() peut réserver le nombre d'octets nécessaires pour nb_var variables de
type type_var comme suit :

Syntaxe :

type_var* ptr;
ptr = malloc( sizeof(type_var) * nb_var );

b) La libération de la mémoire avec free()

La mémoire allouée dynamiquement n'est pas automatiquement libérée. Il faudra donc,


après utilisation, libérer ce bloc de mémoire via un appel à la fonction free.

Syntaxe :

nom‐du‐pointeur = malloc( ) ;
….
free(nom‐du‐pointeur);

Remarque :
Si nous ne libérons pas la mémoire à l'aide free(), alors elle ne sera libérée
automatiquement qu’à la fin du programme.

Information :
Les fonctions de gestion dynamique de la mémoire se trouvent dans :
bibliothèque standard du C

#include <stdlib.h>

20
c) Autres fonction de l’allocation de la mémoire

i. La fonction calloc()

La fonction calloc() = malloc() + initilisation à 0

ii. La fonction realloc()

La fonction realloc() modifie la taille d'un bloc de mémoire alloué.

Après modification

21
Exemple : allocation dynamique de la mémoire

Exécution :

Ce programme peut à chaque exécution afficher d’autres résultats,


par exemple :

Allocation de 16 entiers à l'adresse 072A


Allocation de 32 entiers à l'adresse 0752
Libération de 16 entiers en 072A
Allocation de 10 entiers en 072A --> utilise l’espace libéré par free()

22

Vous aimerez peut-être aussi