Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

La pile et le tas en C

Après cette leçon: Je peux dire où vit une variable et ce que font malloc et free.

Leçon de 60 min7 commandesLab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

Une variable locale disparaît, le tas reste

La pile et le tas sont les deux zones de mémoire où un programme C range ses variables. Savoir dans quelle zone vit une variable dit combien de temps elle existe et qui doit la libérer.

Un serveur de réservations tourne des semaines sans redémarrer. À chaque requête, il oublie de rendre dix octets. Au bout de quelques jours, la mémoire est pleine et le serveur s’arrête.

À la fin de cette leçon

Remarque

Je peux dire où vit une variable et ce que font malloc et free.

Mots-clés

MotCe que ça veut direExemple
Pilela zone qui garde les variables locales des appels en cours
Cadrel’espace que la pile réserve pour un appel de fonction
Tasla zone où on réserve des blocs à la demande
mallocla fonction qui réserve un bloc sur le tasmalloc(12)
freela fonction qui rend un bloc au tasfree(p)
Fuite de mémoireun bloc qu’on ne rend jamais alors qu’on ne s’en sert plus

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

La pile garde les variables locales d’un appel

Chaque appel de fonction reçoit un cadre sur la pile. Il contient les paramètres et les variables locales. Quand la fonction retourne, le cadre est retiré et ses variables n’existent plus.

Le prochain appel réutilise la même place avec de nouvelles variables. Une variable déclarée static fait exception : elle garde sa valeur d’un appel à l’autre.

Une variable locale et une variable static

Code: c
int suivant(void) {
    static int compte = 0;
    int local = 0;
    compte++;
    local++;
    return compte * 10 + local;
}

Aller dans le dossier de travail

Commande
mkdir -p ~/c && cd ~/c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Écrire le programme dans un fichier

Commande
printf '#include <stdio.h>\nint suivant(void) {\n    static int compte = 0;\n    int local = 0;\n    compte++;\n    local++;\n    return compte * 10 + local;\n}\nint main(void) {\n    int a = suivant();\n    int b = suivant();\n    int c = suivant();\n    printf("%%d %%d %%d\\n", a, b, c);\n    return 0;\n}\n' > pile.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Compiler et lancer le programme

Commande
gcc -Wall -o pile pile.c && ./pile

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Exemple travaillé : trois appels de suivant

Appelcompte (static)local au départRésultat
1er10 puis 111
2e20 puis 121
3e30 puis 131

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

malloc réserve un bloc, free le rend

Quand on ne connaît pas la taille à l’avance, ou qu’une donnée doit survivre à la fonction, on demande un bloc au tas avec malloc. La fonction rend l’adresse du bloc, ou NULL s’il n’y a plus de place.

Le bloc reste réservé jusqu’à l’appel de free. calloc fait comme malloc et met aussi tous les octets à zéro. Un bloc de malloc contient n’importe quoi au départ.

Réserver, remplir et rendre des blocs

Code: c
int *p = malloc(3 * sizeof(int));
p[0] = 1; p[1] = 2; p[2] = 3;
free(p);
int *z = calloc(4, sizeof(int));

Écrire le programme du tas

Commande
printf '#include <stdio.h>\n#include <stdlib.h>\nint main(void) {\n    int *p = malloc(3 * sizeof(int));\n    p[0] = 1;\n    p[1] = 2;\n    p[2] = 3;\n    printf("%%d\\n", p[0] + p[1] + p[2]);\n    free(p);\n    int *z = calloc(4, sizeof(int));\n    printf("%%d %%d\\n", z[0], z[3]);\n    free(z);\n    return 0;\n}\n' > tas.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Compiler et lancer le programme du tas

Commande
gcc -Wall -o tas tas.c && ./tas

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Trois erreurs classiques avec le tas

Une fuite : on oublie free, et la mémoire n’est jamais rendue. Un usage après free : on écrit dans un bloc déjà rendu, qui peut appartenir à autre chose. Un double free : on rend deux fois le même bloc, ce qui abîme les notes du tas.

Aucune de ces erreurs ne stoppe forcément le programme sur-le-champ. On ne les lance pas dans le labo : on les lit dans le tableau.

Les trois erreurs, sans les lancer

Code: c
char *a = malloc(10);   /* jamais free : une fuite */
char *b = malloc(10);
free(b);
b[0] = 'x';             /* usage après free */
free(b);                /* double free */

Exemple travaillé : ce que chaque erreur coûte

ErreurCe qui se passeQuand on le voit
FuiteLa mémoire utilisée grossitAprès des heures ou des jours
Usage après freeOn écrit chez un autre blocPlus tard, ailleurs dans le programme
Double freeLe tas est corrompuSouvent un arrêt immédiat, parfois bien après

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Écrire une fonction qui rend l’adresse d’un local

Commande
printf '#include <stdio.h>\nint *mauvais(void) {\n    int local = 5;\n    return &local;\n}\nint main(void) {\n    printf("%%d\\n", *mauvais());\n    return 0;\n}\n' > local.c

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Compter les avertissements de gcc

Commande
gcc -Wall -c local.c 2>&1 | grep -c "warning"

Affichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.

Erreur fréquente

Attention

Beaucoup de gens pensent qu’on peut renvoyer l’adresse d’une variable locale. Son cadre disparaît au retour : l’adresse désigne alors une place que le prochain appel va écraser. Renvoyez une valeur, ou un bloc de malloc que l’appelant rendra.

À propos de ce labo et de sa source: Lab de compilation et d’architecture : gcc, flex, bison et RISC-V dans une VM

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.