<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Cours #4 - Récursivité et stack]]></title><description><![CDATA[<p dir="auto">&lt;p&gt;Bonjour à tous,&lt;br/&gt;<br />
Nous passons encore à un autre niveau aujourd'hui, et nous allons voir ensemble la Récursivité, et la notion de Stack.&lt;/p&gt;<br />
&lt;p&gt;&lt;strong&gt;I- La récursivité, c'est quoi?&lt;/strong&gt;&lt;br/&gt;<br />
La récursivité, c'est un autre moyen de provoquer une "boucle" dans une fonction.&lt;br/&gt;<br />
C'est totalement différent de ce que je vous ai expliqué avant. Nous avions vu la partie "itérative" du C, qui corresponds à exécuter un programme, ligne par ligne. Ici, nous allons apprendre un peux plus les fonctions de la récursivité, et comment elle réagit sur la stack.&lt;br/&gt;<br />
C'est une façon de faire, pour qu'une fonction se rappelle elle-même.&lt;/p&gt;<br />
&lt;p&gt;Prenons l'exemple suivant:&lt;/p&gt;<br />
&lt;pre class="ipsCode prettyprint"&gt;<br />
int test(int a) {<br />
a++;<br />
if (a &lt; 12)<br />
test(a);<br />
return (a);<br />
}<br />
int main(void) {<br />
my_putnbr(test(1));// my_putnbr est une fonction permettant d'afficher une valeur numérique. Vous devez la re-créer ou utiliser printf (ce qui est interdit par la norme! Re-créez la, ça vous apprendra pas mal de choses!)<br />
}&lt;/pre&gt;<br />
&lt;p&gt;La fonction "test" est ici récursive.&lt;br/&gt;<br />
Ce code nous affichera: 12&lt;br/&gt;<br />
Vous l'aurez compris, la récursivité peut être utile dans plusieurs cas (pour annecdote, my_putnbr peut être codé en 3 lignes avec de la récursivité).&lt;br/&gt;<br />
Les fonctions récursives peuvent êtres comparées à des poupées russes s'emboitant.&lt;br/&gt;<br />
Ne vous perdez pas! Et ne vous inquiétez pas! Je vais mieux vous l'expliquer en vous expliquant le fonctionnement de la stack.&lt;/p&gt;<br />
&lt;p&gt;&lt;strong&gt;II- La stack? DAFUQ?&lt;/strong&gt;&lt;br/&gt;<br />
Je vais pouvoir vous expliquer une notion qui est assez floue dans le cerveau de beaucoup de développeurs: la stack.&lt;br/&gt;<br />
La stack est une mémoire assignée à votre programme pour la prise en charge de tout ce qui est "static" dans votre programme (d'où le nom "stack").&lt;br/&gt;<br />
Lors du lancement de votre programme, la stack est vide. Si vous appelez la fonction "test" celle-ci va se rajouter dans la stack. Si, de la fonction "test", vous appelez la fonction "my_putstr" celle-ci va se rajouter dans la stack, de même pour la fonction "my_putchar" contenue dans la fonction "my_putstr" qui fera elle-même appel à la fonction "write" qui se rajoutera à son tour à la stack.&lt;br/&gt;<br />
La stack a donc constitué une liste d'exécution. On peut re-définir l'ordre d'exécution précédent&lt;br/&gt;<br />
comme ceci:&lt;br/&gt;<br />
 &lt;/p&gt;<br />
&lt;blockquote class="ipsQuote" data-ipsquote=""&gt;&lt;div&gt;write - my_putchar - my_putstr - test.<br />
&lt;p&gt; &lt;/p&gt;<br />
&lt;/div&gt;&lt;/blockquote&gt;<br />
&lt;p&gt;Il ne faut pas oublier que la stack est une mémoire, et qu'elle va stocker tout ce qui est statique dans notre programme. Donc, si nous la sur-utilisons (une boucle infinie de fonctions par exemple: surempiler les poupées russes), nous risquons de faire segfault (segmentation fault) notre programme (C'est souvent une explication pour les programme qui segfault sans raisons).&lt;br/&gt;<br />
Lorsqu'une fonction finit son exécution, elle est supprimée de la stack.&lt;br/&gt;<br />
Pour vous faire un schéma, imaginez un tas de vaisselle: à chaque fois, vous rajoutez une assiette sale sur le tat, et lorsque vous faites la vaiselle, vous enlevez vos assiettes dans l'ordre contraire de celui de l'empilation.&lt;/p&gt;<br />
&lt;p&gt;Reprenons la théorie: Une fonction récursive est une fonction qui se rappelle elle-même. Elle se rajoute donc sur la stack, puis se rappelle. Elle se rajoute donc encore une fois sur la stack, puis se rappelle...etc...&lt;br/&gt;<br />
Et là, deux choses peuvent avoir lieu: Soit on atteint la taille maximum de la stack (définie par le système), et on provoque un segfault, sinon, et c'est ce que vous devrez faire la plupart du temps en utilisant les récursifs, vous devez prévoir une condition d'arrêt du rappel de cette fonction, donc à un moment de votre récursivité, vous dites STOP, cette fois je ne me rappelle pas, car mon rôle est terminé. A ce moment là, vous allez libérer la stack de toutes les fonctions que vous avez au préalable ajouté.&lt;/p&gt;<br />
&lt;p&gt;Le mieux, reste encore de vous montrer un exemple de ce qu'il ne faut pas faire:&lt;br/&gt;<br />
Créons un programme qui va afficher "hello" indéfiniment:&lt;/p&gt;<br />
&lt;pre class="ipsCode prettyprint"&gt;<br />
void my_putchar(char c) {<br />
write(1, &amp;c, 1);<br />
}<br />
void fg() {<br />
my_putchar('h');<br />
my_putchar('e');<br />
my_putchar('l');<br />
my_putchar('l');<br />
my_putchar('o');<br />
my_putchar('\n');<br />
fg();<br />
}<br />
int main(void) {<br />
fg();<br />
}&lt;/pre&gt;<br />
&lt;p&gt;Effectivement, on voit "hello" s'afficher plusieurs fois, mais si on laisse tourner notre programme jusqu'à ce que la stack soit remplie, on remarque de notre programme crash, et qu'un segfault est apparu.&lt;br/&gt;<br />
C'est l'exemple typique de ce que l'on peut attendre au niveau des problèmes liés à la récursivité.&lt;br/&gt;<br />
Un autre exemple, c'est notre légendaire my_putnbr:&lt;/p&gt;<br />
&lt;pre class="ipsCode prettyprint"&gt;<br />
void my_put_nbr(int nb) {<br />
if (nb &lt;= 9 &amp;&amp; nb &gt;= 0)<br />
my_putchar(nb + '0');<br />
else<br />
{<br />
my_put_nbr(nb / 10);<br />
my_put_nbr(nb % 10);<br />
}<br />
}&lt;/pre&gt;<br />
&lt;p&gt;c'est typiquement la bonne utilisation de la récursivité.&lt;br/&gt;<br />
Voilà, j'espère vous avoir encore aidé au niveau de votre apprentissage avancé du C.&lt;br/&gt;<br />
Rendez-vous au prochain cours!&lt;br/&gt;<br />
Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr&lt;/p&gt;</p>
]]></description><link>https://melinyel.net/topic/483/cours-4-récursivité-et-stack</link><generator>RSS for Node</generator><lastBuildDate>Wed, 02 Sep 2026 04:58:19 GMT</lastBuildDate><atom:link href="https://melinyel.net/topic/483.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 09 Apr 2014 17:51:52 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Cours #4 - Récursivité et stack on Fri, 25 Apr 2014 18:05:17 GMT]]></title><description><![CDATA[<p dir="auto">&lt;p&gt;ok merci =)&lt;/p&gt;</p>
]]></description><link>https://melinyel.net/post/6420</link><guid isPermaLink="true">https://melinyel.net/post/6420</guid><dc:creator><![CDATA[cegdd]]></dc:creator><pubDate>Fri, 25 Apr 2014 18:05:17 GMT</pubDate></item><item><title><![CDATA[Reply to Cours #4 - Récursivité et stack on Thu, 24 Apr 2014 00:06:21 GMT]]></title><description><![CDATA[<p dir="auto">&lt;p&gt;Un exemple de code ASM avec un generic push:&lt;/p&gt;<br />
&lt;pre class="ipsCode prettyprint"&gt;<br />
;; exemple avec la fonction "hello world" x86 asm<br />
global main<br />
extern printf</p>
<p dir="auto">section .text<br />
main:<br />
push rbp ;; Ici, le generic push<br />
mov rbp, rsp ;; Suite du generic push (on le retrouvera dans toutes les fonctions en C (sans exceptions, il est ajouté automatiquement par le compilateur)</p>
<p dir="auto">mov rdi, FormatStr ;; 1er param de printf<br />
call printf ;; call de printf</p>
<p dir="auto">mov rsp, rbp ;; on remet l'ancienne stack en place<br />
pop rbp ;; on vire la sauvegarde de l'ancienne stack</p>
<p dir="auto">mov rax, 60 ;; on prépare l'appel au systcall "exit"<br />
xor rdi, rdi ;; on passe le paramètre 0 dans rdi (xor x, x revient à mettre 0 dans x (car un xor de 2 même valeurs donne 0)<br />
syscall ;; appel du systcall n°60<br />
ret</p>
<p dir="auto">;; section read only<br />
section .rodata<br />
FormatStr db 'Hello World !',0Ah,0<br />
&lt;/pre&gt;</p>
]]></description><link>https://melinyel.net/post/6312</link><guid isPermaLink="true">https://melinyel.net/post/6312</guid><dc:creator><![CDATA[AlexMog]]></dc:creator><pubDate>Thu, 24 Apr 2014 00:06:21 GMT</pubDate></item><item><title><![CDATA[Reply to Cours #4 - Récursivité et stack on Wed, 23 Apr 2014 23:57:46 GMT]]></title><description><![CDATA[<p dir="auto">&lt;blockquote class="ipsQuote" data-cite="cegdd" data-ipsquote="" data-ipsquote-contentclass="forums_Topic" data-ipsquote-contentcommentid="6285" data-ipsquote-contentid="483" data-ipsquote-contenttype="forums" data-ipsquote-timestamp="1398274860" data-ipsquote-username="cegdd"&gt;&lt;div&gt;<br />
&lt;div&gt;<br />
&lt;p&gt;J'ai compris a quoi ça sert de stocker ce qui est static dans une mémoire, mais pourquoi stocker les fonctions pour les supprimer par la suite ?&lt;/p&gt;<br />
&lt;p&gt;En quoi est-ce utile pour le programme ?&lt;/p&gt;<br />
&lt;/div&gt;<br />
&lt;/div&gt;&lt;/blockquote&gt;<br />
&lt;p&gt;En réalité, tout ce passe au niveau du code ASM.&lt;/p&gt;<br />
&lt;p&gt;Pour éviter de modifier la stack précédente, et être sûr que ladite stack ne soit pas modifiée, toutes les fonctions font une sauvegarde temporaire de la stack (c'est ce qu'on appelle le "generic push" en ASM).&lt;/p&gt;<br />
&lt;p&gt;La stack est donc remplie temporairement avec les anciennes valeurs.&lt;/p&gt;<br />
&lt;p&gt;Qui plus est, lorsque tu utilise une fonction qui contient elle même une variable, ou qui passe une variable en paramètre, celle-ci est stockée en stack (c'est pour cela qu'on préfèrera envoyer un pointeur plutôt qu'une structure en dur dans une fonctions <img src="https://melinyel.net/assets/plugins/nodebb-plugin-emoji/emoji/android/1f609.png?v=d0a000c383a" class="not-responsive emoji emoji-android emoji--wink" style="height:23px;width:auto;vertical-align:middle" title=";)" alt="😉" /> ) (pour info: un pointeur = 8 octets (une structure contenant 2 int = 8 * 2 octets. Le choix est vite fait.)&lt;/p&gt;</p>
]]></description><link>https://melinyel.net/post/6311</link><guid isPermaLink="true">https://melinyel.net/post/6311</guid><dc:creator><![CDATA[AlexMog]]></dc:creator><pubDate>Wed, 23 Apr 2014 23:57:46 GMT</pubDate></item><item><title><![CDATA[Reply to Cours #4 - Récursivité et stack on Wed, 23 Apr 2014 17:41:00 GMT]]></title><description><![CDATA[<p dir="auto">&lt;blockquote class="ipsQuote" data-cite="AlexMog" data-ipsquote="" data-ipsquote-contentclass="forums_Topic" data-ipsquote-contentcommentid="5224" data-ipsquote-contentid="483" data-ipsquote-contenttype="forums" data-ipsquote-timestamp="1397065912" data-ipsquote-username="AlexMog"&gt;&lt;div&gt;<br />
&lt;div&gt;La stack est une mémoire assignée à votre programme pour la prise en charge de tout ce qui est "static" dans votre programme (d'où le nom "stack").&lt;p&gt;&lt;/p&gt;&lt;p&gt;Lors du lancement de votre programme, la stack est vide. Si vous appelez la fonction "test" celle-ci va se rajouter dans la stack.&lt;/p&gt;<br />
&lt;/div&gt;<br />
&lt;/div&gt;&lt;/blockquote&gt;<br />
&lt;p&gt; &lt;/p&gt;<br />
&lt;p&gt;J'ai compris a quoi ça sert de stocker ce qui est static dans une mémoire, mais pourquoi stocker les fonctions pour les supprimer par la suite ?&lt;/p&gt;<br />
&lt;p&gt;En quoi est-ce utile pour le programme ?&lt;/p&gt;</p>
]]></description><link>https://melinyel.net/post/6285</link><guid isPermaLink="true">https://melinyel.net/post/6285</guid><dc:creator><![CDATA[cegdd]]></dc:creator><pubDate>Wed, 23 Apr 2014 17:41:00 GMT</pubDate></item><item><title><![CDATA[Reply to Cours #4 - Récursivité et stack on Thu, 17 Apr 2014 08:28:10 GMT]]></title><description><![CDATA[<p dir="auto">&lt;p&gt;Très bon tutoriel, c'est sympa que tu expliques pas à pas les différents points du C. <img src="https://melinyel.net/assets/plugins/nodebb-plugin-emoji/emoji/android/1f642.png?v=d0a000c383a" class="not-responsive emoji emoji-android emoji--slightly_smiling_face" style="height:23px;width:auto;vertical-align:middle" title=":)" alt="🙂" /> &lt;br/&gt;<br />
Peut-être un peu plus d'espace, sinon toujours pareil : Bien joué. <img src="https://melinyel.net/assets/plugins/nodebb-plugin-emoji/emoji/android/1f609.png?v=d0a000c383a" class="not-responsive emoji emoji-android emoji--wink" style="height:23px;width:auto;vertical-align:middle" title=";)" alt="😉" /> &lt;br/&gt;&lt;br/&gt;<br />
+1 point de rep.&lt;/p&gt;</p>
]]></description><link>https://melinyel.net/post/5671</link><guid isPermaLink="true">https://melinyel.net/post/5671</guid><dc:creator><![CDATA[Azad]]></dc:creator><pubDate>Thu, 17 Apr 2014 08:28:10 GMT</pubDate></item></channel></rss>