Nous allons à présent aborder un chapitre qui peut paraître quelque peu déroutant au départ ; mais ce que nous y apprendrons se révèle rapidement être extrêmement utile, et important. Je ne peux donc que vous inciter à persévérer si vous ne saisissez pas tout dès la première lecture, car il est rare de ne pas être amené à rencontrer des "allocations dynamiques de mémoire" dans les programmes que l'on trouve sur le net, ou que l'on écrit, à partir du moment où l'on arrive à des programmes de taille non négligeable.
Il est relativement fréquent, lorsque l'on commence à développer des programmes réellement interactifs, d'avoir besoin, par moment, de disposer d'un espace mémoire dont la taille n'est soit pas connue à l'écriture du programme, soit trop grande pour pouvoir être allouée sur la pile.
Par exemple, puisque la pile ne fait que environ 16Ko, il n'est pas possible de déclarer un tableau de la manière qui suit, dans le corps d'une fonctions :
La solution à ce problème est de demander de la mémoire ailleurs que sur la pile, c'est-à-dire, sur ce qu'on appelle, en programmation, le tas ("Heap" en anglais, par opposition à "Stack", la pile).
Sur nos calculatrice, la taille du tas est au maximum d'environ 180Ko, lorsque toute la mémoire RAM est libre ; naturellement, si l'utilisateur a laissé des variables en mémoire RAM sans les archiver, moins de mémoire sera disponible ; autrement dit, une allocation dynamique de mémoire peut échouer ; il vous faudra donc toujours, lorsque vous en effectuerez une, vérifier si elle a réussi.
D'autre part, la mémoire RAM est découpée en blocs de 64Ko ; il n'est donc pas possible d'allouer plus de 64Ko (moins quelques octets) à la fois.
Effectuer une allocation dynamique de mémoire, c'est demander au système de vous réserver un bloc de mémoire, que vous pourrez utiliser à votre convenance.
Cela dit, c'est à vous d'indiquer, avant la fin de votre programme, que vous souhaitez libérer ce bloc mémoire. Dans le cas contraire, il restera marqué comme réservé, et le système d'exploitation de la TI ne pourra plus l'utiliser ; au final, si vous allouez beaucoup de mémoire sans jamais la libérer, votre TI n'en n'aura plus de libre... ni pour vos programmes, ni pour son propriétaire... Et, dans ce cas de figure, la seule solution permettant de récupérer la mémoire perdue est d'effectuer un reset de la calculatrice.
Vous vous doutez bien que cette solution n'est pas appréciable pour les utilisateurs de votre programme... qui ne l'utiliseront probablement pas longtemps, s'il cause de telles fuites de mémoire.
Donc, lorsque vous allouez dynamiquement de la mémoire, pensez à toujours la libérer lorsque vous n'en n'avez plus besoin !
Maintenant que nous avons vu en quoi l'allocation dynamique de mémoire consiste, ainsi qu'à quoi elle sert, nous allons étudier les différentes fonctions mises à notre disposition pour travailler avec le tas.
Tout d'abord, allouons de la mémoire.
Pour cela, nous utilisons la fonction malloc, dont le prototype est le suivant :
Je me permet d'insister sur la nécessité de vérifier que l'allocation a réussi : si la fonction d'allocation a renvoyé NULL, le bloc mémoire que vous souhaitiez réserver ne vous a pas été alloué ; il ne faut pas, en ce cas, travailler avec le pointeur retourné, sous peine de plantage (écriture vers l'adresse nulle, ou vers une zone mémoire non définie).
Par exemple, pour allouer un tableau de 5000 unsigned long, comme nous souhaitions le faire au début de ce chapître :
Il arrive que l'on ait besoin de modifier la taille d'un bloc mémoire que nous avions alloué gràce à la fonction malloc.
Pour cela, il nous faudra utiliser la fonction realloc, dont le prototype est le suivant :
A titre d'illustration, voici un petit exemple de réallocation de l'espace mémoire que nous avons alloué un peu plus haut :
J'ai déjà parlé plusieurs fois de l'importance qui réside dans le fait de bien libérer l'espace mémoire que vous avez alloué... Il serait peut-être temps d'étudier comment cela se fait.
Pour libérer un espace mémoire que vous aviez demandé précédemment à l'aide de la fonction malloc, il convient d'utiliser la fonction free, dont le prototype est le suivant :
Je me permet d'attirer votre attention sur le fait qu'il est nécessaire que le paramètre que vous passez à la fonction free soit valide, et corresponde bien au pointeur qui avait été retourné par une fonction d'allocation mémoire.
Si le pointeur que vous passez en paramètre n'est pas valide, il est fort probable que votre programme plantera.
Et voici un petit exemple, même si je doute de son utilité :
Pour finir, voici un petit exemple de programme au sein duquel nous réalisons une allocation dynamique de mémoire :
Pour cet exemple comme pour celui que nous avions étudié il y a quelques chapîtres de ça, il aurait été possible de se passer d'un tableau... Mais, après tout... c'était le but de notre exemple.
Notons, qu'il existe de nombreuses autres fonctions permettant de travailler avec la mémoire ; on peut par exemple déterminer combien de mémoire est disponible, verrouiller des blocs en mémoire, et pas mal d'autres choses encore.
Cela dit, ces fonctionnalités ne sont pas ANSI, et il n'est pas nécessaire, à mon avis, de les connaître, sauf si l'on souhaite effectuer des manipulations bien particulières ; si le besoin s'en fait sentir plus loin au cours de ce tutorial, nous étudierons certaines de ces fonctions.
Bien entendu, en plus de cela, rien ne vous empêche de consulter la documentation du fichier alloc.h.