Printf qui change le résultat d'un programme ?? - C - Programmation
Marsh Posté le 22-03-2013 à 15:16:25
Ma première idée, c'est que tu accèdes à/écrit des valeurs non initialisées (via un accès mal fait à un tableau par exemple). Du coup l'utilisation d'un printf peut changer pas mal de choses en mémoire et arranger ou empirer ta situation.
Passe un coup de valgrind
Marsh Posté le 23-03-2013 à 02:05:02
Tout d'abord merci de cette réponse rapide, et merci à la personne qui a édité mon message pour rendre mon code lisible ! Le copier-coller avait fait des dégâts...
Bref, je connaissais pas Valgrind, mais après installation et lancement de la commande "valgrind ./programme" (dois-je rajouter des options pour être plus précis ?), j'ai ceci :
Je ne saurais pas du tout l'interpréter !
==2443== Memcheck, a memory error detector
==2443== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==2443== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==2443== Command: ./test
==2443==
Null Matrice Null Null Matrice
Null Null Matrice Matrice Null
Null Null Null Matrice Null
Null Null Null Null Matrice
Null Null Null Null Null
i = 0, j = 0, k = 1
==2443== Invalid read of size 4
==2443== at 0x8048809: FC (in /home/alex/Bureau/test)
==2443== by 0x804892A: main (in /home/alex/Bureau/test)
==2443== Address 0xbe84fff0 is not stack'd, malloc'd or (recently) free'd
==2443==
i = 0, j = 0, k = 4
i = 1, j = 1, k = 2
i = 1, j = 1, k = 3
i = 2, j = 0, k = 3
i = 3, j = 2, k = 4
==2443== Conditional jump or move depends on uninitialised value(s)
==2443== at 0x804884B: FC (in /home/alex/Bureau/test)
==2443== by 0x804892A: main (in /home/alex/Bureau/test)
==2443==
1 1 1
0 1 1
1 0 1
0 0 1
0 1 0
0 1 0 2 1
==2443==
==2443== HEAP SUMMARY:
==2443== in use at exit: 0 bytes in 0 blocks
==2443== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==2443==
==2443== All heap blocks were freed -- no leaks are possible
==2443==
==2443== For counts of detected and suppressed errors, rerun with: -v
==2443== Use --track-origins=yes to see where uninitialised values come from
==2443== ERROR SUMMARY: 48 errors from 2 contexts (suppressed: 0 from 0)
==> Ca, c'est quand je lance avec la fameuse ligne commentée. C'est à dire que j'ai le résultat attendu, comme quand "j'exécute" mon code à la main (0 1 0 2 1)
Maintenant, en non commenté, ça donne ça, le mauvais résultat (et quelques affichages de matrices en plus) :
==2459== Memcheck, a memory error detector
==2459== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==2459== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==2459== Command: ./test
==2459==
Null Matrice Null Null Matrice
Null Null Matrice Matrice Null
Null Null Null Matrice Null
Null Null Null Null Matrice
Null Null Null Null Null
1 1 1
1 1 1
1 1 1
1 1 1
1 1 1
i = 0, j = 0, k = 1
==2459== Invalid read of size 4
==2459== at 0x804883F: FC (in /home/alex/Bureau/test)
==2459== by 0x8048960: main (in /home/alex/Bureau/test)
==2459== Address 0xbe974ff0 is not stack'd, malloc'd or (recently) free'd
==2459==
i = 0, j = 0, k = 4
1 1 1
0 1 1
1 1 1
1 1 1
0 1 1
i = 1, j = 1, k = 2
i = 1, j = 1, k = 3
1 1 1
0 1 1
1 0 1
1 0 1
0 1 1
i = 2, j = 0, k = 3
==2459== Conditional jump or move depends on uninitialised value(s)
==2459== at 0x8048881: FC (in /home/alex/Bureau/test)
==2459== by 0x8048960: main (in /home/alex/Bureau/test)
==2459==
1 1 1
0 1 1
1 0 1
0 0 0
0 1 1
Fail !
1 1 1
0 1 1
1 0 1
0 0 0
0 1 1
1 1 1
0 1 1
1 0 1
0 0 0
0 1 1
0 1 0 -1 1
==2459==
==2459== HEAP SUMMARY:
==2459== in use at exit: 0 bytes in 0 blocks
==2459== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==2459==
==2459== All heap blocks were freed -- no leaks are possible
==2459==
==2459== For counts of detected and suppressed errors, rerun with: -v
==2459== Use --track-origins=yes to see where uninitialised values come from
==2459== ERROR SUMMARY: 39 errors from 2 contexts (suppressed: 0 from 0)
Marsh Posté le 23-03-2013 à 02:24:46
Bonjour !
Votre problème de variable non initialisée est toujours présent, que vous incluiez la ligne avec le "printf" ou non, et valgrind la met en évidence dans tous les cas (ce qui est rassurant )
Recompilez votre programme en débug et valgrind vous indiquera pour chaque erreur le numéro de la ligne correspondante, et vous pourrez corriger très rapidement.
Bonne continuation !
Marsh Posté le 23-03-2013 à 12:57:59
Hum, d'accord. Effectivement, je crois qu'on avance. Deux petits problèmes : Premièrement, je ne connais pas bien Valgrind. Quand vous dites "Recompilez votre programme en débug", ça signifie rajouter l'option -g ? En tout cas, après avoir fait ça, j'obtiens ceci :
==2059== Invalid read of size 4
==2059== at 0x804883F: FC (test.c:126)
==2059== by 0x8048960: main (test.c:155)
==2059== Address 0xbefadff0 is not stack'd, malloc'd or (recently) free'd
Puis un peu plus loin...
==2059== Conditional jump or move depends on uninitialised value(s)
==2059== at 0x8048881: FC (test.c:132)
==2059== by 0x8048960: main (test.c:155)
Donc si j'ai bien compris, mon affectation de ma matrice tmp (ligne 126) ne s'est pas faite correctement, ce qui explique le "Conditional jump or move depends on uninitialised value(s)" ligne 132. Ce qui explique également que mon résultat soit faux. Ca se tient. Seulement, pourquoi cette affectation s'est mal déroulée ? Je ne comprends pas très bien le message d'erreur. L'affectation de tmp a été faite sur matrice_pointeurs, qui elle-même a été faite dans la fonction couleur_graphe, à partir de la ligne 94...
Deuxième problème, et je crois que c'est ce qui me rend fou, pourquoi diable un printf change-t-il le résultat ? J'ai bien compris que mes erreurs apparaissent aussi quand je l'enlève, même si j'ai le bon résultat. Mais comment ça se fait ? Le printf aurait changé des choses dans les pointeurs, les affectations ?
Marsh Posté le 23-03-2013 à 14:24:03
Bonjour ! L'erreur indique simplement que l'une des valeurs "d'entrée" de l'affectation ligne 126 n'est pas initiailisée.
Le mieux, pour savoir laquelle est de remplacer :
Code :
|
par
Code :
|
qui vous donnera toutes les informations, et surtout vous indiquera laquelle des deux valeurs n'est pas initialisée. Une fois celle-ci identifiée, remontez la chaîne !
Bonne continuation !
Marsh Posté le 23-03-2013 à 14:27:42
Bon, je crois que j'ai compris:
tmp.mat[c1][c2]=matrice_pointeurs[i][k]->mat[c1][c2];
cette ligne pose problème par la suite, ce qui veut dire qu'il y a du pointeur nul ou invalide qui traine...
ou matrice_pointeurs[i][k] est il mis à autre chose que NULL?
Dans couleur_graphe, ou on fait:
matrice_pointeurs[0][1]=&contraintes[0];
etc
Quelle est la durée de vie de contraintes?
contraintes est déclaré comme
matrice contraintes[M];
dans couleur_graphe, donc sa durée de vie est limitée à celle de couleur_graphe
et donc comme dans FC, on n'est plus dans couleur_graphe, les zones mémoires utilisées pour contraintes peuvent donc être réutilisées...
A+,
Marsh Posté le 23-03-2013 à 14:57:50
En effet, vos matrices "contraintes" sont déclarées dans une variable locale, dont vous stockez les adresses des éléments dans matrice_pointeurs puis, à la fin de la fonction, la mémoire est désallouée.
Le cycle de vie de la matrice "contraintes" n'est pas suffisant, déclarez-la elle aussi en variable dans le "main" et passez là à la fonction "couleur_graphes" et tout ira mieux !
Bien vu, gilou !
Marsh Posté le 23-03-2013 à 22:17:15
Merci de votre aide, vous êtes des génies ! Donc, permettez-moi de résumer pour être sûr d'avoir bien compris :
Ma matrice matrice_pointeurs, qui comme son nom l'indique est une matrice de pointeurs, a pour éléments soit des pointeurs pointant sur NULL, soit des pointeurs pointant sur une autre matrice, mais une matrice d'entiers. Ce sont les fameuses "contraintes". contraintes est défini localement dans couleur_graphe, donc à cet instant, matrice_pointeurs pointe où il faut, comme il faut. Mais à la fin de la procédure, matrice_pointeurs pointe sur des trucs potentiellement désalloués, puisqu'ils étaient locaux.
C'est là que je suis pas sûr : en fait, si je touche à pas grand chose, tout se passe bien ? Mais si je fais un printf, celui-ci nécessite un tout petit peu de mémoire et mon OS peut décider d'allouer l'emplacement qui était celui des contraintes. Donc matrice_pointeurs va pointer au bon endroit, mais sur des valeurs qui ont pu changer. C'est pourquoi mon résultat final s'en retrouve erroné ?
Bref, j'ai bien compris ?
Bon sinon, en modifiant mon code le plus simplement possible, valgrind me donne :
==1944== HEAP SUMMARY:
==1944== in use at exit: 0 bytes in 0 blocks
==1944== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==1944==
==1944== All heap blocks were freed -- no leaks are possible
==1944==
==1944== For counts of detected and suppressed errors, rerun with: -v
==1944== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Ca signifie plus d'erreur, n'est-ce pas ?
Dernière question ? Dois-je modifier le sujet du topic en rajoutant un tag résolu, ou quelque chose comme ça ?
En tout cas, merci encore de votre aide !
Marsh Posté le 23-03-2013 à 23:53:44
alexanonymous a écrit : Bon sinon, en modifiant mon code le plus simplement possible, valgrind me donne : |
Ça signifie qu'avec les paramètres que tu as mis dans ton programme il n'y a effectivement plus de fuites mémoire ou d'accès à des valeurs non initialisées, ce qui était ton problème à la base
Marsh Posté le 22-03-2013 à 14:50:55
Bonsoir,
J'ai l'impression d'avoir un problème venu d'un autre monde ! Selon que je laisse ou que j'enlève un printf (en le mettant en commentaire par exemple), le résultat de mon programme change !
Je vous donne le code mais je ne pense pas que ça soit très utile.
Le résultat final devrait être 0 1 0 2 1, mais de temps en temps, j'ai des résultats bizarres avec des -1...
Encore une fois, c'est peut-être pas la peine de se jeter dans le code, surtout qu'il n'est pas commenté.
Ce en quoi vous pourriez m'aider, c'est me dire par exemple si chez vous aussi, en mettant EN METTANT EN COMMENTAIRE OU NON la ligne 116, le résultat change (la ligne afficher_matrice(*domaine, N, D); )
Vous pourriez aussi me dire dans quelles circonstances un simple printf peut changer un résultat ! Je prends l'exemple de cette ligne mais je pense que je peux arriver à des résultats bizarres en laissant / enlevant d'autres lignes ! (ce qui m'est arrivé d'ailleurs).
Merci d'avance de votre aide !
Message édité par alexanonymous le 23-03-2013 à 01:40:47