Allocation dynamique de mémoire en C : malloc(), calloc()

⚡ Résumé intelligent

L'allocation dynamique de mémoire en C réserve et libère de la mémoire du tas au moment de l'exécution à l'aide des fonctions malloc(), calloc(), realloc() et free() de la bibliothèque stdlib.h, permettant aux programmes de dimensionner les tableaux et les structures de manière flexible lorsque les besoins sont inconnus avant l'exécution.

  • 🧠 Pile vs tas : Les variables de base utilisent la pile automatique, tandis que la mémoire dynamique réside sur le tas et est gérée manuellement par le biais de pointeurs.
  • 📦 malloc() : Réserve un bloc non initialisé de la taille d'octet demandée et renvoie un pointeur vide, ou NULL lorsque la mémoire est insuffisante.
  • (I.e. calloc (): Alloue plusieurs blocs pour les tableaux, initialise chaque octet à zéro et renvoie un pointeur vers le premier bloc.
  • (I.e. realloc() : Permet de redimensionner un bloc existant vers le haut ou vers le bas tout en préservant son contenu original à un nouvel emplacement éventuel.
  • 🧹 libre(): Libère la mémoire dans le tas ; chaque appel à malloc() ou calloc() nécessite un appel correspondant à free() pour éviter les fuites.
  • 🤖 Aide de l'IA : Les assistants IA et GitHub Copilot ébauchent le code d'allocation et signalent les appels free() manquants et les fuites.

Allocation dynamique de mémoire en C

Comment fonctionne la gestion de la mémoire en C ?

Lorsque vous déclarez une variable en utilisant un type de données de base, le compilateur C alloue automatiquement un espace mémoire pour la variable dans un pool de mémoire appelé la pile.

Par exemple, une variable de type float occupe généralement 4 octets (selon la plateforme) lors de sa déclaration. On peut vérifier cette information à l'aide de l'opérateur sizeof, comme illustré dans l'exemple ci-dessous.

#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

De plus, un tableau avec une taille spécifiée est alloué en blocs de mémoire contigus, chaque bloc a la taille d'un élément :

#include <stdio.h>
int main() { float arr[10];
printf("The size of the float array with 10 element is %d", sizeof(arr)); return 0;}

Le résultat est:

 The size of the float array with 10 element is 40

Comme nous l'avons vu jusqu'à présent, lors de la déclaration d'un type de données de base ou d'un tableau, la mémoire est gérée automatiquement. Cependant, il existe en C un processus d'allocation de mémoire qui permet d'implémenter un programme dont la taille du tableau est indéterminée jusqu'à l'exécution. Ce processus est appelé « allocation dynamique de mémoire ».

Allocation dynamique de mémoire en C

L'allocation dynamique de mémoire consiste à allouer et libérer manuellement de la mémoire en fonction des besoins de votre programme. La mémoire dynamique est gérée et accessible via des pointeurs qui indiquent l'espace mémoire nouvellement alloué dans une zone appelée le tas.

Vous pouvez désormais créer et détruire un tableau d’éléments de manière dynamique lors de l’exécution sans aucun problème. Pour résumer, la gestion automatique de la mémoire utilise la pile, et l'allocation dynamique de mémoire C utilise le tas.

Le La bibliothèque a des fonctions responsables de la gestion dynamique de la mémoire.

Fonction Interet
malloc () Alloue la mémoire de la taille demandée et renvoie le pointeur sur le premier octet de
espace alloué.
calloc() Alloue de l'espace pour les éléments d'un tableau. Initialise les éléments à zéro et renvoie un pointeur vers la mémoire.
réalloc() Il permet de modifier la taille de l'espace mémoire précédemment alloué.
Gratuit() Libère ou vide l'espace mémoire précédemment alloué.

Discutons des fonctions ci-dessus avec leur application

fonction malloc() en C

La fonction C malloc() signifie allocation de mémoire. C'est une fonction qui permet d'allouer dynamiquement un bloc de mémoire. Il réserve un espace mémoire d'une taille spécifiée et renvoie le pointeur nul pointant vers l'emplacement mémoire. Le pointeur renvoyé est généralement de type void. Cela signifie que nous pouvons attribuer la fonction C malloc() à n’importe quel pointeur.

Syntaxe de la fonction malloc() :

ptr = (cast_type *) malloc (byte_size);

Ici,

  • ptr est un pointeur de cast_type.
  • La fonction C malloc() renvoie un pointeur vers la mémoire allouée de byte_size.

Exemple de malloc() :

Example: ptr = (int *) malloc (50)

Lorsque cette instruction est exécutée avec succès, un espace mémoire de 50 octets est réservé. L'adresse du premier octet de l'espace réservé est affectée au pointeur ptr de type int.

Prenons un autre exemple :

#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */
    if (ptr != NULL) {
      *(ptr + 5) = 480; /* assign 480 to sixth integer */
      printf("Value of the 6th integer is %d",*(ptr + 5));
    }
}

Sortie :

Value of the 6th integer is 480

Fonction C malloc()

  1. Notez que sizeof(*ptr) a été utilisé au lieu de sizeof(int) afin de rendre le code plus robuste lorsque la déclaration *ptr est convertie en un type de données différent ultérieurement.
  2. L'allocation peut échouer si la mémoire n'est pas suffisante. Dans ce cas, il renvoie un pointeur NULL. Vous devez donc inclure du code pour rechercher un pointeur NULL.
  3. Gardez à l’esprit que la mémoire allouée est contiguë et qu’elle peut être traitée comme un tableau. Nous pouvons utiliser l'arithmétique du pointeur pour accéder aux éléments du tableau plutôt que d'utiliser des crochets [ ]. Nous conseillons d'utiliser + pour faire référence aux éléments du tableau car l'utilisation de l'incrémentation ++ ou += modifie l'adresse stockée par le aiguille.

La fonction Malloc() peut également être utilisée avec le type de données caractère ainsi qu'avec des types de données complexes tels que les structures.

fonction free() en C

La mémoire pour les variables est automatiquement libéré au moment de la compilation. Dans l'allocation dynamique de mémoire, vous devez libérer explicitement la mémoire. Si ce n'est pas fait, vous risquez de rencontrer une erreur de mémoire insuffisante.

La fonction free() est appelée pour libérer de la mémoire en C. En libérant de la mémoire dans votre programme, vous en rendez davantage disponible pour une utilisation ultérieure.

Par exemple :

#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() en C

La fonction C calloc() signifie allocation contiguë. Cette fonction est utilisée pour allouer plusieurs blocs de mémoire. Il s'agit d'une fonction d'allocation dynamique de mémoire qui est utilisée pour allouer de la mémoire à des structures de données complexes telles que des tableaux et des structures.

La fonction Malloc() est utilisée pour allouer un seul bloc d’espace mémoire tandis que la fonction calloc() en C est utilisée pour allouer plusieurs blocs d’espace mémoire. Chaque bloc alloué par la fonction calloc() est de la même taille.

Syntaxe de la fonction calloc() :

ptr = (cast_type *) calloc (n, size);

L'instruction ci-dessus est utilisée pour allouer n blocs de mémoire de même taille.

Une fois l’espace mémoire alloué, tous les octets sont initialisés à zéro.

Le pointeur qui se trouve actuellement sur le premier octet de l'espace mémoire alloué est renvoyé.

Chaque fois qu'il y a une erreur lors de l'allocation de l'espace mémoire, telle qu'un manque de mémoire, un pointeur nul est renvoyé.

Exemple de calloc() :

Le programme ci-dessous calcule la somme d'une séquence 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);
        }
        printf("Building and calculating the sequence sum of the first 10 terms \ n ");
        for (i = 0; i < 10; ++i) { * (ptr + i) = i;
            sum += * (ptr + i);
        }
        printf("Sum = %d", sum);
        free(ptr);
        return 0;
    }

