Pièce jointe 607640
Bonjour je vous contacte car j'ai un petit soucis avec ce code je n'arrive pas à avoir un résultat dans le terminal. Pourtant le code ne m'indique aucune erreur?
En espérant que vous puissiez m'aider.
Version imprimable
Pièce jointe 607640
Bonjour je vous contacte car j'ai un petit soucis avec ce code je n'arrive pas à avoir un résultat dans le terminal. Pourtant le code ne m'indique aucune erreur?
En espérant que vous puissiez m'aider.
J'ai également la même chose pour deux autres codes.
En espérant que vous puissiez m'aider car pourtant mes codes je pense qu'ils sont bons non ?
Pièce jointe 607641
Pièce jointe 607642
Bonjour,
le code est bugué :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 $ valgrind --leak-check=full --track-origins=yes --show-reachable=yes ./arbreB ==43310== Memcheck, a memory error detector ==43310== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==43310== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info ==43310== Command: ./arbreB ==43310== ==43310== Invalid write of size 8 ==43310== at 0x109469: nouveau_noeud (arbreB.c:143) ==43310== by 0x1094BC: inserer (arbreB.c:158) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310== Address 0x4a40058 is 16 bytes after a block of size 8 alloc'd ==43310== at 0x483E7C5: malloc (vg_replace_malloc.c:380) ==43310== by 0x10944A: nouveau_noeud (arbreB.c:139) ==43310== by 0x1094BC: inserer (arbreB.c:158) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310== ==43310== Invalid write of size 8 ==43310== at 0x109475: nouveau_noeud (arbreB.c:144) ==43310== by 0x1094BC: inserer (arbreB.c:158) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310== Address 0x4a40048 is 0 bytes after a block of size 8 alloc'd ==43310== at 0x483E7C5: malloc (vg_replace_malloc.c:380) ==43310== by 0x10944A: nouveau_noeud (arbreB.c:139) ==43310== by 0x1094BC: inserer (arbreB.c:158) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310== ==43310== Invalid write of size 8 ==43310== at 0x109481: nouveau_noeud (arbreB.c:145) ==43310== by 0x1094BC: inserer (arbreB.c:158) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310== Address 0x4a40050 is 8 bytes after a block of size 8 alloc'd ==43310== at 0x483E7C5: malloc (vg_replace_malloc.c:380) ==43310== by 0x10944A: nouveau_noeud (arbreB.c:139) ==43310== by 0x1094BC: inserer (arbreB.c:158) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310== ==43310== Invalid read of size 8 ==43310== at 0x109511: inserer (arbreB.c:170) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310== Address 0x4a40048 is 0 bytes after a block of size 8 alloc'd ==43310== at 0x483E7C5: malloc (vg_replace_malloc.c:380) ==43310== by 0x10944A: nouveau_noeud (arbreB.c:139) ==43310== by 0x1094BC: inserer (arbreB.c:158) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310== ==43310== Invalid write of size 8 ==43310== at 0x109469: nouveau_noeud (arbreB.c:143) ==43310== by 0x109538: inserer (arbreB.c:181) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310== Address 0x4a400a8 is 16 bytes after a block of size 8 alloc'd ==43310== at 0x483E7C5: malloc (vg_replace_malloc.c:380) ==43310== by 0x10944A: nouveau_noeud (arbreB.c:139) ==43310== by 0x109538: inserer (arbreB.c:181) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310== et ça continue encore et encore
Même pour les codes TP1 et 2 ?
Je ne comprends pas pourquoi pourtant je n'ai aucune erreur non ?
Ce n'est pas parce que le compilo ne produit pas de messages d'erreurs que pour autant le code est correct. Je n'ai pas même lu ton code, je n'ai qu'utilisé des outils pour débuguer. En l'occurrence, j'ai utilisé valgrind pour vérifier tes accès mémoires, et ils sont fautifs, le log te donne même les endroits … Par exemple pour la première erreur :
valgrind te dit que dans main à la ligne 388 tu appelles la fonction inserer qui elle-même appelle nouveau_noeud en ligne 158 ; dans nouveau_noeud en ligne 139 tu alloues un espace mémoire de taille 8 bytes. Dans la même fonction tu essayes d'écrire 16 bytes après cette portion de mémoire allouée ! Cela provoque une erreur …Code:
1
2
3
4
5
6
7
8
9
10 ==43310== Invalid write of size 8 ==43310== at 0x109469: nouveau_noeud (arbreB.c:143) ==43310== by 0x1094BC: inserer (arbreB.c:158) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310== Address 0x4a40058 is 16 bytes after a block of size 8 alloc'd ==43310== at 0x483E7C5: malloc (vg_replace_malloc.c:380) ==43310== by 0x10944A: nouveau_noeud (arbreB.c:139) ==43310== by 0x1094BC: inserer (arbreB.c:158) ==43310== by 0x1099DA: main (arbreB.c:388) ==43310==
Alors si on regarde de plus près le code de la fonction nouveau_noeud :
on voit que tu alloues de la mémoire mais que très certainement le sizeof est incorrect. Je suppose que tu as voulu écrire x = malloc(sizeof(struct noeud_s). C'est toujours, mais toujours, une mauvaise idée que de cacher un pointeur dans un typedef.Code:
1
2
3
4
5
6
7
8
9
10
11
12 b_t nouveau_noeud(element_t a){ ab_t x; x = malloc(sizeof(ab_t*)); if (!x) { perror("Echec malloc"); } x->parent = NULL; x->gauche = NULL; x->droite = NULL; x->e = a; return x; }
Il est aussi souvent bien plus simple d'écrire x = malloc(sizeof *x) ; au moins tu es certain que la bonne taille sera allouée (dans la très grande majorité des cas, il y aura toujours quelques exceptions, mais en ce qui te concerne ce sera toujours bon).
J'ai débusqué une erreur dans ton code sans même le lire entièrement ni même essayer de le comprendre. C'est grâce aux outils de débugage … c'est indispensable de savoir s'en servir, car débuguer vcia un forum est non seulement lent mais il ne te permettra pas d'apprendre de tes erreurs puisqu'au fond tu ne les trouves pas.
Il va falloir apprendre à utiliser valgrind et un debuger pas à pas …
Ca y est j'ai finalement bien reussi a faire marcher le code par contre , pour les TP1 et 2 est ce le même problème? Parce que au niveau des allocations je n'ai pas vu de problème particulier ?
Je t'ai montré comment faire, n'as-tu pas essayé ?
Comment je dois télécharger valgrind ?
euh … bah oui … comment veux-tu bosser sans les outils adéquats ?
tu te rends compte que j'ai trouvé quelques erreurs sans connaître ton code ni même le lire … alors que toi tu pataugeais, toi qui l'as écrit. Ce n'est pas une question de savoirs ou d'expérience, c'est juste une question d'outils.
mais bon, sur quelle plateforme développes-tu ?
Je travaille sur eclipse
plateforme =
quel OS : windows ? mac ? linux ?
quel compilo : gcc ? clang ? autre ?
…
Windows 10 et compilateur GCC
Je ne développe pas sous windows, mais on peut trouver : Existe-t-il un bon substitut Valgrind pour Windows?.
Il est impératif, lorsqu'on développe, de savoir utiliser ce genre d'outils.
Bon j'ai télécharger VerySleepy et ça ne me donne pas d'erreur je ne comprends plus rien..
Bonjour.
J'ai seulement pris le TP1 pour voir un peu de quoi il en retourne.
Tu utilises une première fonction chargeGraphe(); pour initialiser deux tableaux imbriqués. Voila quelques remarques d'ordre générales pour commencer :
- Le nom de la fonction doit être le plus explicite possible. Si elle initialise des données, on n'utilise pas le mot "charge" qui sous-entend que des données particulières vont être utilisées ;
- En programmation C on ne caste pas malloc(); ;
- Si une erreur survient lors de l'allocation mémoire on ne quitte pas l'application comme un goret :D;
- Si une erreur d'allocation mémoire pour le deuxième tableau survient il faut désallouer le premier avant de sortir ;
- On teste les paramètres en entrée. Si l'utilisateur entre un nombre inférieur à 1. Que se passe-t-il ?
Voila ce que pourrait donner ta fonction en fonction des remarques précédentes :
Comme tu peux le voir cette fonction renvoie un pointeur valide ou bien NULL en cas d'erreur. La fonction appelante devra donc vérifier ce qu'elle reçoit et faire le traitement en fonction. Tu utilises d'ailleurs dejà cette méthode avec malloc ();. Quitter le programme ne pouvoir se faire que depuis la fonction main ();. Ainsi, puisque cette fonction d'initialisation est appelée justement dans main (); il est facile de quitter proprement ton programme :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 int **initGraphe(int n) { /* test du paramètre */ if (n<1) { fprintf (stderr, "n doit être supérieur à 0 dans %s ();\n", __func__); return NULL; } int **adjc ; // On initialise le premier tableau adjc = malloc(n*sizeof(int**)); if (adjc==NULL) { fprintf (stderr, "Probleme d'allocation memoire pour le premier tableau dans %s ();\n", __func__); return NULL; } // On initialise le deuxieme tableau int i,k; for(i=0;i<n;i++) { adjc[i] = malloc(n*sizeof(int)); if( adjc[i]==NULL) { fprintf (stderr, "Probleme d'allocation memoirepour le deuxième tableau dans %s ();\n", __func__); /* Libération de la première partie du deuxième tableau déjà allouée */ for (int j=0; j < i; j++) free (adjc[j]); /* Libération du premier tableau */ free (adjc); return NULL; } } for(i=0;i<n;i++){ for(k=0;k<n;k++){ adjc[i][k]=0; } } return adjc; }
La fonction marquerVoisins(); :Code:
1
2
3
4
5
6
7
8
9
10 int main (void) { int**adjacence; int n = 4; adjacence = chargeGraphe(n); if (!adjacence) exit (1); ...
Sans chercher à comprendre l'algorithme de cette dernière voila ce qui me choque :
Tu ne remarques rien ? Dans le commentaire il est dit d'allouer un tableau de taille n. Déjà comment récupères-tu n ? Ensuite l'allocation proprement dite n'alloue qu'un espace mémoire pour un int.Code:
1
2
3
4
5 // Allouer le tableau marques de taille «n» marques=(int*)malloc(sizeof(int)); if(marques==NULL) { printf("Probleme d'allocation memoire\n"); }
Passé cette allocation tu scrutes cette mémoire avec la boucle suivante :
Je me dis à ce niveau qu'en fait ordre doit valoir n. Il faut modifier la formulation de ton allocation de marques.Code:
1
2 for (x=0; x < ordre; x++) marques[x]=0;
Je suppose que tu as oublié [i] sur la ligne en gras.Citation:
Code:
1
2
3
4
5
6
7
8
9
10 for(i=0;i<n;i++) { adjc[i] = malloc(n*sizeof(int)); if( adjc==NULL) { fprintf (stderr, "Probleme d'allocation memoirepour le deuxième tableau dans %s ();\n", __func__); /* Libération du premier tableau */ free (adjc); return NULL; } }
Mais surtout, si une allocation échoue, il faut libérer toutes les précédentes qui ont réussi.
Pour ça, c'est plus simple de faire une unique grosse allocation n*n que multiplier ça en matrice.
Je n’ai pas voulu trop compliquer les explications. Je ne suis pas sûr qu’il en soit à ce niveau ;)
Édit : j’ai modifié le code suite à ta remarque justifiée sur la vérification de l’allocation mémoire.
Merci pour les conseils j'ai réussi a faire marche les TP0, 3, 4 et 5
Mais pour le 1 et 2 je ne comprends pourquoi rien ne s'affiche.
Je n'arrive pas à faire marcher la fonction afficheGraphe
C'est un des memory profilers que tu aurais dû télécharger ⇒ DrMemory ou UMDH … mais je ne sais pas ce qu'ils vallent.
N'oublie pas de compiler en utilisant les options -Wall -Wextra pour les warnings, et le -g pour le debugging.
Tu as bien un mode debug avec eclipse, non ? un mode où tu peux mettre des points d'arrêts, puis exécuter pas à pas en scrutant la valeur des variables ?
Il faut que utilises ça pour débuguer plutôt qu'un forum, il y a de la doc en plus : debug + eclipse.