Gestion dynamique de la mémoire

Ce cours explique la gestion dynamique de la mémoire en langage C. Il détaille l'utilisation des fonctions malloc, free et realloc pour manipuler des tableaux et matrices dynamiques.

D'après le document Gestion dynamique de la mémoire

Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Gestion dynamique de la mémoire

Document source

Gestion dynamique de la mémoire

Computer Science · PDF · 4 pages · 2011

Afficher l'aperçu du document

Consulter le document original →

Ce cours traite de la gestion dynamique de la mémoire en langage C, un sujet fondamental dans la programmation avancée. Il s'inscrit dans un module d'atelier de programmation destiné aux étudiants de première année, visant à comprendre comment allouer, utiliser et libérer la mémoire pendant l'exécution d'un programme, notamment lorsque la taille des données n'est pas connue à la compilation.

Déclaration statique et limites

La déclaration statique fixe la taille des variables dès la compilation, ce qui peut engendrer un gaspillage de mémoire. Dans un programme, chaque variable occupe un nombre précis d'octets en mémoire :

  • float A, B, C; réserve 12 octets (3 × 4 octets)
  • char E[] = {"Bonjour"}; réserve 8 octets (7 caractères + le caractère nul '\0')
  • double *g; réserve p octets, où p est la taille d'une adresse mémoire
  • char *h; réserve p octets
  • float *tab[10]; réserve 10 × p octets
  • char *J = "Bonjour"; réserve p + 8 octets
  • char *K[] = {"un", "deux", "trois", "quatre"}; réserve 4 × p + 3 + 5 + 6 + 7 octets

Quel que soit le type du pointeur (int *, char *, etc.), il occupe toujours la même taille en mémoire, soit p octets.

Le problème avec la déclaration statique est que souvent, le nombre et la taille des données ne peuvent pas être prévus à la compilation. Réserver systématiquement la taille maximale possible conduit à un gaspillage de mémoire. Il est donc nécessaire de gérer la mémoire dynamiquement pendant l'exécution.

Allocation dynamique avec malloc et sizeof

La fonction malloc permet de réserver dynamiquement un bloc de mémoire lors de l'exécution du programme. La fonction malloc de la bibliothèque stdlib.h prend en paramètre le nombre d'octets à allouer et retourne un pointeur vers ce bloc ou NULL si la mémoire est insuffisante.

Par exemple, pour réserver un bloc de 4000 octets destiné à contenir un texte de 4000 caractères :

char *T;
T = (char *)malloc(4000);

Si la mémoire est insuffisante, T vaut NULL.

L'opérateur sizeof est utilisé pour garantir la portabilité du programme en calculant la taille en octets d'un type ou d'une variable. Par exemple :

  • sizeof B où B est un tableau char B[5][10];, vaut 50
  • sizeof "Bonjour" vaut 8
  • sizeof(float) vaut 4
  • sizeof(double) vaut 8

Si l'allocation échoue, il est conseillé d'interrompre l'exécution du programme avec la fonction exit de stdlib.h.

Libération de mémoire avec free

La fonction free restituera à l'ordinateur les blocs de mémoire qui ne sont plus utilisés. Lorsque la mémoire allouée dynamiquement n'est plus nécessaire, elle doit être libérée :

free(<Pointeur>);

Cette fonction libère le bloc de mémoire pointé, mais ne modifie pas la valeur du pointeur. Il est recommandé d'affecter NULL au pointeur après la libération pour éviter les accès invalides :

free(tab);
tab = NULL;

Si la mémoire n'est pas libérée explicitement, elle sera automatiquement libérée à la fin du programme. Notez que free ne permet pas de libérer une partie seulement d'un bloc alloué.

Exemples d'utilisation : tableaux dynamiques

Les tableaux dynamiques permettent d'adapter la taille des structures de données aux besoins réels de l'utilisateur. Voici un exemple de programme qui alloue dynamiquement un tableau d'entiers de taille n, le remplit et l'affiche :

#include <stdio.h>
#include <stdlib.h>

void main() {
  int *tab, n, i;
  printf("saisir nbre éléments");
  scanf("%d", &n);
  tab = (int *)malloc(n * sizeof(int));
  for (i = 0; i < n; i++)
    scanf("%d", tab + i);
  for (i = 0; i < n; i++)
    printf("%d ", *(tab + i));
  free(tab);
  tab = NULL;
}

Une autre version utilise un pointeur t pour parcourir le tableau :

#include <stdio.h>
#include <stdlib.h>

void main() {
  int *tab, *t, n;
  printf("saisir nbre éléments");
  scanf("%d", &n);
  tab = (int *)malloc(n * sizeof(int));
  for (t = tab; t < tab + n; t++)
    scanf("%d", t);
  for (t = tab; t < tab + n; t++)
    printf("%d ", *t);
  free(tab);
  tab = NULL;
}

