Allocation mémoire dynamique en C : Maîtriser malloc, calloc, realloc et free
Avant de plonger dans l'allocation mémoire dynamique en C, il est essentiel de comprendre comment la mémoire est gérée dans le langage.
Comment fonctionne la gestion de la mémoire en C
Quand vous déclarez une variable avec un type primitif, le compilateur alloue automatiquement de l'espace pour elle sur la pile (stack). Par exemple, un float occupe typiquement 4 octets (dépendant de la plateforme). Vous pouvez confirmer cela avec l'opérateur sizeof :
#include <stdio.h>
int main() {
float x;
printf("The size of float is %d bytes", sizeof(x));
return 0;
}
La sortie sera :
The size of float is 4 bytes
Un tableau de taille spécifiée est aussi alloué contiguement sur la pile, chaque élément occupant la taille de son type :
#include <stdio.h>
int main() {
float arr[10];
printf("The size of the float array with 10 elements is %d", sizeof(arr));
return 0;
}
Le résultat est :
The size of the float array with 10 elements is 40
Bien que l'allocation sur pile soit automatique, de nombreux programmes nécessitent de la mémoire dont la taille n'est pas connue avant l'exécution. Ce besoin est adressé par l'allocation mémoire dynamique, qui utilise le tas (heap) au lieu de la pile.
Allocation mémoire dynamique en C
L'allocation dynamique implique de demander et libérer manuellement la mémoire selon les besoins, avec des pointeurs suivant les blocs alloués sur le tas. La bibliothèque standard C fournit plusieurs fonctions pour cela :
- malloc() – Alloue un bloc contigu d'octets et retourne un pointeur vers son premier octet.
- calloc() – Alloue un tableau d'éléments, initialise tous les octets à zéro, et retourne un pointeur vers le premier élément.
- realloc() – Redimensionne un bloc précédemment alloué, en préservant son contenu.
- free() – Libère un bloc précédemment alloué de retour au tas.
Explorons chaque fonction en détail.
Fonction malloc()
La fonction malloc() signifie « memory allocation ». Elle réserve un bloc de mémoire de taille spécifiée et retourne un pointeur vers celui-ci. Le pointeur est généralement casté vers le type désiré :
ptr = (type_cast *) malloc(taille_octets);
Exemple :
#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* 15 entiers */
if (ptr != NULL) {
*(ptr + 5) = 480; /* sixième élément */
printf("Value of the 6th integer is %d", *(ptr + 5));
}
}
Sortie :
Value of the 6th integer is 480
Points clés :
- Utilisez
sizeof(*ptr)pour rendre le code robuste contre les changements de type. - Vérifiez une valeur de retour
NULLpour détecter l'échec d'allocation. - La mémoire allouée est contiguë ; traitez-la comme un tableau et utilisez l'arithmétique de pointeurs.
L'allocation dynamique n'est pas limitée aux types primitifs ; elle fonctionne avec les structures, tableaux de caractères, et plus.
Fonction free()
La mémoire allouée avec malloc(), calloc() ou realloc() doit être libérée explicitement pour éviter les fuites. La fonction free() effectue cette tâche :
#include <stdio.h>
int main() {
int* ptr = malloc(10 * sizeof(*ptr));
if (ptr != NULL){
*(ptr + 2) = 50;
printf("Value of the 2nd integer is %d", *(ptr + 2));
}
free(ptr);
}
Sortie :
Value of the 2nd integer is 50
Fonction calloc()
calloc() alloue plusieurs blocs de taille égale et initialise chaque octet à zéro, le rendant idéal pour les tableaux et structures nécessitant une mémoire initialisée à zéro :
ptr = (type_cast *) calloc(n, taille);
Exemple – sommer une suite arithmétique :
#include <stdio.h>
int main() {
int i, *ptr, sum = 0;
ptr = calloc(10, sizeof(int));
if (ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
for (i = 0; i < 10; ++i) {
*(ptr + i) = i;
sum += *(ptr + i);
}
printf("Sum = %d", sum);
free(ptr);
return 0;
}
Résultat :
Sum = 45
calloc() vs malloc()
Différences clés :
- Initialisation :
calloc()met la mémoire à zéro ;malloc()la laisse non initialisée (valeurs indéterminées). - Usage :
calloc()est préférable pour les tableaux ou structures nécessitant des valeurs à zéro ;malloc()est plus simple quand aucune initialisation n'est requise. - Performance : Les deux performent de manière similaire, mais
calloc()peut être légèrement plus lent à cause de la mise à zéro.
Fonction realloc()
La fonction realloc() change la taille d'une allocation existante tout en préservant son contenu :
ptr = realloc(ptr, nouvelle_taille);
Exemple – étendre un tampon de chaîne :
#include <stdio.h>
int main () {
char *ptr = malloc(10);
strcpy(ptr, "Programming");
ptr = realloc(ptr, 20); // agrandir
strcat(ptr, " In 'C'");
printf("%s, Address = %u", ptr, ptr);
free(ptr);
return 0;
}
Si la réallocation échoue, realloc() retourne NULL et le bloc original reste valide.
Tableaux dynamiques
Les tableaux dynamiques permettent au nombre d'éléments de croître pendant l'exécution, un motif courant dans les algorithmes et structures de données :
#include <stdio.h>
int main() {
int *arr_dynamic = NULL;
int elements = 2, i;
arr_dynamic = calloc(elements, sizeof(int));
for (i = 0; i < elements; i++)
arr_dynamic[i] = i;
for (i = 0; i < elements; i++)
printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
elements = 4;
arr_dynamic = realloc(arr_dynamic, elements * sizeof(int));
printf("After realloc\n");
for (i = 2; i < elements; i++)
arr_dynamic[i] = i;
for (i = 0; i < elements; i++)
printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
free(arr_dynamic);
}
Résultat :
arr_dynamic[0]=0 arr_dynamic[1]=1 After realloc arr_dynamic[0]=0 arr_dynamic[1]=1 arr_dynamic[2]=2 arr_dynamic[3]=3
Résumé
- La mémoire dynamique vous permet d'allouer et libérer de l'espace sur le tas à l'exécution.
- Utilisez
malloc()pour les blocs uniques,calloc()pour les tableaux initialisés à zéro. - Vérifiez toujours
NULLpour détecter les échecs d'allocation. - Libérez la mémoire avec
free()pour éviter les fuites. - Redimensionnez les allocations avec
realloc()quand plus d'espace est nécessaire. - Les tableaux dynamiques sont un motif puissant pour les structures de données flexibles.
Langue C
- Comprendre ROM, PROM, EPROM et EEPROM : conception, programmation et identification
- Fondamentaux C# : Entrées et sorties essentielles
- Maîtriser les directives using C# : Imports, alias et directives static
- Maîtriser la gestion de mémoire en C++ : Utilisation experte de new et delete
- Quatre modèles éprouvés pour les fonctions définies par l'utilisateur en C
- Allocation dynamique de mémoire en C : Maîtriser malloc, calloc, realloc et free
- Maîtriser les fonctions de la bibliothèque standard C : Guide pratique
- Maîtriser l'allocation de tableaux dynamiques en C++ : Guide pratique avec exemples de code
- Les Fonctions en C++ Expliquées avec des Exemples de Code Pratiques