Bonjour,
Débutant en C, je suis en train de faire un petit exercice pour m'entrainer.
Le but est de remplir une liste de containers dans un nombre de silos ayant une hauteur max, puis de les afficher
J'ai essayé cet algo pour remplir:
void remplir1(LesSilos stockage, int nbSilos, int hMax, GSList *liste){
int nbContainers = g_slist_length(liste);
int containerEnCours = 0;
int siloEnCours = 0;
int hauteurRestante = hMax;
int silos = nbSilos;
while((nbContainers > 0) && (silos > 0)) {
Element *elt = (Element*)g_slist_nth_data(liste, containerEnCours);
if(hauteurRestante >= elt->hauteurElement){
empiler(stockage[siloEnCours], elt);
containerEnCours++;
nbContainers--;
hauteurRestante = hauteurRestante - elt->hauteurElement;
}
else{
siloEnCours++;
hauteurRestante = hMax;
silos--;
}
}
}
et ceux-ci pour l'affichage:
void ecrireUnElement(gpointer data, gpointer user_data){
Element *elt;
elt = (Element*)data;
printf("Element %s de hauteur %d\n", elt->nomElement, elt->hauteurElement);
}
void ecrireDonnees(GSList *liste){
g_slist_foreach(liste, (GFunc)ecrireUnElement, NULL);
}
void afficherSilos(LesSilos stockage, int n){
int i;
for(i=0; i<n; i++){
ecrireDonnees(stockage[i]);
}
}
Seulement lorsque je lance l'algo de remplissage, j'obtiens une erreur de segmentation lors de l'affichage. Je suppose que les silos ne sont pas remplis, mais je n'en suis pas sur...
Est-ce bien celà ?
Merci d'avance
il est difficile de donner une reponse sans avoir le code complet.
Mon conseil est (comme toujours quand on a une segfault): fait tourner le code dans valgrind.
Ou passer en debugueur.
Selon ton IDE ça fait plus ou moins peur au début mais avec la ligne qui flanche + les dernières valeurs de variables recensées + la pile d'instruction tu fais souvent très mal !
Apres passage dans valgrind, j'obtiens ca:
==25715== Memcheck, a memory error detector
==25715== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==25715== Using Valgrind-3.5.0-Debian and LibVEX; rerun with -h for copyright info
==25715== Command: ./main
==25715==
==25715== Conditional jump or move depends on uninitialised value(s)
==25715== at 0x40877B0: g_slist_foreach (gslist.c:465)
==25715== by 0x8048932: ecrireDonnees (fonctions.c:61)
==25715== by 0x8048BAA: afficherSilos (fonctions.c:153)
==25715== by 0x80487D4: main (main.c:39)
==25715==
==25715==
==25715== HEAP SUMMARY:
==25715== in use at exit: 5,251 bytes in 30 blocks
==25715== total heap usage: 31 allocs, 1 frees, 5,603 bytes allocated
==25715==
==25715== LEAK SUMMARY:
==25715== definitely lost: 1,016 bytes in 2 blocks
==25715== indirectly lost: 0 bytes in 0 blocks
==25715== possibly lost: 671 bytes in 24 blocks
==25715== still reachable: 3,564 bytes in 4 blocks
==25715== suppressed: 0 bytes in 0 blocks
==25715== Rerun with --leak-check=full to see details of leaked memory
==25715==
==25715== For counts of detected and suppressed errors, rerun with: -v
==25715== Use --track-origins=yes to see where uninitialised values come from
==25715== ERROR SUMMARY: 4 errors from 1 contexts (suppressed: 15 from 8)
mais je n'ai jamais utilisé ceci...
les lignes qui t'interessent sont les suivantes:
==25715== Conditional jump or move depends on uninitialised value(s)
==25715== at 0x40877B0: g_slist_foreach (gslist.c:465)
==25715== by 0x8048932: ecrireDonnees (fonctions.c:61)
==25715== by 0x8048BAA: afficherSilos (fonctions.c:153)
==25715== by 0x80487D4: main (main.c:39)
a la ligne 465 de gslist.c, une condition utilise une zone memoire non initialise. Ca veut probablement dire que tu ne l'a pas initialise auparavant.
« Mon conseil est (comme toujours quand on a une segfault): fait tourner le code dans valgrind. »
heu… gdb / ddd plutôt pour un segfault. En pratique, c'est plus simple et plus rapide.
en moyenne, je trouve l'erruer plus rapidement avec valgrind parceque souvent la seg fault vient d'un autre probleme un peu plus tot dans l'execution. Si la premiere erreur est celle qui caus ela segfault, alors je degaine un debugger.
Après verifications en tout genre, il semble que mon probleme vienne directement lorsque j'appelle ma fonction creerLesSilos, qui pour une raison qui m'est totalement inconnue, me rempli automatiquement les deux premiers silos d'un element...
En fait, lorsque dans mon main, je fais:
/*Creation des silos*/
LesSilos mesSilos;
mesSilos = creerLesSilos(4);
et après affichage de la longueur de chaque silo, je me rend compte que les deux premiers valent 1, et les deux derniers 0 (alors que cette fonction est seulement sensé m'allouer la memoire).
Faut-il alors que je "vide" chaque silo crée ? Et si oui, comment puis-je faire ?
sans le code de la fonction creerlessilo et les structures de donnees associe, il me semble difficile de repondre a la question.
My educated guess would be : tu alloues la memoire, mais ne l'initialise pas.
Un très bon conseil dans ta vie de programmeur : On a le droit d'identifier un problème en essayant de le contourner... Mais on ne le résout pas pour autant !
Si ta fonction bugue tu dois voir d'où ça vient, et pas t'amuser à faire du rafistolage en sortie.
Pour t'aider ils nous manquent les éléments essentiels à mes yeux qui sont : qu'est ce que la structure LesSilos, et deuxièmement que se passe-t-il dans la fonction creerLesSilos.
PS : Si je puis me permettre tu as de très mauvais noms de variables, qui plus est l'anglais c'est mieux en programmation.
Ma fonction creerLesSilos:
LesSilos creerLesSilos(int n){
/*Reservation du tableau*/
UnSilo *tab = NULL;
/*Allocation du tableau*/
tab = malloc(n*sizeof(UnSilo));
return tab;
}
Elle ne fait qu'allouer l'espace memoire d'un tableau stockant les pointeurs des listes chainées (qui modelisent les silos).
Mes definitions de type:
typedef GSList *UnSilo;
typedef UnSilo *LesSilos;
Si tu ne forces pas la taille des silos a une valeures, comment ton programme peut savoir quelle valeure tu souhaites ?
(par ailleurs, qu'est ce que c'est un GSList ?)
Une GSList, c'est une liste chainee.
Et je passe la taille de mes silos dans mon algorithme qui va me replir ces silos.
Je ne sais toujours pas bien ce que je dis parceque tu n'as toujours pas donner de code complet. Mais j'ai quand meme l'impression que apres "tab = malloc(n*sizeof(UnSilo));", les pointeurs dans le tableau ne sont pas initialises a NULL ou a une valeure coherente.
En gros, je dois créer mes silos avec cette fonction (qui ne fait qu'allouer la mémoire, et ne remplit pas ces silos). Mes silos ne sont en fait qu'un simple tableau qui vont contenir les pointeurs des listes chainées (GSList).
Il seront remplis qu'avec un autre algo (beaucoup trop gros pour le mettre ici), qui initialisera justement la taille de chaque silo.
Et donc oui, lorsque je crée mon tableau de silo, il n'est pas vide...
Par exemple, lorsque je fais:
LesSilos mesSilos = creerLesSilos(4);
toutes les tailles des silos (que j'obtiens par la fonction g_slist_length) devraient être à 0, vu que je n'ai encore rien mis dedans. Or, certaines sont à 1...
Donc voilà pourquoi je souhaiterais vider mon tableau avant de le remplir (bizarre, car il devrait être vide, mais bon)
C'est un peu dur à expliquer c'est vrai...
Noms de structures et de variables exotiques, aucun copier-coller des définitions, c'est à n'y rien comprendre du tout mon gars !
Tiens, copie-colle le code entier sur ce site et donne nous le lien qu'on y comprenne quelque chose :
http://ideone.com/
"toutes les tailles des silos (que j'obtiens par la fonction g_slist_length) devraient être à 0, vu que je n'ai encore rien mis dedans. Or, certaines sont à 1... "
Non, pour ça il faut d'abord que tu initialise chaque silo. Sinon leur contenu est complètement aléatoire après un malloc et tu ne peut appeler aucune fonction qui va lire ce qu'il y a dans la structure (c'est l'idée du message d'erreur de valgrind qui dit que tu lis une donnée qui n'a pas été initialisé).
Mes fonctions: http://ideone.com/DqoYf
Mon main: http://ideone.com/IScMU
Désolé pour le double post, mais si dans le main, je fais la déclarations des silos avant celle des containers, je n'ai plus cette erreur...
Ce n'est pas ca qui cause l'erreur probablement mais :
Ligne 67
" while(fscanf(fichier, "%s %d", nom, &hauteur) != EOF){"
Il faut verifier que fscanf retourne 2 egalement.
Ligne 78 et 80:
" /*Ajout en fin de liste*/
liste = g_slist_prepend(liste, (gpointer)elt);"
Ca, ca ajoute en debut de liste, pas en fin de liste. cf
http://library.gnome.org/devel/glib/stable/glib-Singly-Linked-Lists.html#g-slist-prepend
Ta seg fault vient bien de ce que je pensais, les donnees ne sont pas initialise apres "tab = malloc(n*sizeof(UnSilo));" ligne 130.
La prochaine utilisation de tab[i] que tu fais est : "stockage[siloEnCours] = empiler(stockage[siloEnCours], elt); /*On empile le container*/" Ligne 145.
Ensuite, tu les afficheras avec "g_slist_foreach(liste, (GFunc)ecrireUnElement, NULL);" ligne 110.
Ce qui se passe est que malloc n'initialise pas ses donnes. Du coup, tu peux recuperer NULL ou n'importe quoi. Suivant l'ordre dans lequel tu fais les operations ce qui se trouve dans la memoire que tu alloue est different. D'ailleurs si tu changes d'ordinateur, de compilateur ou de systeme d'exploitation tu aurais un comportement different.
La solution a se probleme est d'initialiser les cases de ton tableau a NULL apres sont allocation:
tab = malloc(n*sizeof(UnSilo));
for (int i=0;i<n;i++)tab[i]=NULL;
ou encore utiliser calloc a la place de malloc.