Résultat:

Building and calculating the sequence sum of the first 10 terms
Sum = 45

calloc() et malloc() : différences clés

Voici la principale différence entre malloc() contre calloc() en C:

La fonction calloc() est généralement plus adaptée et efficace que celle de la fonction malloc(). Alors que les deux fonctions sont utilisées pour allouer de l'espace mémoire, calloc() peut allouer plusieurs blocs à la fois. Vous n'êtes pas obligé de demander un bloc de mémoire à chaque fois. La fonction calloc() est utilisée dans des structures de données complexes qui nécessitent un espace mémoire plus grand.

Le bloc mémoire alloué par un calloc() en C est toujours initialisé à zéro alors que dans la fonction malloc() en C, il contient toujours une valeur poubelle.

fonction realloc() en C

La fonction C `realloc()` permet d'augmenter la taille de la mémoire allouée. Elle agrandit le bloc courant tout en conservant son contenu initial. En C, `realloc()` signifie « réallocation de mémoire ».

realloc() peut également être utilisé pour réduire la taille de la mémoire précédemment allouée.

Syntaxe de la fonction realloc() :

ptr = realloc (ptr,newsize);

L'instruction ci-dessus alloue un nouvel espace mémoire avec une taille spécifiée dans la variable newsize. Après avoir exécuté la fonction, le pointeur sera renvoyé sur le premier octet du bloc mémoire. La nouvelle taille peut être plus grande ou plus petite que la mémoire précédente. Nous ne pouvons pas être sûrs que le bloc nouvellement alloué pointera vers le même emplacement que celui du bloc mémoire précédent. Cette fonction copiera toutes les données précédentes dans la nouvelle région. Il garantit que les données resteront en sécurité.