Modification de la taille avec realloc

La fonction realloc permet d'agrandir ou de réduire la taille d'un bloc mémoire déjà alloué. Ses deux principales fonctions sont :

  • Réduire la taille d'un bloc
  • Augmenter la taille tout en conservant le contenu

Exemple d'augmentation :

int *tab;
tab = (int *)malloc(100 * sizeof(int));
if (!tab) exit(-1);
tab = (int *)realloc(tab, 130 * sizeof(int));
if (!tab) exit(-2);

La fonction realloc peut déplacer le bloc en mémoire, mais elle garantit que le contenu initial est conservé. Le premier paramètre est l'adresse du bloc à redimensionner, le second la nouvelle taille en octets.

Si la nouvelle taille est inférieure à l'ancienne, le contenu du début du bloc reste inchangé.

Exemple avancé : fonctions d'allocation et manipulation

L'utilisation de fonctions dédiées permet d'encapsuler et de modulariser l'allocation dynamique dans un programme. Le programme suivant illustre cette approche :

#include <stdio.h>
#include <stdlib.h>

void allocation(int **p, int *n) {
  printf("saisir nbre éléments");
  scanf("%d", n);
  *p = (int *)malloc((*n) * sizeof(int));
  if (!*p) exit(-1);
}

void main() {
  int *tab, n;
  allocation(&tab, &n);
  remplir(tab, n);
  afficher(tab, n);
  free(tab);
  tab = NULL;
}

Une autre version utilise une fonction retournant un pointeur :

int *allocation2(int *n) {
  int *p;
  printf("saisir nbre éléments");
  scanf("%d", n);
  p = (int *)malloc((*n) * sizeof(int));
  if (!p) exit(-1);
  return p;
}

Gestion dynamique d'une matrice

La création d'une matrice dynamique repose sur l'allocation d'un tableau de pointeurs pointant chacun vers une ligne de données. Pour gérer une matrice dynamique de l lignes et c colonnes :

void saisir(int *l, int *c) {
  printf("saisir nbre de lignes    ");
  scanf("%i", l);
  printf("saisir nbre de colonnes    ");
  scanf("%i", c);
}

void allocation2(int ***m, int l, int c) {
  int i;
  *m = (int **)malloc(l * sizeof(int *));
  if (!*m) exit(-1);
  for (i = 0; i < l; i++) {
    *(*m + i) = (int *)malloc(c * sizeof(int));
    if (!*(*m + i)) exit(-2);
  }
}

int **allocation(int l, int c) {
  int i;
  int **t;
  t = (int **)malloc(l * sizeof(int *));
  if (!t) exit(-1);
  for (i = 0; i < l; i++) {
    *(t + i) = (int *)malloc(c * sizeof(int));
    if (!*(t + i)) exit(-2);
  }
  return t;
}

void remplir(int **t, int l, int c) {
  int i, j;
  for (i = 0; i < l; i++)
    for (j = 0; j < c; j++)
      scanf("%d", *(t + i) + j);
}

void afficher(int **t, int l, int c) {
  int i, j;
  for (i = 0; i < l; i++) {
    for (j = 0; j < c; j++)
      printf("%d ", *(*(t + i) + j));
    printf("\n");
  }
}

void main() {
  int l, c;
  int **t;
  saisir(&l, &c);
  t = allocation(l, c);
  remplir(t, l, c);
  afficher(t, l, c);
  // ou bien allocation2(&t, l, c);
}

Cette méthode permet de créer une matrice dont la taille est connue uniquement à l'exécution, en allouant dynamiquement chaque ligne.

Points clés

  • La mémoire statique est limitée et souvent insuffisante pour des données dont la taille est inconnue à la compilation.
  • malloc permet d'allouer dynamiquement un bloc mémoire de taille variable.
  • sizeof garantit la portabilité en calculant la taille en octets d'un type ou d'une variable.
  • free libère la mémoire allouée dynamiquement et il est conseillé de mettre le pointeur à NULL après.
  • realloc ajuste la taille d'un bloc mémoire existant tout en conservant son contenu.
  • Les tableaux dynamiques peuvent être manipulés via des pointeurs et des fonctions dédiées pour allocation, remplissage et affichage.
  • La gestion dynamique d'une matrice nécessite l'allocation d'un tableau de pointeurs vers des tableaux d'entiers.

Partager

Commentaires

Aucun commentaire pour le moment. Posez la première question.

Les commentaires sont relus avant publication. Votre e-mail n'est jamais affiché.

← Toutes les révisions