ProgrammationDéveloppeur Backend C

Parlez en détail de l'allocation, de l'utilisation et de la libération correcte de la mémoire dynamique en C via malloc/free. Quels pièges existent lors de l'utilisation de la mémoire dynamique ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question :

Les mécanismes d'allocation dynamique de mémoire sont apparus en C avec les fonctions de la bibliothèque standard malloc/free dans <stdlib.h>. Ils ont permis de mettre en œuvre des structures de taille variable, des collections complexes et des objets, ce qui a donné une forte impulsion au développement du langage et à son utilisation dans la grande programmation.

Problème :

Le travail avec la mémoire dynamique nécessite du programmeur un contrôle total sur le cycle de vie des objets. Les erreurs (fuites de mémoire, double libération, utilisation incorrecte des pointeurs) peuvent entraîner des pannes ou des vulnérabilités (par exemple, des exploits via des erreurs use-after-free).

Solution :

— Toujours vérifier les valeurs de retour de malloc/calloc/realloc. Si l'allocation a échoué, elles renvoient NULL. — Lors de la libération de la mémoire, diriger le pointeur vers NULL pour éviter l'utilisation d'un bloc libéré. — Ne pas utiliser un pointeur après free. — Maintenir une correspondance correcte entre malloc/free et calloc/free.

Exemple de code :

#include <stdio.h> #include <stdlib.h> int main() { int *arr = malloc(5 * sizeof(int)); if (!arr) { perror("Échec de l'allocation mémoire"); return 1; } for (int i = 0; i < 5; ++i) arr[i] = i * i; for (int i = 0; i < 5; ++i) printf("%d ", arr[i]); printf(" "); free(arr); arr = NULL; return 0; }

Caractéristiques clés :

  • malloc/calloc/realloc renvoient void*, nécessitant une conversion de type explicite (pas pour C, pour C++).
  • Après free, le pointeur devient incorrect.
  • La taille de la mémoire allouée dépend toujours du type et du nombre d'éléments (n * sizeof(type)).

Questions pièges.

Que se passe-t-il lors de la libération de la mémoire allouée via malloc avec l'opérateur delete ou vice versa (en C++) ?

Il est interdit de mélanger les mécanismes d'allocation et de libération de mémoire entre les langages (C/C++). En C, c'est uniquement malloc/free, en C++ new/delete.

Que se passe-t-il lorsque vous essayez d'appeler free(NULL) ?

free(NULL) est sûr (cela est garanti par la norme C). Un tel appel ne fait rien.

Peut-on utiliser realloc pour augmenter ou diminuer un bloc de mémoire et que se passe-t-il avec le pointeur d'origine ?

realloc peut déplacer le bloc de mémoire, et si cela s'est produit, l'ancien pointeur devient invalide. Assignez toujours le nouveau pointeur :

ptr = realloc(ptr, new_size);

Erreurs courantes et anti-patterns

  • Utilisation de la mémoire après free (use-after-free).
  • Double appel de free pour le même pointeur.
  • Fuites de mémoire (allouées mais non libérées).
  • Erreurs dans les calculs de la taille de la mémoire lors de malloc (oublié sizeof(...)).
  • Ignorer le retour NULL lors d'un malloc échoué.

Exemple de la vie réelle

Cas négatif

Allocation mémoire pour un tableau dans une boucle, mais oubli de libérer à la fin de l'itération. Pendant la nuit sur le serveur, le programme a "avalé" toute la RAM.

Avantages :

  • Code plus simple, moins de vérifications.

Inconvénients :

  • Fuite de mémoire, performance réduite, chute de l'application.

Cas positif

Dans la boucle, la mémoire était toujours libérée après utilisation, toutes les vérifications NULL étaient faites juste après malloc, des outils de débogage étaient utilisés pour contrôler les fuites.

Avantages :

  • Fonctionnement stable, aucune fuite.
  • Code facile à maintenir et à étendre.

Inconvénients :

  • Code légèrement plus encombrant, nécessité d'attention à chaque étape du cycle de vie de la mémoire.