La gestion de la mémoire est un concept fondamental en programmation, surtout en C et C++, où elle est principalement manuelle. Contrairement aux langages modernes comme Python ou Java, C et C++ ne disposent pas de ramasse-miettes (Garbage Collector). Il est donc crucial pour le développeur de bien gérer l’allocation, l’utilisation et la libération de la mémoire.
Dans cet article, nous allons explorer :
✅ Les types de mémoire (stack, heap, statique)
✅ L’allocation et la libération en C (malloc, free)
✅ La gestion de la mémoire en C++ (new, delete, smart pointers)
✅ Les erreurs courantes et bonnes pratiques
1. Les types de mémoire en C et C++
En C et C++, la mémoire est divisée en trois principales zones :
1️⃣ La mémoire statique (Data Segment)
📌 Utilisée pour les variables globales et statiques.
📌 Allouée au démarrage du programme et libérée automatiquement à la fin.
cCopierModifierint global_var = 42; // Variable globale, allouée dans la mémoire statique
void function() {
static int counter = 0; // Variable statique, persiste après la fin de la fonction
counter++;
}
2️⃣ La pile (Stack)
📌 Utilisée pour les variables locales et les appels de fonctions.
📌 Gérée automatiquement par le compilateur.
📌 Chaque fonction a sa propre zone de pile (stack frame).
📌 Taille limitée (peut provoquer un stack overflow).
cCopierModifiervoid function() {
int a = 10; // Variable locale, allouée sur la stack
}
⚠️ Problème du stack overflow
Si une fonction s’appelle récursivement sans condition d’arrêt, elle peut épuiser la mémoire disponible sur la stack.
cCopierModifiervoid recursive_function() {
int array[10000]; // Grosse allocation sur la stack
recursive_function(); // Appel récursif infini -> Stack Overflow
}
3️⃣ Le tas (Heap)
📌 Utilisé pour l’allocation dynamique de mémoire.
📌 Doit être géré manuellement (malloc / free en C, new / delete en C++).
📌 Plus lent que la stack, mais permet d’allouer des blocs de mémoire de taille variable.
cCopierModifierint* ptr = (int*)malloc(10 * sizeof(int)); // Alloue un tableau de 10 entiers
free(ptr); // Libère la mémoire
2. Allocation dynamique en C
🛠️ malloc (Memory Allocation)
Alloue un bloc de mémoire de taille donnée, mais ne l’initialise pas.
cCopierModifierint* ptr = (int*)malloc(5 * sizeof(int)); // Alloue un tableau de 5 entiers
if (ptr == NULL) {
printf("Allocation échouée\n");
}
🛠️ calloc (Cleared Allocation)
Comme malloc, mais initialise la mémoire à zéro.
cCopierModifierint* ptr = (int*)calloc(5, sizeof(int)); // Alloue et initialise à zéro
🛠️ realloc (Resize Memory Block)
Permet de redimensionner un bloc de mémoire existant.
cCopierModifierint* ptr = (int*)malloc(5 * sizeof(int));
ptr = (int*)realloc(ptr, 10 * sizeof(int)); // Étend le tableau à 10 entiers
🛠️ free (Libérer la mémoire)
Libère un bloc de mémoire précédemment alloué avec malloc, calloc ou realloc.
cCopierModifierfree(ptr); // Libération
ptr = NULL; // Évite les accès mémoire invalides
3. Allocation dynamique en C++ (new et delete)
C++ fournit des opérateurs new et delete pour gérer l’allocation dynamique plus facilement qu’en C.
🔹 new (Allocation d’un objet unique)
Crée un objet en mémoire dynamique et retourne un pointeur.
cppCopierModifierint* ptr = new int(42); // Alloue un entier avec la valeur 42
delete ptr; // Libération
🔹 new[] (Allocation d’un tableau)
Pour allouer un tableau dynamique, on utilise new[].
cppCopierModifierint* array = new int[5]; // Tableau de 5 entiers
delete[] array; // Libération
🔹 delete et delete[]
⚠️ Utiliser delete[] pour les tableaux, sinon comportement indéfini !
4. Les erreurs courantes en gestion de mémoire
❌ Fuites de mémoire (Memory Leak)
Oublier d’appeler free ou delete entraîne une consommation excessive de mémoire.
cppCopierModifiervoid memory_leak() {
int* ptr = new int(42);
// Oubli de `delete ptr;` => Mémoire jamais libérée
}
❌ Double libération (Double Free)
Libérer une mémoire déjà libérée peut causer un segmentation fault.
cCopierModifierint* ptr = (int*)malloc(sizeof(int));
free(ptr);
free(ptr); // ERREUR !
❌ Dangling Pointer (Pointeur Dangling)
Un pointeur qui pointe vers une mémoire libérée peut provoquer un comportement indéfini.
cCopierModifierint* ptr = (int*)malloc(sizeof(int));
free(ptr);
printf("%d", *ptr); // ERREUR : accès mémoire illégal
❌ Dépassement de mémoire (Buffer Overflow)
Lire ou écrire en dehors des limites d’un tableau alloué peut provoquer des plantages.
cCopierModifierint* array = (int*)malloc(5 * sizeof(int));
array[5] = 10; // ERREUR : accès hors limites !
5. Les Smart Pointers en C++ (Eviter les fuites de mémoire)
C++ moderne (C++11 et +) propose les smart pointers pour éviter les erreurs de gestion de mémoire.
✅ unique_ptr (Pointeur unique, pas de copie)
cppCopierModifier#include <memory>
std::unique_ptr<int> ptr = std::make_unique<int>(42); // Pas besoin de delete
✅ shared_ptr (Référence partagée)
cppCopierModifier#include <memory>
std::shared_ptr<int> p1 = std::make_shared<int>(10);
std::shared_ptr<int> p2 = p1; // p1 et p2 partagent la mémoire
✅ weak_ptr (Référence sans ownership)
Utilisé pour éviter les cycles de références.
6. Conclusion et bonnes pratiques
✔️ Utiliser malloc / free en C et new / delete en C++.
✔️ Toujours libérer la mémoire après utilisation (free ou delete).
✔️ Éviter les fuites de mémoire en suivant la règle « Chaque new doit avoir un delete« .
✔️ Utiliser les smart pointers (unique_ptr, shared_ptr) en C++.
✔️ Toujours initialiser les pointeurs à NULL après free.
La gestion de la mémoire est cruciale pour optimiser les performances et éviter des erreurs difficiles à déboguer. Avec de bonnes pratiques, on peut écrire un code fiable et efficace ! 🚀

















