Allocation dynamique de la mémoire en C
En C, la taille d'un tableau déclaré classiquement est fixée à la compilation. Si on déclare int tab[8] et qu'on n'utilise que 5 éléments, 3 cases sont gaspillées. Inversement, si on a besoin de 11 éléments, il n'y a pas de place. L'allocation dynamique résout ce problème en permettant de réserver et d'ajuster la mémoire à l'exécution.

C fournit 4 fonctions dans <stdlib.h> pour gérer l'allocation dynamique :
| Fonction | Rôle | Initialise à 0 ? | Arguments |
|---|---|---|---|
malloc() | Allouer un bloc de mémoire | Non (valeurs indéterminées) | Taille en octets |
calloc() | Allouer n blocs initialisés à zéro | Oui | Nombre d'éléments + taille d'un élément |
realloc() | Redimensionner un bloc existant | Non (données conservées) | Pointeur existant + nouvelle taille |
free() | Libérer un bloc alloué | — | Pointeur à libérer |
1. malloc() — Allocation simple
malloc malloc (memory allocation) alloue un bloc contigu de n octets sur le tas et retourne un pointeur void * vers le début du bloc. Le contenu du bloc est indéterminé (valeurs quelconques).malloc C#include <stdlib.h>
ptr = (type *) malloc(n * sizeof(type));
/* Exemple : tableau de 10 entiers */
int *ptr = (int *) malloc(10 * sizeof(int));
/* Alloue 10 × 4 = 40 octets sur le tas
ptr pointe vers le premier octet du bloc */malloc Si la mémoire disponible est insuffisante, malloc retourne NULL. Toujours vérifier avant d'utiliser le pointeur :int *ptr = (int *) malloc(n * sizeof(int));
if (ptr == NULL)
{
fprintf(stderr, "Erreur : allocation échouée\n");
exit(1);
}Exemple n°1 — Allocation, remplissage et affichage avec malloc
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *tab;
int i;
tab = (int *) malloc(5 * sizeof(int));
if (tab == NULL)
{
printf("Mémoire non allouée.\n");
exit(1);
}
printf("Mémoire allouée avec succès (malloc)\n");
/* Remplissage */
for (i = 0; i < 5; i++)
tab[i] = i; /* équivalent à *(tab+i) = i */
/* Affichage */
printf("Éléments : ");
for (i = 0; i < 5; i++)
printf("%d ", tab[i]);
printf("\n");
free(tab);
tab = NULL;
return 0;
}Mémoire allouée avec succès (malloc) Éléments : 0 1 2 3 4
2. calloc() — Allocation avec initialisation à zéro
calloc calloc (contiguous allocation) alloue n éléments de taille donnée et initialise tous les octets à zéro. C'est l'équivalent d'un malloc suivi d'un memset(ptr, 0, …).calloc Cptr = (type *) calloc(n, sizeof(type));
/* Exemple : tableau de 10 entiers initialisés à 0 */
int *ptr = (int *) calloc(10, sizeof(int));Exemple n°2 — Allocation avec calloc : valeurs initiales à 0
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *tab;
int i;
tab = (int *) calloc(5, sizeof(int));
if (tab == NULL)
{
printf("Mémoire non allouée.\n");
exit(1);
}
/* Avant modification — tous les éléments valent 0 */
printf("Avant remplissage : ");
for (i = 0; i < 5; i++)
printf("%d ", tab[i]);
printf("\n");
/* Remplissage */
for (i = 0; i < 5; i++)
tab[i] = i * 2;
printf("Après remplissage : ");
for (i = 0; i < 5; i++)
printf("%d ", tab[i]);
printf("\n");
free(tab);
tab = NULL;
return 0;
}Avant remplissage : 0 0 0 0 0 Après remplissage : 0 2 4 6 8
3. malloc vs calloc
| Critère | malloc | calloc |
|---|---|---|
| Nombre d'arguments | 1 — taille totale en octets | 2 — nombre d'éléments + taille d'un élément |
| Initialisation | Non — valeurs indéterminées ("garbage") | Oui — tous les octets à 0 |
| Vitesse | Plus rapide (pas de mise à zéro) | Légèrement plus lente |
| Valeur de retour | void * ou NULL si échec | void * ou NULL si échec |
| Cas d'usage | Quand on va remplir le bloc immédiatement | Quand on a besoin d'un bloc initialement vide |
malloc quand le bloc sera rempli immédiatement (copie, saisie…) — pas besoin de payer le coût de la mise à zéro. Préférer calloc quand on a besoin de partir de zéros, par exemple pour un tableau de compteurs ou une matrice nulle.4. free() — Libérer la mémoire
free free(ptr) restitue au système le bloc mémoire pointé par ptr, qui doit avoir été alloué par malloc, calloc ou realloc. Après un free, le pointeur devient invalide (dangling pointer) — il faut le mettre à NULL.free Cfree(ptr);
ptr = NULL; /* bonne pratique — évite le pointeur dangling */free connaît-il la taille à libérer ? Lors de l'allocation, le gestionnaire de mémoire stocke la taille du bloc dans un mot caché juste avant l'adresse retournée. free(ptr) lit ce mot pour savoir combien d'octets restituer — d'où l'absence de paramètre de taille.Exemple n°3 — Utilisation correcte de free
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *tab;
int i;
tab = (int *) calloc(5, sizeof(int));
if (tab == NULL) { printf("Allocation échouée\n"); exit(1); }
for (i = 0; i < 5; i++)
tab[i] = i;
printf("Éléments : ");
for (i = 0; i < 5; i++)
printf("%d ", tab[i]);
printf("\n");
free(tab); /* restitution de la mémoire */
tab = NULL; /* évite tout accès accidentel ultérieur */
return 0;
}Éléments : 0 1 2 3 4
free(ptr)deux fois sur le même pointeur corrompt le gestionnaire de tas et peut provoquer un comportement indéfini ou une faille de sécurité :free(ptr);
free(ptr); /* comportement indéfini — NE PAS FAIRE */
/* Solution : mettre à NULL après free */
free(ptr);
ptr = NULL;
free(ptr); /* free(NULL) est sans effet — sans danger */5. realloc() — Redimensionner un bloc
realloc realloc modifie la taille d'un bloc précédemment alloué. Les données existantes sont conservées (jusqu'à l'ancienne taille). Si un déplacement est nécessaire, realloc copie automatiquement les données vers le nouvel emplacement et libère l'ancien bloc.realloc Cptr = (type *) realloc(ptr, nouvelle_taille);
/* Exemple : agrandir un tableau de 5 à 10 entiers */
tab = (int *) realloc(tab, 10 * sizeof(int));realloc échoue, il retourne NULL et l'ancien bloc n'est pas libéré. Écraser directement le pointeur original entraîne une fuite mémoire :/* Incorrect — fuite si realloc échoue */
tab = (int *) realloc(tab, n * sizeof(int));
/* Correct — préserver l'accès à l'ancien bloc */
int *tmp = (int *) realloc(tab, n * sizeof(int));
if (tmp == NULL)
{
fprintf(stderr, "realloc échoué\n");
free(tab); /* libérer l'ancien bloc */
exit(1);
}
tab = tmp;Exemple n°4 — Agrandir un tableau de 5 à 10 éléments avec realloc
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *tab;
int *tmp;
int i, n;
/* Allocation initiale — 5 éléments */
tab = (int *) calloc(5, sizeof(int));
if (tab == NULL) { printf("Allocation échouée\n"); exit(1); }
for (i = 0; i < 5; i++)
tab[i] = i;
printf("Avant realloc : ");
for (i = 0; i < 5; i++) printf("%d ", tab[i]);
printf("\n");
/* Agrandissement à 10 éléments */
n = 10;
tmp = (int *) realloc(tab, n * sizeof(int));
if (tmp == NULL) { fprintf(stderr, "realloc échoué\n"); free(tab); exit(1); }
tab = tmp;
/* Remplissage des nouvelles cases */
for (i = 5; i < n; i++)
tab[i] = i;
printf("Après realloc : ");
for (i = 0; i < n; i++) printf("%d ", tab[i]);
printf("\n");
free(tab);
tab = NULL;
return 0;
}Avant realloc : 0 1 2 3 4 Après realloc : 0 1 2 3 4 5 6 7 8 9
6. Fuites mémoire
Exemple n°5 — Fuite mémoire : retour sans libération
#include <stdlib.h>
/* INCORRECT — fuite mémoire */
void test_fuite()
{
int *ptr = (int *) malloc(sizeof(int));
*ptr = 42;
return; /* ptr non libéré — 4 octets perdus à chaque appel */
}
/* CORRECT — libération avant le retour */
void test_correct()
{
int *ptr = (int *) malloc(sizeof(int));
if (ptr == NULL) return;
*ptr = 42;
free(ptr); /* mémoire restituée */
ptr = NULL;
}/* Compilation avec informations de débogage */
gcc -g programme.c -o programme
/* Exécution sous Valgrind */
valgrind --leak-check=full ./programmeRécapitulatif
| Fonction | Syntaxe | Init à 0 | Point clé |
|---|---|---|---|
malloc | malloc(n * sizeof(T)) | Non | Rapide — vérifier retour ≠ NULL |
calloc | calloc(n, sizeof(T)) | Oui | Utile pour compteurs, matrices nulles |
realloc | realloc(ptr, new_n * sizeof(T)) | Non | Utiliser un pointeur temporaire |
free | free(ptr); ptr = NULL; | — | Toujours mettre à NULL après free |
| Règle d'or | Conséquence si non respectée |
|---|---|
Un malloc = un free | Fuite mémoire |
Vérifier le retour de malloc/calloc/realloc | Déréférencement de NULL → segfault |
| Ne jamais libérer deux fois le même pointeur | Corruption du tas, comportement indéfini |
Mettre ptr = NULL après free | Pointeur dangling — accès mémoire invalide |
Utiliser un pointeur temporaire avec realloc | Perte de l'ancien pointeur si échec → fuite |
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.