# ***Heap VS Stack*** Maintenant est le bon moment pour vous expliquer la différence entre heap et stack. La RAM que va utiliser votre programme, la mémoire que vous allez manipuler, est divisée en 3 parties distinctes qui fonctionnent séparement mais intéragissent entre elles. Dans ce cours, je vais essayer de vous expliquer au mieux comment les langages informatiques qui vous laissent avoir le contrôle de votre mémoire fonctionnent dans les bas fonds. <br> ![](https://hackmd.io/_uploads/rkbKiDkC3.jpg) <br> <br> ***Commençons par les présenter :*** --- - ***la stack*** > "Vous voyez ce jeu ? Pareil mdr" ![](https://hackmd.io/_uploads/B10k2DyCh.png) C'est la première partie de la mémoire où les variables que vous allez utiliser seront stockées directement (*"stocker la variable en dur"*), seront plus facilement atteignables car elles se ***stackent*** les unes sur les autres, et une fois la fonction terminée ces variables se libèrent. > *Imaginez que vous avez une pile de pièces (c'est votre stack (qui littéralement veut dire "pile" en anglais )) et à chaque fois que vous voudrez créer et déclarer une variable dans la stack, cette dernière sera juste une pièce qui se rajoutera sur le tas. Y accéder est donc bien plus rapide qu'un pointeur car vous n'aurez juste qu'à enlever les 2 ou 3 pièces (si il y en a bien sûr) qui sont en dessus de la votre.* > ***Mais comment faire ça ?*** > *Et bien votre ordinateur le fait tout seul, donc aucune contrainte* !!! A savoir qu'il y a plusieurs instances et rôles dans life time pour les variables déclarées en dur. D'où l'importance des variables ***globales*** (qui ne vous sont malheureusement pas autorisées dans nombres de projets) mais ces dernières sont des pièces de la stack qui resteront jusqu'à la fin de votre programme contrairement à un variable locale qui se freera toute seule à la fin de la fonction. <br> Exemple : ```c int main(int ac, char **av) { int a; int b[10]; int n = 20; int c[n]; char string[6] = "Hello\n"; char array[40] = {0}; } ``` Toutes ces variables sont déclarées dans la stack, et seront donc déstackées faisant en sorte qu'il n'y a aucun leak. <br> --- - ***La static*** Bah elle est juste là quoi. Genre tu déclares la variable, et elle pop pendant le programme. Et... euh... c'est tout mdr... <br> --- - ***la heap*** > "*Vous voyez cette image ? Pareil.. (mais en fait pas vraiment).*" ![](https://hackmd.io/_uploads/H1nunDk0n.png) C'est la dernière partie de la mémoire (ou mémoire vive), c'est là où toutes les allocations dynamiques (malloc, realloc, calloc, alloca, ...) seront faites. De ce fait, vouloir coder un programme propre veut dire free toutes les variables et un exit() prématuré ou un return 84 peuvent faire exploser toute une base de données si vous ne faites pas attention plus tard. <br> > *Maintenant, voyons voir une allégorie pour comprendre en opposé à la stack, comment fonctionne la heap. Imaginez un énorme calendrier qui s'étendue sur plusieurs millions d'années et plusieurs milliards de jour. Chaque jour est une case qui a sa date (son adresse) -> 21/12/2587 = (0x78D75Z) et à chaque date vous pouvez y mettre de l'information (votre variable) -> rdv avec Jacqueline = (int x = 11 ou _00001011_).* > *Imaginez maintenant que vous allez partir en vacances pendant 3 semaines, vous allez réserver 3 lignes du calendrier en plus de 7 jours par semaine :* <br> ```c char **array = malloc(sizeof(char *) * 3); for (int i = 0; i < 3; i++) array[i] = malloc(sizeof(char) * 7); i[array] = malloc(7); // fonctionne tout aussi bien // hehehe faites genre vous avez rien vu ``` <br> > *Et bien votre heap c'est comme ce calendrier, elle contient des milliards de "cases" mémoires. Certaines libres, certaines nons. Alors bien sûr la taille est gigantesque, il arrivera rarement que vous atteignez le bout mais manager correctement votre calendrier le rendra plus facile à lire !!!* Le problème qui rend le tout plus lent lors de l'exécution de votre programme , c'est les ***pointeurs***. > *Imaginez les pointeurs comme des postites qui ne contiennent qu'une seule chose, la date à laquelle un évènement se produit. Si vous recherchez la date à laquelle vous reverrez Jacqueline (x = 11), regardez sur votre postite s'appelant "&x" et il devrait y avoir écrit 21/12/2587* ou : ```c int x = 11; int *pointeur_vers_x = &x; printf("adresse : %p", pointeur_vers_x); // devrait écrire un truc du genre // adresse : 0x78D75Z ``` <br> > ***"Mais alors pourquoi favoriser la stack dans certains cas"*** *Et bien comme vous pouvez le comprendre, si vous déclarer une variable dans la heap et que derrière vous ne la freeiez pas lors de la sortie du programme, cette dernière reste coincée dans la heap ://* Exemple : ```c int main(int ac, char **av) { char *str = my_strdup(av[1]); if (str[0] != 'A') return 84; do_something(str); free(str); return 0; } ``` Ici, vous allez avoir un leak si jamais vous rentrez dans le if alors faites attention. <br> Autre point à noter, si vous cherchez de la ***performance***, accéder à *la stack* dans une boucle qui demande une grosse variable comme un tableau est, genre... 1000 fois plus rapide que d'accéder à chaque itération via *un pointeur vers ce tableau* (donc accéder à la heap). --- Pour résumer, en utilisant la stack vous aurez : - moins de libertés sur le changement de vos variables mais vous aurez aussi : - un code plus sûr - un programme plus rapide --- Vous comprenez mieux maintenant comment fonctionne la mémoire. Gardez en tête que vous n'en êtes pas le maître mais un occupant qui peut faire ce qu'il veut avec. Sachez que tous les programmes ***qui tournent*** sur un ordinateur utilisent la RAM, que ce soit la stack, static ou heap. Toutes les "cases" de votre RAM qui sont écrits en fait en binaire changent constamment entre _0_ et _1111.1111.1111.1111_ (_INT32_MAX_ *ou encore* 2 147 483 647). Car oui votre mémoire vive fonctionne en permanence , entre le moment où vous allumerez votre PC, jusqu'à l'instance procédurale qui supprimera par n'importe quel moyen les données non nécessaires au fonctionnement de votre OS quand vous cliquerez sur [Arrêter] ou [Redémarrer]. > *PS : A vous de décider ce dont vous avez besoin. Perso je ne suis pas forcément en recherche de sûreté ni de vitesse mais plus de liberté qui me permette d'avoir un code plus maléable et franchement bien plus drôle, c'est pour ça que je préfère allouer dynamiquement dans la heap :))) **Il y a des pros et des cons pour les 2 alors vous êtes totalement libres de choisir votre manière de coder préférée.*** <br> ***Reminder visuel pour garder le tout à l'esprit :*** ```c int x; // static int main(void) { int y = 4; // déclaré en dur dans la stack char *str; // pointeur déclaré dans la stack str = malloc(100 * sizeof(char)); // pointant sur une // zone de la heap return 0; } ``` ces variables fonctionnent ainsi dans la ***mémoire*** : ![](https://hackmd.io/_uploads/SkVT0UJCn.png)