Débordement de pile irréparable ? - C - Programmation
Marsh Posté le 28-07-2014 à 20:03:45
C-user a écrit : Évidemment, comme à chaque récursion on met un tableau de 200 entiers en mémoire, et bien la pile déborde |
Haha, mauvaise supposition. Les tableaux sont toujours transmis par adresse aux fonctions (aucune copie n'est faite). C'est pour les "struct" qu'il y a une copie. Après j'ai un peu de mal à comprendre ce que fait ton algo, mais à mon avis si ton programme se plante, c'est probablement du à un buffer overflow.
Marsh Posté le 28-07-2014 à 23:49:56
Il y a pleins de pbs dans ce code...
Il semble y avoir:
- pleins de variables non initialisées ( X,Y,i,j,r)
- des mélanges passage par valeur / pointeur s ( la fonction deplace ne deplace rien pour moi car X et Y ne sont jamais modifiées)
- l'init du tableau qui n'initialise que la case [0,0]
Les bases du langage lui même semblent être à revoir car la le code ne fait pas ce que tu veux ( pire il fait aléatoirement n'importe quoi)
Marsh Posté le 29-07-2014 à 09:35:30
essaye de faire des pointeurs sur tableau plutôt qu'un tableau directement. la pile, tu ne pourras pas l'agrandir. c'est surement la multiplication d'appels récursifs qui la fait exploser. faut voir de ce coté là si y'a pas un soucis
Marsh Posté le 29-07-2014 à 09:38:13
je crois que j'ai compris. ta fonction estvalide recherche toutes les possibilités. mais tu ne l'empêches pas de rechercher là où tu as déjà cherché. donc il n'y a aucune limite. il faut faire en sorte de n'aller que dans un sens de recherche lorsque tu appelles cette fonction
Marsh Posté le 29-07-2014 à 11:42:11
Pour info, tout algo récursif peut être transformé en algo itératif. L'algo itératif est généralement plus rapide (car pas d'appels successifs à la fonction et empilement du contexte) et on maîtrise mieux les critères d'arrêt, évitant le buffer overflow.
Marsh Posté le 29-07-2014 à 12:23:20
Merci beaucoup à tous pour votre oeil neuf. Alors dans l'ordre :
@tpierron : ah oui c'est vrai, bien vu ^^
@dreameddeath : bases acquises voyons, je sais initialiser des variables ne t'inquiète pas (de toute façon le compilo me prévient ).
Pour les pointeurs vs adresse, effectivement mes cours remontent un peu, mais de ce que j'ai revu ça devrait aller non ? On a une variable X passée en paramètre, on en stocke l'adresse dans un pointeur [int* pX = &X], et plus tard pour modifier X on fait [*pX = X+1] par exemple pour ajouter 1 à la variable d'entrée (au passage : si j'ai bon on a bien modifié X). > Y a-t-il encore une erreur ?
Init du tableau : en mettant un seul 0 ça remplit tout le tableau de zéros, bien pratique
@ddr555 : Un tableau n'est-il pas déjà un genre de pointeur (pointant sur la 1ère case puis avance dans les cases mémoires) ? Enfin bref je ne connais sûrement pas assez les nuances dans la théorie. Ça a l'air pas mal comme idée mais je vois pas trop ... tu voudrais détailler pour moi ? Sinon pour "estValide" le but est bien de tout tester, en imposant des conditions pour n'afficher que LE bon chemin.
@rufo : Jackpot, j'ai lu un article là-dessus, et même si le temps d'exécution est pas mon problème, c'est surtout le fait de ne pas stocker à chaque étape qui m'intéresse ! Par contre même en sachant que c'est théoriquement possible, je n'ai aucune idée sur comment faire la transformation... Pour du backtracking aussi c'est possible ??
Encore merci à tous pour vos conseils, et n'hésitez pas à continuer
Marsh Posté le 29-07-2014 à 12:39:14
C-user a écrit : Merci beaucoup à tous pour votre oeil neuf. Alors dans l'ordre : |
Pas du tout:
Quand tu fais
int deplace (int tab[10][20], int X, int Y, int direction)
ton paramètre X est passé par copie. Donc X contient une copie de la valeur de la variable passée, et son adresse n'est pas celle de la valeur.
int* pX; pX = &X;
ne fait alors que prendre l'adresse de la copie et non pas de l'original, qui ne sera donc pas modifiée.
Ce que tu voulais probablement faire, c'était:
int deplace (int tab[10][20], int *X, int *Y, int direction)
avec un appel
deplace(tab, &X, &Y, direction);
A+,
Marsh Posté le 29-07-2014 à 12:42:37
Bon sang, mais c'est bien sûr !
Je modifie dans le premier message, on n'a qu'à dire que ma mémoire m'a fait défaut
Merci beaucoup en tout cas
Ce qui nous donne :
Code :
|
Et l'appel :
Code :
|
Marsh Posté le 03-08-2014 à 18:53:25
Alors tout le monde, avez-vous encore des idées ?
Je ne vois pas du tout comment se passer dans cet algo de la récursion, qui pourtant pose tant de problèmes
Vous voulez bien m'aider encore ? <3
Marsh Posté le 03-08-2014 à 19:09:24
Code :
|
Ben déjà la je ne sais pas ce que tu veux faire (et ça coute rien de bien indenter et de mettre des blocs partout), mais clairement tu vas jamais passer dans le code avec (*pX)--; et ses potes, vu que tu auras toujours un return avant d'atteindre ce type de ligne...
A+,
Marsh Posté le 04-08-2014 à 12:33:12
Au temps pour moi il y a une coquille !
Voilà le cas 1 corrigé, indenté, et explicité :
Code :
|
En fin de compte la fonction se comporte comme une booléenne (0/1), et en plus si 0 elle modifie soit X, soit Y, c'est-à-dire qu'elle déplace le curseur sur la grille.
Marsh Posté le 05-08-2014 à 12:05:02
Pour continuer à comprendre ton code, et ses appels récursifs, c'est la fonction récursive qu'il faudrait corriger:
bool estValide (int tab[10][20])
{
int i, j, r, X, Y;
/* on cherche la case dont le numéro est le plus grand, stocke ses coordonnées dans X et Y, et sa valeur dans r */
/* on teste les conditions, et si elles sont réunies on affiche la solution puis renvoit 'false' */
// récursion et backtracking :
int direction;
for(direction=1; direction<=4; direction++)
{
// si case vide donc autorisée ...
if (deplace (tab,&X,&Y,direction) == 0)
{
// ... on met cette valeur :
tab[X][Y] = r+1;
if(estValide(tab))
{
return true;
}
tab[i][j] = 0;
}
}
return false;
}
Vu que ni i ni j, ni r ne sont initialisés.
L'emploi de i et j est d'ailleurs incompréhensible dans ce code, et r, s'il était initialisé, n"est jamais modifié...
En ce qui me concerne, je supprimerais déplace dont je n'aime pas l'effet de bord et je collerais directement ce qu'il faut dans est valide
Code :
|
A+,
Marsh Posté le 05-08-2014 à 15:44:56
Pardon d'insister mais toutes les variables utilisées sont bien initialisées, dès la première ligne :
Code :
|
Et le couple i/j sert essentiellement à ça :
Code :
|
Quant à la variable r, elle a bien un rôle : ça permet de reconnaître la dernière case du chemin déjà tracé (r le plus grand), et on l'incrémente à chaque appel.
... Ceci dit, effectivement je ne l'ai pas bien incrémentée
Ça nous donne :
Code :
|
Voilà. Je ne pensais pas être si brouillon pour vous autres relecteurs, même si c'est souvent le cas quand on lit le code d'un autre.
Merci Gilou
Marsh Posté le 05-08-2014 à 15:48:49
Au fait, l'effet de bord de 'deplace' est voulu : en modifiant les coordonnées de la case ciblée, elle permet d'avancer dans la grille.
J'imagine que c'est la sortie de route qui te fait peur, et à moi aussi quand j'ai écrit l'algo. C'est pourquoi avant de faire le moindre changement, la fonction vérifie qu'on n'a pas atteint le la ligne extérieure dudit tableau (d'où les tests X=0 ou 9 et Y=0 ou 19).
J'espère que ça ne te gênera pas trop
Marsh Posté le 05-08-2014 à 16:18:41
elles sont déclarées, mais pas initialisées, c'est à dire que tu leur donnes une valeur
Marsh Posté le 05-08-2014 à 16:47:43
C-user a écrit : Au fait, l'effet de bord de 'deplace' est voulu : en modifiant les coordonnées de la case ciblée, elle permet d'avancer dans la grille. |
La sortie de route (ie vérification des paramètres aux limites) est un code standard et n'a aucune raison de faire peur.
Mais il n'y a aucune raison de passer par une fonction a effet de bord alors que le code de ce qui est fait est si direct, c'est une couche de complication inutile.
A+,
Marsh Posté le 05-08-2014 à 16:52:12
C-user a écrit : Pardon d'insister mais toutes les variables utilisées sont bien initialisées, dès la première ligne :
|
Ceci est une déclaration et non une initialisation
Par contre
C-user a écrit :
|
Ici on a effectivement des affectations, mais ce code ne figurait nulle part dans ce que tu avais posté auparavant.
Si tu veux qu'on comprenne ce qui ne va pas dans ton code, peut être faudrait il poster un code complet et non des bribes.
A+,
Marsh Posté le 05-08-2014 à 23:32:55
Ah oui j'ai toujours confondu initialiser et déclarer pour le c, tout simplement parce que la nuance à mon petit niveau n'a jamais eu que peu d'importance ..
Citation : peut être faudrait-il poster un code complet et non des bribes. |
Effectivement j'ai pas mal hésité dans mon premier message entre d'une part tout poster et vous noyer dans les détails de l'énoncé, et d'autre part "masquer" (synthétiser) comme je l'ai fait les petites fonctions qui n'étaient pas censées poser problème à l'exécution. Je comprends que l'absence des détails de ce paragraphe gêne la compréhension vu que je réutilise un peu ces variables, mais je ne peux pas tout poster (je pense surtout à ces quelques lignes simples qui testent les conditions, mais qui n'apporteraient rien pour le coup).
Maintenant, je pense également que le problème n'est pas là.
Citation : Si tu veux qu'on comprenne ce qui ne va pas dans ton code |
Justement, je suis désormais à peu près certain que ce n'est pas un problème de "langage", mais plutôt de méthode ; ainsi (et à part les erreurs de débutant que vous m'avez gentiment corrigées) je pense connaitre suffisamment les bases du c pour écrire ce que j'ai en tête, l’enchaînement des étapes, mais que cette façon de traiter l'énoncé n'est pas pensé de la bonne manière.
Je ne sais pas si ce que je raconte est bien exprimé, vous aurez saisi l'idée
Ma faible expérience ne me permet pas encore de prendre le recul nécessaire afin de modifier globalement (et si possible efficacement) l'angle d'attaque choisi de prime abord. Je n'ai pas étudié l'ensemble des façons de faire. Le retour sur traces me parlait pas mal suite à un TP réalisé cette année (pour résoudre des labyrinthes), c'est donc par là que j'ai commencé mes recherches (enfin c'est un bien grand mot !).
Concrètement, un prof m'a dit : "les récursions c'est un joli jouet théorique mais à bannir de la programmation efficace".
Avec votre expérience et votre recul, comment attaqueriez-vous le problème ?
PS : je vous remercie pour votre patience avec moi, et désolé pour le pavé ^^
Marsh Posté le 06-08-2014 à 06:59:21
C-user a écrit : Ah oui j'ai toujours confondu initialiser et déclarer pour le c, tout simplement parce que la nuance à mon petit niveau n'a jamais eu que peu d'importance .. |
Pourtant elle est fondamentale, et encore plus en C. Dans la plupart des langages maintenant on s'en fiche, mais ici non. En C, par défault, les variables ne sont pas initialisées. Passe ta souris au-dessus de X au premier appel de deplace() tu vas voir des valeurs bizarres genre -32761, puis un segmentation fault.
Mais j'ai l'impression que le problème de base n'est pas le C, mais plutôt l'algo. Tu veux pas écrire en pseudo code ce que tu essayes de faire ?
Marsh Posté le 06-08-2014 à 11:43:44
Citation : Concrètement, un prof m'a dit : "les récursions c'est un joli jouet théorique mais à bannir de la programmation efficace". |
C'est juste faux si la récursion en question est de la tail recursion.
Bon, en regardant plus loin dans votre code, il manque un test d'arrêt final dans votre fonction récursive
Par exemple (si j'ai bien compris, l'algo va numéroter de manière croissante toute les cases, sauf la case initiale a valeur 1):
if (r == 10 * 20) { return true; }
D'autre part, votre ordre de parcours pour chercher une case a numéroter haut bas gauche droite n'est pas très efficace (sur quelques tests que j'ai effectué). L'ordre haut gauche bas droite trouve une solution beaucoup plus rapidement.
L'algo a l'air de croitre de manière exponentielle en fonction du nb de cases. Sur ma bécane (vieille et poussive), avec un rectangle 16x10 la solution est quasi instantanée, avec un rectangle 18x10, ça prend de 2 a 3 mn, et je n'ai pas eu la patience de tester avec un rectangle 20x10.
A+,
Marsh Posté le 06-08-2014 à 11:52:25
Yonel a écrit : Mais j'ai l'impression que le problème de base n'est pas le C, mais plutôt l'algo. Tu veux pas écrire en pseudo code ce que tu essayes de faire ? |
Son algo (tel qu'actuellement donné dans son code) numérote de manière croissante les cases d'un tableau rectangulaire. Il part de la case avec le plus grand numero r (au premier pas, c'est la case initialisée a 1 qui est trouvée) et cherche une une case a 0 autour. S'il en trouve une, il y met r+1 et s'appelle récursivement. Si l'appel revient a vrai (ie il a pu numéroter récursivement le reste du tableau), il retourne avec vrai et sinon, il remet la case trouvée a 0 et cherche une autre case voisine a numéroter pour faire la même chose. Si aucune case voisine ne convient, il revient avec faux.
A+,
Marsh Posté le 06-08-2014 à 12:04:36
Promis je fais attention maintenant
Relis un peu les derniers messages, tu verras que X est bien ... initialisée ^^ ... => On cherche la case dont le contenu est le nombre le plus élevé (au premier appel c'est la case départ, qu'on a initialisée à 1), et une fois qu'on l'a trouvée :
- on stocke ses coordonnées dans X et Y
- on stocke sa valeur dans r (donc on commence par r=1, puis incrémenté à chaque appel).
Citation : j'ai l'impression que le problème de base n'est pas le C, mais plutôt l'algo |
Jackpot !
VOICI LE CODE COMPLET :
Code :
|
Voilà, j'espère que ça vous éclaire !
Marsh Posté le 06-08-2014 à 12:12:33
Gilou a parfaitement expliqué, merci à toi !
Citation : il manque un test d'arrêt final dans votre fonction récursive |
Effectivement, il y en a un dans le code complet (comme on cherche un chemin de longueur fixe 84, dès que cette longueur est atteinte on sort).
Citation : D'autre part, votre ordre de parcours pour chercher une case a numéroter haut bas gauche droite n'est pas très efficace (sur quelques tests que j'ai effectué). L'ordre haut gauche bas droite trouve une solution beaucoup plus rapidement. |
Très étonnant ça ! Je ne cherche pas à tout prix la vitesse mais pourquoi pas, il suffira que je change la fonction... ferai ça un d'ces quatre.
Citation : Sur ma bécane (vieille et poussive), avec un rectangle 16x10 la solution est quasi instantanée, avec un rectangle 18x10, ça prend de 2 a 3 mn |
Ah bah m****, c'est pas la première fois que ça me fait le coup !
Alors cette fois je suis convaincu qu'on peut y arriver, merci
Marsh Posté le 06-08-2014 à 13:59:30
Citation : Très étonnant ça ! Je ne cherche pas à tout prix la vitesse mais pourquoi pas, il suffira que je change la fonction... ferai ça un d'ces quatre. |
Ça me semblait pas logique, et j'ai compris pourquoi: l'implémentation de l'algo est foireuse!
Faire (*pX)--; pour aller au dessus puis (*pX)++; pour aller en dessous, ca marche pas...
Avec votre algo, si vous êtes allé au dessus, quand vous voulez aller au dessous, en fait, vous revenez à la position de départ...
A+,
Marsh Posté le 06-08-2014 à 15:03:59
Citation : Faire (*pX)--; pour aller au dessus puis (*pX)++; pour aller en dessous |
Je vois, mais on ne fais jamais les deux en principe :
1. après chaque déplacement (après chaque "(*pX/Y)++/--" ) on a un 'return' qui clôt la fonction, donc déjà on ne peut pas faire les deux lors d'un même appel de 'deplace'
2. si on tente de monter d'une case par un "deplace (tab,*px, *pY, 1)", alors il se présente deux cas :
2.1. la case n'est pas libre, tab[][] != 0, et dans ce cas on ne monte pas (false), et il nous reste les autres directions à tester.
2.2. la case est libre, on y va. Dans ce cas il est impossible à l'appel suivant de redescendre, car la case est déjà remplie !
En fait la fonction 'deplace' a son rôle dans le retour sur trace (par sa construction et sa gestion des directions qui autorise la boucle 'for'), elle permet également de connaitre à chaque étape la longueur du chemin, mais elle s'assure surtout qu'à aucun moment le serpent ne se mordra la queue
Marsh Posté le 06-08-2014 à 17:30:55
À tout hasard, je vous fais part des pistes explorées en parallèles, en espérant que ça inspire quelqu'un
Ça ne mène pas à la solution comme ça mais comme j'aime les chiffres ...
Alors, si on note les mouvements effectués sur le trajet idéal, toujours de 1 à 4, on obtient une combinaison à 84 chiffres (tous de 1 à 4). J'essaie d'en extraire des infos.
On sais qu'il y a 84 chiffres. Or, pour aller de la case départ à la case arrivée, il faut en tout aller de 18 cases vers la droite (on note GD=18), et de 2 cases vers le bas (HB=2). En gros c'est la distance de Manhattan...
on note A le nombre de 1, B de 1, C de 3, D de 4 dans la combinaison
Ça veut donc dire qu'il faut : GD = D-C = 18
HB = B-A = 2
A+B+C+D = 84.
...
Ainsi on peut par exemple exprimer B, C et D en fonction de A.
C'est ce que j'ai fait => A ∈ [0;32] et C ∈ [0;32] avec A+C=32
B ∈ [2;34] et D ∈ [18;50] avec B+D=52
Tout ça nous permet d'exclure beaucoup de combinaisons, et il en reste quand même ... beaucoup !
Marsh Posté le 06-08-2014 à 22:46:23
Bon en tout cas, si vous avez toujours un débordement de pile, c'est que manifestement votre implémentation est viciée (au plus, on a 84 appels récursifs sur la pile, ce qui est minime).
En ce qui me concerne, j'aurais implémenté ce genre de chose ainsi:
Code :
|
Bon, c'est une variante simplifiée de votre pb, avec un point de départ et un point d'arrivée et une longueur imposés (je me suis amusé a le tester avec un point intermédiaire atteignable ou non comme critère supplémentaire et non vos 26 points).
Ça marche sans pb mais c'est un algo exponentiel en la taille du tableau, et ça peut prendre trop longtemps (pour ma patience) a chercher une solution lorsqu'il n'y en a pas en 10x20 (en 10x16, c'est relativement correct comme temps d’exécution).
A+,
Marsh Posté le 06-08-2014 à 23:39:29
Ouaip ça marche aussi bien sûr.
Je viens de faire le test chez moi de compiler et exécuter ton code, pas de soucis ça me sort une solution (et on pourrait s'arranger pour les avoir toutes).
En revanche pas d'amélioration pour le mien : toujours rien de notable à la compil, mais comme d'habitude le fameux :
a.out a cessé de fonctionner
Windows cherche une solution au problème...
Au fait, sérieusement, ça lui arrive de TROUVER une solution aux problèmes ?
Je ne vois pas pourquoi ça déconne comme ça : il n'y a que 2 ouvertures dans la boucle 'for' qui s'initient ! C'est rageant parfois
Marsh Posté le 07-08-2014 à 03:31:26
Ben déjà, tracez le nb d'appels récursifs a votre routine estValide.
Pour voir si ça dépasse 84...
A+,
Marsh Posté le 07-08-2014 à 12:53:26
Tiens, je croyais avoir posté un message là-dessus, pas dû cliquer où il fallait...
Apparemment, 'estValide' se lance une seule fois. Elle appelle alors 'deplace' vers le haut (cas 1).
Je rajoute des balises dans la fonction, comme ça :
Code :
|
Et en console j'obtiens :
Citation : DEBUT DEPLACE |
Il se passe quelque chose entre les repères 1 et 2 !
=> Y a-t-il un problème dans ma façon de tester la case du tableau ? Est-il interdit d'écrire comme ça avec un passage par adresse ??
Marsh Posté le 07-08-2014 à 13:00:26
J'ai donc fait un test :
Code :
|
Et ici il n'y a aucun problème, le chiffre 6 apparaît bien en sortie...
_______________________________________________________________________
Ce soir je teste ton code en l'adaptant à mes dimensions (10*20). Le programme tourne depuis 3 heures. Tant pis pour ce soir
Marsh Posté le 09-08-2014 à 01:40:38
Cher Gilou, je crois bien qu'il y a dans ton code un souci avec le retour sur traces.
En effet en affichant le tableau à chaque étape on constate que la fonction avance, avance, avance, et quand elle arrive à un cul-de-sac (oui maintenant il y en a ), au lieu de revenir aux choix précédents, elle s'arrête !
*pataper*
... Dis-moi ce que tu en penses
Spoiler : À mon avis ça pourrait venir de ta construction de la récursion. Concrètement il faudrait renvoyer 'false' si plus aucune case n'est libre (cul-d'sac), et remettre à 0 après avoir testé resoudre(case suivante). |
Marsh Posté le 09-08-2014 à 23:41:53
C-user a écrit : Cher Gilou, je crois bien qu'il y a dans ton code un souci avec le retour sur traces.
|
Possible, mais s'il y a maintenant des culs de sac, c'est que les specs initiales ont changé?
Parce que tel que c'est écrit, résoudre renvoie faux quand aucune case adjacente n'est libre, et cette sortie a faux va faire que la ligne suivante du code va être exécutée, et donc (sauf cas du premier appel), la case va être mise à 0.
Bon, ça ne mange pas de pain de rajouter un tab[X][Y] = 0; avant le return false final, mais à priori, ça me semblait inutile.
En fait l'écrire ainsi simplifierait les choses:
Code :
|
Un exemple de conditions initiales aboutissant a cet arrêt alors qu'il ne devrait pas survenir m'aiderait a comprendre.
Parce que c'est surement reproductible en taille 10x16, qui ma machine aboutit a un résultat (solution ou pas de solution) en 1mn environ.
A+,
Marsh Posté le 10-08-2014 à 12:52:48
Pour la "nouvelle" condition : le tracé ne doit pas se recouper, ça tu le savais, mais également il ne doit même pas revenir à son contact. C'est-à-dire que chaque case non-nulle #n (autre que départ et arrivée) doit être en contact avec exactement 2 cases non-nulles : #(n-1) et #(n+1).
J'ai pas trouvé de façon très futée de le faire : à chaque tour on remplit chaque case nulle jouxtant une case non-nulle d'un "- 1", qui représente un genre de mur (~ labyrinthe).
Dans la fonction d'affichage je représente les -1 par des symboles °° (degré), qui sont mal reconnus par le shell, affichant un carré hachuré.
_______
Ainsi en début de récursion, on met tous les "- 1", on teste 'deplace' (qui est alors limitée par ces murs), et le plus important lorsqu'on revient en arrière c'est de remettre les murs à "0", pour ne pas remplir toute la grille de murs...
Je teste encore tout ça, pas parfaitement au point, alors si tu as des suggestions surtout n'hésite pas
Marsh Posté le 28-07-2014 à 19:21:40
Bonjour à tous,
c'est ma première demande sur le forum. Je ne m'y connais probablement pas assez, alors j'ai besoin de votre savoir
Voici mon souci : pour résoudre un problème de trajet sur une grille 10*20 (un genre de labyrinthe si on veut), j'ai tenté d'écrire un programme en c qui liste toutes les possibilités et sélectionne la réponse en fonction de différents critères (de l'énoncé). Du coup j'apprends (enfin ré-apprends ^^) le retour sur trace ...
Évidemment, comme à chaque récursion on met un tableau de 200 entiers en mémoire, et bien la pile déborde
Après quelques tests je constate que la boucle 'for' n'est ouverte que 2 ou 3 fois, soit 2 ou 3 récursions, alors qu'il m'en faudrait ... un nombre ÉNORME !! (et pas beaucoup réductible...)
Voici mon code si ça peut aider :
Y a-t-il un moyen d'échapper à ce problème, par exemple en agrandissant la pile (quitte à monopoliser toute la machine) ou en modifiant le code pour remplacer la récursion ?
Je me suis renseigné bien sûr avant de vous solliciter, mais le peu de réponse que j'ai trouvées, et surtout comprises (comme les histoires de tail-récursivité) étaient sans effet...
Quelles que soient vos réponses je vous remercie infiniment pour votre aide
Message édité par C-user le 30-07-2014 à 17:47:32