Allocation dynamique de la mémoire en c
Comme C est un langage structuré, il a des règles fixes pour la programmation. L'un d'entre eux inclut la modification de la taille d'un tableau. Un tableau est une collection d'éléments stockés dans des emplacements de mémoire continus.
Comme on peut voir que la longueur (taille) du tableau ci-dessus est égale à 8. Mais que se passe-t-il s’il est nécessaire de modifier cette longueur (taille). Par exemple, s'il existe une situation dans laquelle il ne faut que 5 éléments à entrer dans ce tableau. Dans ce cas, les 3 indices restants ne font que gaspiller de la mémoire dans ce tableau. Il est donc nécessaire de réduire la longueur (la taille) du tableau de 8 à 5.
Prenons une autre situation. En cela, il y a un tableau de 8 éléments avec tous les 8 indices remplis. Mais il est nécessaire d’entrer 3 autres éléments dans ce tableau. Dans ce cas, 3 indices supplémentaires sont nécessaires. Donc, la longueur (taille) du tableau doit être changée de 8 à 11.
Cette procédure est appelée allocation dynamique de la mémoire.
Par conséquent, l'allocation dynamique de la mémoire peut être définie comme une procédure dans laquelle la taille d'une structure de données (telle que les tableaux) est modifiée au cours de l'exécution.
C fournit certaines fonctions pour accomplir ces tâches. Il existe 4 fonctions de bibliothèque fournies par C définies sous le fichier d'en-tête <stdlib.h> pour faciliter l'allocation dynamique de mémoire en programmation C. Elles sont:
- malloc()
- calloc()
- free()
- realloc()
malloc()
La méthode “malloc” ou "allocation de la mémoire" est utilisée pour allouer de manière dynamique un seul grand bloc de mémoire avec la taille spécifiée. Il retourne un pointeur de type void pouvant être transformé en un pointeur de n'importe quelle forme.
- cast-type: type de pointeur.
- byte-size : taille du bloc
Exemple 1 :
int *ptr; // Puisque la taille de int est de 4 octets, // cette instruction allouera 40 octets de mémoire. // Et le pointeur ptr contient l'adresse // du premier octet dans la mémoire allouée. ptr = (int*) malloc(10 * sizeof(int));
Exemple 2 :
#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(0); } else{ printf("Mémoire allouée avec succès avec malloc \n"); for(i=0 ; i < 5 ; i++){ // *(tab+i) ou tab[i] *(tab+i)=i; } printf("Les éléments du tableau sont: "); for(i=0 ; i < 5 ; i++){ // *(tab+i) ou tab[i] printf("%d, ", *(tab+i)); } } return 0; }
Les éléments du tableau sont: 0, 1, 2, 3, 4
calloc()
La méthode “calloc” ou “allocation contiguë” est utilisée pour allouer dynamiquement le nombre spécifié de blocs de mémoire du type spécifié. Il initialise chaque bloc avec la valeur par défaut ‘0’.
- cast-type: type de pointeur.
- n : nombre d'éléments
- element-size : taille du bloc
Exemple 3 :
int *ptr; // alloue un espace contigu en mémoire // pour 10 éléments chacun avec la taille d'un entier. ptr = (int*) calloc(10, sizeof(int));
Exemple 4 :
#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(0); } else{ printf("Mémoire allouée avec succès avec malloc \n"); for(i=0 ; i < 5 ; i++){ // *(tab+i) ou tab[i] *(tab+i)=i; } printf("Les éléments du tableau sont: "); for(i=0 ; i < 5 ; i++){ // *(tab+i) ou tab[i] printf("%d, ", *(tab+i)); } } return 0; }
calloc() vs malloc()
Initialisation
malloc() alloue un bloc de mémoire de taille donnée (en octets) et renvoie un pointeur au début du bloc. malloc() n’initialise pas la mémoire allouée. Si nous essayons d’accéder au contenu du bloc mémoire, nous obtiendrons des valeurs d'ordures.
calloc() alloue la mémoire et initialise également le bloc de mémoire alloué à zéro. Si nous essayons d’accéder au contenu de ces blocs, nous aurons 0.
Nombre d'arguments
Contrairement à malloc(), calloc() prend deux arguments:
- Nombre de blocs à allouer.
- Taille de chaque bloc.
Valeur de retour
Après une affectation réussie dans malloc() et calloc(), un pointeur sur le bloc de mémoire est renvoyé, sinon la valeur NULL est renvoyée, ce qui indique l'échec de l'attribution.
free()
La méthode "free" est utilisée pour désallouer dynamiquement la mémoire. La mémoire allouée à l'aide des fonctions malloc() et calloc() n'est pas désaffectée d'elle-même. Par conséquent, la méthode free() est utilisée chaque fois que l’allocation de mémoire dynamique a lieu. Cela aide à réduire le gaspillage de mémoire en le libérant.
Exemple 5 :
#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(0); } else{ printf("Mémoire allouée avec succès avec malloc \n"); for(i=0 ; i < 5 ; i++){ // *(tab+i) ou tab[i] *(tab+i)=i; } printf("Les éléments du tableau sont: "); for(i=0 ; i < 5 ; i++){ // *(tab+i) ou tab[i] printf("%d, ", *(tab+i)); } // liberer l'espace reservé par tab free(tab); } return 0; }
Notez que la fonction free n'accepte pas la taille en tant que paramètre. Comment la fonction free() sait-elle la quantité de mémoire à libérer à l'aide d'un pointeur?
realloc()
La méthode “realloc” ou “réallocation” est utilisée pour modifier dynamiquement l’allocation mémoire d’une mémoire allouée précédemment. En d'autres termes, si la mémoire allouée précédemment à l'aide de malloc ou calloc est insuffisante, realloc peut être utilisé pour réaffecter dynamiquement de la mémoire.
Exemple 6 :
#include < stdio.h> #include < stdlib.h> int main(void){ int *tab; int i, n; tab=(int*)calloc(5, sizeof(int)); if (tab == NULL) { printf("Mémoire non allouée.\n"); exit(0); } else{ printf("Mémoire allouée avec succès avec malloc \n"); for(i=0 ; i < 5 ; i++){ // *(tab+i) ou tab[i] *(tab+i)=i; } printf("Les éléments du tableau sont: "); for(i=0 ; i < 5 ; i++){ // *(tab+i) ou tab[i] printf("%d, ", *(tab+i)); } // nouvelle taille n=10; tab=realloc(tab, n * sizeof(int)); for(i=5 ; i < n ; i++){ *(tab+i)=i; } printf("Les éléments du tableau après la “réallocation” sont : "); for(i=0 ; i < n ; i++){ // *(tab+i) ou tab[i] printf("%d, ", *(tab+i)); } // liberer l'espace reservé par tab free(tab); } return 0; }
Les éléments du tableau sont: 0, 1, 2, 3, 4,
Les éléments du tableau après la “réallocation” sont : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Qu’est-ce que la fuite de mémoire?
Une fuite de mémoire se produit lorsque les programmeurs créent une mémoire dans le tas et oublient de la supprimer.
Les fuites de mémoire sont des problèmes particulièrement graves pour des programmes tels que les démons et les serveurs qui, par définition, ne se terminent jamais.
Exemple 7 :
#include < stdlib.h> void test(){ int *ptr; ptr=(int *) malloc(sizeof(int)); // Retour sans libérer ptr return; }
Pour éviter les fuites de mémoire, la mémoire allouée sur le segment de mémoire doit toujours être libérée lorsqu'elle n'est plus utilisée.
Exemple 8 :
#include < stdlib.h> void test(){ int *ptr; ptr=(int *) malloc(sizeof(int)); free(ptr); return; }