L’allocation de mémoire à la volée est la façon dont les programmes C grandissent et rétrécissent pendant leur exécution. Vous ne connaissez pas les besoins exacts de votre application tant qu’elle n’est pas réellement exécutée. La solution est le tas. Vous demandez un blocage. Le système d’exploitation le réserve. Vous l’utilisez. Ensuite, vous le renvoyez avec « gratuit ». Ce cycle permet à d’autres programmes de recycler cette même RAM.
Considérez cet exemple simple. C’est l’interaction la plus basique que vous puissiez obtenir avec le tas.
Comment fonctionne réellement Malloc
La fonction malloc n’est pas magique. C’est un mécanicien qui vérifie l’inventaire. Lorsque vous l’appelez, trois choses se produisent en séquence.
- Il vérifie la capacité actuelle du tas. Il examine le paramètre que vous avez passé — dans ce cas
sizeof(int), qui fait 4 octets. Il demande s’il existe suffisamment d’espace contigu. Si le tas est fragmenté ou plein, il échoue. - Si de l’espace existe, il réserve ce bloc. Le système le marque comme « le vôtre ». Aucun autre appel
mallocne peut toucher ce morceau. Il évite les collisions accidentelles entre les allocations. - Il renvoie l’adresse de ce bloc. Il ne vous donne pas les données lui-même. Il vous donne une variable de pointeur. Cette variable contient l’emplacement. Vous disposez maintenant d’un identifiant vers un emplacement spécifique dans la RAM.
Dans notre exemple, p reçoit cette adresse. La variable pointeur n’est qu’un conteneur pour un emplacement mémoire. La valeur entière réelle réside à cet emplacement.
Pourquoi vous devez vérifier NULL
Vous voyez la vérification « if (p == 0) » immédiatement après l’allocation. Certains débutants sautent cela. C’est une erreur fatale.
Vérifiez toujours le pointeur après tout appel à malloc pour vous assurer que le pointeur est valide.
La taille du tas fluctue constamment. Cela dépend des autres processus en cours d’exécution. Cela dépend de la quantité de mémoire qu’ils ont récupérée. Il n’y a aucune garantie qu’un appel réussira. Si malloc échoue, il renvoie zéro. Zéro est « NULL ». Si vous essayez de déréférencer un pointeur nul, votre programme plante. Dur.
Vous pouvez écrire « if (p == NULL) » ou « if (!p) ». Ils veulent dire la même chose. Mais il faut vérifier. À chaque fois.
Que se passe-t-il si vous oubliez de libérer de la mémoire ?
Si votre programme se termine et que vous n’avez pas appelé « free », le système d’exploitation nettoie. Il libère l’espace exécutable. Cela efface la pile. Il récupère la mémoire globale. Il recycle également toutes les allocations de tas en attente.
Alors, est-il acceptable de perdre de la mémoire à la fin d’un programme ? Techniquement, oui. Le système d’exploitation gère le nettoyage. Il n’y a aucune conséquence à long terme pour la machine.
Mais c’est une mauvaise forme. Et plus important encore, les fuites de mémoire pendant l’exécution sont mortelles. Si vous continuez à allouer sans libérer, vous affamez votre propre processus. Le tas se remplit. Les nouvelles allocations échouent. Le programme meurt par étouffement, pas par crash.
Pointeurs par rapport aux valeurs vers lesquelles ils pointent
Les pointeurs peuvent prêter à confusion. Ils sont distincts des valeurs auxquelles ils font référence. Voici comment cela se déroule en pratique.
Premier scénario. Vous allouez un bloc. Vous pointez deux variables dessus.
Sortie :
10
20
Pourquoi? p et q sont des pointeurs différents. Mais q = p les fait pointer vers le même bloc de mémoire. Changer la valeur via p la change pour q. Le changer via q le change pour p. Ce sont deux poignées sur la même porte.
Deuxième scénario. Vous attribuez deux blocs distincts.
Sortie :
20
Ici, « p » et « q » pointent vers des emplacements différents. *q contient 20. *p = *q copie la valeur 20 à l’emplacement vers lequel p pointe. Le pointeur « p » lui-même ne bouge pas. La valeur à l’adresse de « p » change.
La distinction compte. On change l’adresse stockée dans la variable. L’autre modifie les données à cette adresse. La confusion des deux conduit à des erreurs logiques plus difficiles à déboguer que des erreurs de syntaxe.