Exemple de realloc() :

#include <stdio.h>
int main () {
   char *ptr;
   ptr = (char *) malloc(10);
   strcpy(ptr, "Programming");
   printf(" %s,  Address = %u\n", ptr, ptr);

   ptr = (char *) realloc(ptr, 20); //ptr is reallocated with new size
   strcat(ptr, " In 'C'");
   printf(" %s,  Address = %u\n", ptr, ptr);
   free(ptr);
   return 0;
}

Chaque fois que realloc() en C aboutit à une opération infructueuse, il renvoie un pointeur nul et les données précédentes sont également libérées.

Tableaux dynamiques en C

Un tableau dynamique en C permet au nombre d'éléments d'augmenter selon les besoins. Les tableaux dynamiques C sont largement utilisés dans les algorithmes informatiques.

Dans le programme suivant, nous avons créé et redimensionné un tableau dynamique dans C

#include <stdio.h>
    int main() {
        int * arr_dynamic = NULL;
        int elements = 2, i;
        arr_dynamic = calloc(elements, sizeof(int)); //Array with 2 integer blocks
        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)); //reallocate 4 elements
        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 du programme C Dynamic array à l'écran :

 
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

FAQ

Une fuite de mémoire se produit lorsque la mémoire allouée par `malloc()` ou `calloc()` n'est jamais libérée. Pour l'éviter, il est recommandé d'associer chaque allocation à un appel à `free()` dès que le bloc n'est plus nécessaire.

Un pointeur non initialisé contient encore l'adresse mémoire libérée par `free()`. Le déréférencer provoque un comportement indéfini ; par conséquent, assignez immédiatement la valeur `NULL` au pointeur après la libération pour éviter tout risque.

Non. Le langage C ne possède pas de ramasse-miettes ; la mémoire du tas n'est donc jamais libérée automatiquement. Le programmeur doit libérer explicitement chaque bloc avec `free()`, sinon l'allocation persiste jusqu'à la fin du programme.

Non. Appeler deux fois la fonction `free()` sur la même adresse mémoire provoque une double libération et peut entraîner un comportement indéfini ou un plantage. Initialiser le pointeur à `NULL` après le premier appel à `free()` rend les appels suivants sans conséquence.

La fonction `realloc(NULL, size)` se comporte exactement comme `malloc(size)` et alloue un nouveau bloc. `realloc(ptr, 0)` libère le bloc ; il est donc impératif de toujours récupérer le pointeur retourné plutôt que d'écraser le pointeur d'origine.

Des outils tels que Valgrind, AddressSanitizer et Dr. Memory track chaque bloc d'allocation et de rapport qui n'a jamais été libéré, ainsi que la ligne exacte, helping Vous localisez les fuites avant la mise en production.

Oui. Un assistant de programmation IA génère les séquences `malloc()`, `calloc()` et `free()` à partir d'une invite de commande, explique les erreurs de pointeurs et signale les appels `free()` manquants. Il est impératif de compiler et de tester le code généré avant de lui faire confiance.

Copilote GitHub suggère des blocs d'allocation, des vérifications NULL et des appels free() correspondants à partir d'un commentaire ; vérifiez chaque complétion pour les fuites et les tailles correctes avant de la livrer.

Résumez cet article avec :