next up previous contents index
Next: Ré-allocation dynamique Up: No Title Previous: Bibliothèques

Allocation dynamique

    

Ce mode d'allocation, aussi appelé allocation sur le tas , est présent en Pascal comme en C, mais pas en Fortran 77. Un objet alloué dynamiquement ne résulte pas de la définition du nom qui le désigne, à la différence des objets statiques et automatiques, mais résulte d'un appel à la fonction malloc ; cet appel est nécessairement réalisé à l'intérieur d'une fonction puisque l'initialisation d'une variable globale ne peut se faire que par une expression constante, ce qui n'est pas le cas d'un appel de fonction.

On a vu que c'était une des façons d'initialiser un pointeur :

int *ip = malloc(sizeof(int));
 

La fonction malloc est déclarée dans stdlib.h. Elle prend en argument un nombre d'octets, alloue un bloc de mémoire de cette taille dans le tas , et retourne l'adresse de ce bloc, de type void*. La taille doit toujours être calculée à l'aide de l'opérateur  sizeof, qui appliqué à un type, donne la taille en octets des objets de ce type.

 

Une application importante de l'allocation dynamique est la simulation de tableaux dynamiques . Pour implémenter un << tableau >> de double dont la taille est lue sur l'entrée standard en cours d'exécution,     on crée un bloc dynamique :

int f() {
  double *t;
  int n, i;

  scanf("%d", &n);
  t = malloc(n * sizeof(double));
  for (i=0; i<n; i++) {
    scanf("%lf", &t[i]);
  }
  ...
  free(t);
  return ...;
}

Il faut noter que la variable t, comme toute variable locale, est allouée automatiquement ; la valeur qui lui est affectée est l'adresse d'un objet alloué dynamiquement, dans le tas. Soulignons aussi que t n'est pas un tableau, les tableaux étant soit globaux et alloués statiquement, soit locaux et alloués automatiquement sur la pile ; il n'y a pas de tableau dynamique en C. Bien que t ne soit pas un tableau, la notation t[i] est utilisable pour accéder aux éléments alloués consécutivement.

 Ces blocs dynamiques sont également utilisés pour permettre à une fonction de << retourner un tableau >>, ce qui, rappelons-le, est impossible (le type de retour d'une fonction ne peut être qu'un type simple, un type pointeur ou un struct). Pour contourner cette difficulté, il ne faut surtout pas commettre l'erreur de retourner l'adresse d'un tableau défini localement dans la fonction :

double *vecteur_add_faux(double x[], double y[]) {
  double z[3];
  int i;

  for(i=0; i<3; i++) {
    z[i] = x[i] + y[i];
  }
  return z;
}

En effet, l'allocation du tableau z étant automatique, le bloc alloué est aussi dés-alloué à la sortie de la fonction, donc la valeur retournée est l'adresse d'un bloc mémoire qui n'est plus alloué. Le résultat est alors imprévisible.

 

On doit plutôt, soit utiliser un tableau défini avant l'appel et le passer en argument, soit recourir à l'allocation dynamique à l'intérieur de la fonction pour allouer un bloc de mémoire où le résultat sera écrit ; la fonction retourne dans ce cas l'adresse du bloc alloué. On procède ainsi :

double *vecteur_add(double x[], double y[]) {
  int i;
  double *z = malloc(3*sizeof(double));

  for(i=0; i<3; i++) {
    z[i] = x[i] + y[i];
  }
  return z;
}

et on l'appelle ainsi :

  double x[] = {1.0, 2.0, 3.0};
  double y[] = {4.0, 5.0, 6.0};
  double *z = vecteur_add(x,y);
  ...
  free(z);

Notons qu'il est possible d'utiliser un entier passé en paramètre pour spécifier la taille du bloc dynamique, alors qu'une définition d'un tableau local utilisant ce paramètre, de la forme << double z[m]; >>, est incorrecte[*] :

double *vecteur_add(int n, double x[], double y[]) {
  int i;
  double *z = malloc(n*sizeof(double));

  for(i=0; i<n; i++) {
    z[i] = x[i] + y[i];
  }
  return z;
}

next up previous contents index
Next: Ré-allocation dynamique Up: No Title Previous: Bibliothèques
Jean-Philippe Chancelier
9/29/1998