Il sagit de la motivation principale dutilisation des pointeurs, dans tous les langages de programmation. Dans de très nombreux programmes en effet, on ne sait pas davance quelle place une donnée (un tableau par exemple) va devoir utiliser. Imaginons par exemple un traitement de texte : il est impossible de savoir quelle taille allouer au tableau de caractères qui contient le texte, puisque cette taille dépend de ce qui sera tapé par lutilisateur.
La solution de facilité consiste à allouer une place fixe déterminée arbitrairement. Mais cela pénalise lutilisateur, et peut poser des problèmes si la taille allouée est trop petite (pas assez de place) ou trop grande (encombrement de la mémoire). En outre, il faut savoir quil existe trois blocs importants de mémoire disponibles : le segment de données, le tas (anglais heap), qui nest généralement limité que par la mémoire disponible pour le programme et enfin la pile (anglais stack), réservée aux arguments de fonctions.
La mémoire située dans le tas ne peut être allouée que dynamiquement, cest-à-dire au moment de lexécution du programme. La mémoire du segment de données est allouée à la compilation, en conséquence dinstructions comme celles-ci :
int i = 0; // quatre octets alloués char *s = "Bonjour à tous."; // 16 octets alloués double matrice[3][3]; // 9*8 == 72 octets alloués char tampon[256]; // 256 octets alloués
Lallocation dynamique peut se faire de deux façons différentes. La première consiste à employer des fonctions spéciales définies dans <alloc.h>
. La plus connue de ces fonctions est malloc
, qui réserve un bloc de mémoire de taille spécifiée, suivant le format :
void *malloc(size_t taille);
taille
est le nombre doctets souhaités (size_t
est équivalent à unsigned
). La fonction renvoie un pointeur qui vaut NULL (cest-à-dire 0
) sil ny a plus de place ou si taille == 0
, et sinon sur le bloc alloué. On écrira ainsi, pour dupliquer une chaîne de caractères par exemple (ne pas oublier la place pour le zéro final) :
char *s1 = "Bonjour à tous!\n"; char *s2 = (char*) malloc( 1+strlen(s1) ); if (s2) strcpy(s2, s1);
(en fait, il existe une fonction nommée strdup
dans <string.h>
qui fait ce travail). Notons dautre part que le bloc alloué nest pas remis à zéro. Il existe une fonction nommée memset
pour cela.
Il existe une fonction cousine de malloc
nommée calloc
; elle admet deux paramètres entiers, les multiplie et appelle malloc
. On utilise souvent cette fonction pour des tableaux :
int dim = 10; double *table = (double*) calloc(dim, sizeof(double));
Il arrive parfois que lon souhaite modifier la taille dun bloc alloué. On utilise alors realloc
:
void *realloc(void *bloc, size_t taille);
taille est la nouvelle taille demandée, bloc est le bloc mémoire à réallouer. La fonction renvoie NULL si taille == 0
ou sil ny a pas assez de place en mémoire, et sinon un pointeur sur la nouvelle position de bloc. Par exemple, on peut augmenter la taille de notre bloc table, si dim vient à augmenter en cours de programme :
dim += 10; // dim augmente table = (double*) realloc(table, dim*sizeof(double) ); if (!table) erreur("Plus de mémoire");
On doit ici faire la multiplication, car il ny a pas déquivalent à calloc
pour la réallocation. On notera que, si le résultat doit être converti en double*
, il nest pas nécessaire de convertir table en void*
, comme on la expliqué à propos de ce type spécial de pointeur.
Précisons que la fonction erreur
doit arrêter le programme, car table est perdu si la réallocation a échoué, puisquon na plus le pointeur table dorigine.
Lorsquon a fini dutiliser un bloc de mémoire, il est préférable de le libérer, afin quil puisse être réutilisé ultérieurement. On utilise pour cela la fonction free
:
void free(void *bloc);
Il suffit donc décrire :
free(table); table = NULL;
On a remis le pointeur à zéro, afin déviter des erreurs dans la suite. Il ne faut plus en effet utiliser un bloc libéré, de même quil ne faut pas utiliser un bloc incomplet : les erreurs décriture en mémoire sont particulièrement graves.
Notons que free
ne doit être appliquée quà des blocs alloués par malloc
, calloc
ou realloc
, sous peine derreurs très graves. Normalement, lappel de free
sur une valeur nulle est sans effet.
Exercice 3.8 |
Écrire une fonction qui ajoute deux chaînes lune à lautre. Il faudra allouer la mémoire nécessaire au résultat. On pourra utiliser les fonctions |
Voir solution |
Précédent | Sommaire | Suivant |