8PRO100 Éléments de programmation Allocation dynamique de la mémoire
Allocation statique et dynamique Jusqu’à maintenant, toutes la mémoire que nous avons utilisée dans nos programmes devait être allouée avant l'exécution à l’aide des déclarations de variables. Il est parfois utile d’allouer une partie de l’espace mémoire en cours d’exécution.
Exemple 1 Par exemple si on a besoin de mémoriser un certains nombre d’objets mais que ce nombre n’est pas connu avant l’exécution du programme. Il faut alors allouer suffisament d’espace au cas ou le nombre d’objets soit grand. Si le nombre d’objets est petits, on gaspille inutilement de l’espace mémoire.
Le fichier d’en-tête stdlib.h Le fichier d’entête stdlib.h contient des déclarations de fonctions traitant, entre autres, de l’allocation de la mémoire: - malloc - free - calloc - realloc
void *malloc(size_t s) size_t est un type d’entiers positifs. malloc retourne un pointeur sur un espace mémoire réservé à un objet de taille s, ou bien NULL si cette demande ne peut être satisfaite. La mémoire allouée n’est pas initialisée.
Exemple 2 int *p; *p = 10; /* INVALIDE puisque p ne pointe sur */ /* aucune case mémoire valide */ p = (int) malloc(sizeof(int)) *p = 10; /* VALIDE */ Avant malloc p: Après malloc p:
Exemple 2 int *p; *p = 10; /* INVALIDE puisque p ne pointe sur */ /* aucune case mémoire valide */ p = (int) malloc(sizeof(int)) *p = 10; /* VALIDE */ Pourquoi? Avant malloc p: Après malloc p:
Pointeurs sur void La fonction malloc ne sait pas à quoi servira l’espace mémoire qui lui est demandée. Elle ne sait pas quel type d’objet utilisera cet espace. Alors, elle retourne un pointeur générique qui peut être converti en n’inporte quel type de pointeur: un pointeur sur void
Conversion implicite En C, certaine conversion de type sont implicite: double x; int n; char c; n = c; /* un char est converti en un int */ c = n; /* un int est converti en un char */ x = n; /* un int est converti en un double */ n = x; /* un double est converti en un int */
Conversion explicite Dans toute expression, on peut forcer explicitement des conversions de types grâce à un opérateur unaire appelé cast. Dans la construction (nom de type) expression l’expression est convertie dans le type précisé (selon certaines règles).
Exemple 3 printf(“%d”, pow(2,3)); /* mauvaise façon */ printf(“%d”, (int) pow(2,3)); /* bonne façon */
Exemple 4 int *p; struct complexe *cplx; p = (int *) malloc(sizeof(int)); cplx = (struct complexe *) malloc(sizeof(struct complexe));
void free(void * p) free libère l’espace mémoire pointé par p; elle ne fait rien si p vaut NULL. p doit être un pointeur sur un espace mémoire alloué par malloc, calloc ou realloc.
void *calloc(size_t nobj, size_t s) calloc retourne un pointeur sur un espace mémoire réservé à un tableau de nobj objets, tous de taille s, ou bien NULL si cette demande ne peut pas être satisfaite. La mémoire allouée est initialisée par des zéros.
void *realloc(void *p, size_t s) realloc change en s la taille de l’objet pointé par p. Si la nouvelle taille est plus petite que l’ancienne, seul le début du contenu de l’objet est conservé. Si la nouvelle taille est plus grande, le contenu de l’objet est conservé, et l’espace mémoire supplémentaire n’est pas initialisé. realloc retourne un pointeur sur un nouvel espace mémoire, ou bien NULL si cette demande ne peut pas être satisfaite, auquel cas *p n’est pas modifié.
Exemple 5 On veut lire des entiers et les mettre en mémoire. Plutôt que de créer un tableau avant l’exécution, on utilise calloc pendant l’exécution. int *p, n; scanf(“%d”, &n); p = (int *) calloc(n, sizeof(int)); si plus tard cet espace n’est plus suffisant, alors on utilise: p = (int *) realloc(p, 2*n); … p:
Exemple 6 Liste chaînée struct Maillon{ int valeur; struct Maillon *suivant; }; typedef struct Maillon maillon; maillon *chaine, *p; chaine: p:
Exemple 6 chaine = (maillon*) malloc(sizeof(maillon)); chaine: p: valeur suivant chaine: p:
Exemple 6 chaine = (maillon*) malloc(sizeof(maillon)); chaine -> valeur = 8; chaine: 8 p:
Exemple 6 chaine -> suivant = (maillon*) malloc(sizeof(maillon)); 8
Exemple 6 p = chaine -> suivant; chaine: 8 p:
Exemple 6 p -> valeur = 5; chaine: 8 5 p:
Exemple 6 p -> suivant = (maillon*) malloc(sizeof(maillon)); 8 5 chaine: 8 5 p:
Exemple 6 p = p -> suivant; chaine: 8 5 p:
Exemple 6 p -> valeur = 13; p -> suivant = NULL; 8 5 13 chaine: p:
Exemple 6 p = chaine; while (p != NULL){ printf(“%d\n”, p->valeur); p = p->suivant; } chaine: 8 5 13 p:
Exemple 6 for (p=chaine; p!=NULL; p=p->suivant) printf(“%d\n”, p->valeur); chaine: 8 5 13 p: