UKOnline

Mémoire dynamique

Jusqu'à présent, la seule manière qu'on a vue pour obtenir un pointeur consiste à utiliser l'opérateur d'adresse & pour récupérer l'adresse d'une variable. On va maintenant voir qu'il est possible de directement créer une nouvelle zone mémoire et d'en récupérer l'adresse.

Organisation de la mémoire

Pendant l'exécution d'un programme, la mémoire utilisée pour stocker les données créées par le programme est composée de deux parties. La pile contient toutes les variables locales, qui sont déclarées dans les procédures et fonctions donc. Ensuite, il y a également une zone appelée le tas qui contient de la mémoire allouée dynamiquement.

La figure 7 montre tout l'espace mémoire réservé à un programme en cours d'exécution. Tout au long de la vie de l'exécution d'un programme, la pile et le tas vont augmenter et diminuer de taille. La pile augmente vers le haut alors que le tas augmente vers le bas.

Organisation de la mémoire
Organisation de la mémoire en deux zones : la pile et le tas.

Allocation dynamique de mémoire

Afin d'allouer une nouvelle zone de mémoire dans le tas, on peut utiliser la fonction malloc, disponible dans la librairie standard C, en incluant le fichier stdlib.h. Voici un exemple d'utilisation de la fonction :

Cet appel à la fonction malloc va tenter d'allouer un bloc mémoire dans le tas, dont la taille correspond à celle d'un int. La fonction renvoie un pointeur vers ce bloc mémoire et on le stocke dans la variable p. La figure 8 montre ce qui s'est passé en mémoire, après exécution de cette instruction. L'appel à malloc a créé un bloc mémoire de la taille d'un int (4 octets) commençant à l'adresse 2997 jusque 3000. L'adresse ce ce bloc est renvoyé par la fonction malloc et stocké dans la variable p.

Appel malloc
Allocation d'une zone mémoire dans le tas.

Il se peut qu'il n'y ait plus de place dans le tas pour allouer des nouvelles zones mémoire. Dans ce cas, la fonction malloc échoue et renvoie un pointeur NULL. En pratique, il faut donc tester la valeur de retour de la fonction malloc avant d'utiliser le pointeur renvoyé. On va donc habituellement tester avec une instruction if si la valeur renvoyée est différente de NULL :

Modifier une valeur en mémoire

On modifier la valeur stockée dans une zone mémoire dont on possède l'adresse dans une variable de type pointeur en utilisant de nouveau l'opérateur de déréférencement. La différence est qu'on utilise cette fois-ci l'opérateur appliqué sur un pointeur à gauche de l'opérateur d'affectation.

Reprenons le pointeur p de l'exemple précédent. L'opération *p donne accès à la zone mémoire correspondant à l'adresse stockée dans p. On a déjà vu qu'en utilisant *p dans une expression, cela permettait d'accéder à la valeur se trouvant à l'adresse stockée dans p. Maintenant, si on veut modifier la valeur se trouvant à l'adresse stockée dans p, on va par exemple écrire :

La figure 9 montre l'effet qu'a cette instruction sur la mémoire. La valeur stockée dans la zone mémoire d'adresse 2997 a été modifiée et vaut maintenant 42.

Modification valeur pointée
Modifier la valeur d'une zone mémoire dans le tas dont on possède l'adresse dans un pointeur.

Si p est un pointeur de type int*, alors on peut considérer que *p est une variable de type int. On peut dès lors utiliser *p partout là où on peut utiliser une variable int.

Libérer une zone mémoire

La mémoire qui est allouée sur la pile varie au cours de l'exécution lorsque des procédures et fonctions sont appelées et se terminent. La gestion de cette partie de la mémoire est donc automatique. Concernant le tas, une fois une zone allouée, grâce à un appel à malloc par exemple, elle le reste par défaut tout au long de l'exécution du programme. Si on n'a plus besoin d'une zone mémoire qui a été allouée, il faut donc explicitement la libérer. Pour cela, on utilise la fonction free qui permet de libérer la zone mémoire associée à un pointeur.

L'exemple de code ci-dessous commence donc par allouer une nouvelle zone mémoire pouvant stocker un int. Elle remplit ensuite cette zone avec le nombre 42. Ensuite, elle libère directement cette zone mémoire. À partir de ce moment, le pointeur p contient le pointeur NULL.