Pointeurs, mémoire et chute libre
La sortie est 20. La ligne 6 dit tout.
Vous pourriez penser que « p = q » et « p = q » font la même chose. Ce n’est pas le cas. On déplace les données. Les autres mouvements s’adressent. Le compilateur vous permet d’attribuer *p = *q car les deux pointeurs déréférencés sont des entiers. C’est un échange direct de valeurs. Mais « p = q » ? C’est différent. Il pointe « p » vers exactement le même bloc de mémoire que « q ». L’adresse bouge. Les données restent en place.
Si les types ne correspondent pas, le compilateur le bloque. Un pointeur vers un entier ne peut pas pointer vers une chaîne de caractères. Les types doivent s’aligner.
Quatre façons d’initialiser
Une nouvelle variable de pointeur est un handicap jusqu’à ce qu’elle soit initialisée.
int *p; crée un pointeur qui ne pointe nulle part en particulier. Cela montre des ordures. Le déréférencer est une erreur. Vous avez besoin d’un emplacement connu. Il y a quatre façons d’y arriver.
- malloc : Ceci alloue un bloc sur le tas.
pcontient désormais une adresse valide. Le pointeur est initialisé car il pointe vers une partie de mémoire spécifique et réservée. - Affectation :
p = q;siqest valide,pdevient valide. Il hérite de l’adresse de « q ». Siqest un déchet,pobtient également un déchet. - Adresse explicite : Vous pouvez pointer
pdirectement vers une variable connue.p = &i;pointepvers l’entieri. Simple. Direct. - Zéro/NULL :
p = 0;oup = NULL;. Cela définit l’adresse à zéro. Cela n’indique pas un blocage. Il pointe vers l’emplacement nul.
Pourquoi utiliser zéro ? C’est un drapeau.
Vous pouvez vérifier « if (p == 0) » pour voir si le pointeur est valide. Le système le reconnaît. Si vous essayez de déréférencer un pointeur nul, le programme plante. Dur.
p = 0 ; *p = 5;
La deuxième ligne échoue. p ne pointe vers rien. Vous ne pouvez pas écrire sur rien. Ce comportement est critique pour les listes chaînées ultérieurement. C’est un filet de sécurité.
Libérer le tas
L’allocation de mémoire ne suffit pas. Vous devez le rendre.
malloc prend de l’espace. free le renvoie.
free(p) fait deux choses. Premièrement, il annule la réservation du bloc. Le tas récupère cette mémoire. Il peut être réutilisé. Deuxièmement, « p » n’est pas initialisé. Cela ne devient pas sûr comme par magie. Vous devez réinitialiser p avant de l’utiliser à nouveau.
Le bloc a disparu de votre champ d’application. Le pointeur pend.
Voici le modèle standard pour gérer un seul entier sur le tas :
Il s’agit principalement d’une démo. Mais cela montre le cycle de vie.
sizeof(int) renvoie la taille en octets. Sur la plupart des machines, cela fait 4. Vous pouvez coder en dur malloc(4). Ne le faites pas. sizeof rend le code portable. Ça se lit mieux. Il s’adapte si l’architecture change.
malloc renvoie un pointeur générique. Les compilateurs vous avertissent souvent si vous ne le lancez pas. (int *) convertit ce blob générique en un pointeur vers un entier. Cela correspond à « p ».
free(p) rend le bloc au tas.
Structures et priorité des opérateurs
Les structures se comportent de la même manière. Vous allouez un bloc pour l’ensemble de la structure, pas seulement pour les champs.
Regardez (*p).i = 10;.
Pourquoi ces parenthèses ?
Parce que . a une priorité plus élevée que *.
Sans parenthèses, *p.i signifie *(p.i). Il essaie d’accéder à « i » sur le pointeur « p », puis de le déréférencer. Ce n’est pas ce que tu veux. Vous souhaitez d’abord déréférencer p, puis accéder à i.
Les règles de préséance sont strictes. * se lie plus étroitement que . dans ce contexte. Les parenthèses forcent le déréférencement à se produire avant l’accès du membre.
La plupart des gens détestent taper (*p).i à plusieurs reprises. C’est verbeux.
C a un raccourci.
p->i
C’est exactement la même chose que (*p).i. Mais c’est plus rapide à taper. Vous verrez -> partout dans le code C. C’est le moyen standard d’accéder aux membres d’une structure via un pointeur.
Le tas est une ressource limitée. Répartissez soigneusement. Désallouer systématiquement. Ou regardez votre mémoire s’échapper.
























