Bonjour !
Voici mon code :
adherents.txt
projet.c1 MICHAUD Apolline apolline.m@gmail.com 02 03 2016 2 2 DODIER Marcelle marcelle.d@gmail.com 24 04 2016 1 3 VENNETIER Violaine violaine.v@gmail.com 01 01 2016 0 4 CHARBONNEAU Dominique dominique.c@gmail.com 12 12 2016 3 5 MARCHAND Eustache eustache.m@gmail.com 12 04 2016 2
projet.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203 #include "projet.h" void adherents_global() { Adherent **tadherents, a; int nbAdherents=0, i; tadherents=(Adherent**)malloc(sizeof(Adherent*)); if(tadherents == NULL) { printf("Erreur : Impossible d'allouer de la mémoire.\n"); exit(1); } tadherents=adherents_chargement(tadherents, &nbAdherents); for(i=0;i<nbAdherents;i++) adherents_affichage(tadherents[i]); /* --- SUPPRESSION --- */ int tmp; printf("\nEntrez l'ID de l'adhérent à supprimer : "); scanf("%d",&tmp); tadherents=adherents_supprimer(tadherents,&nbAdherents,tmp); for(i=0;i<nbAdherents;i++) adherents_affichage(tadherents[i]); /* --- /SUPPRESSION --- */ /* +++ AJOUT +++ */ printf("\nEntrez l'adresse mail du nouvel adherent : "); scanf("%s%*c", a.mailAd); while(adherents_emailCheck(a.mailAd) != 0) { printf("\nVeuillez entrer une adresse e-mail valide."); printf("\nEntrez l'adresse mail de l'adherent : "); scanf("%s%*c",a.mailAd); } i=adherents_emailExists(tadherents, nbAdherents, a); if(i != -1) { printf("Cette adresse email est déjà utilisée.\n"); printf("Elle appartient à %s %s.\n",tadherents[i]->prenomAd, tadherents[i]->nomAd); } else { printf("\nEntrez le nom complet de l'adherent : "); scanf("%s%s%*c",a.nomAd, a.prenomAd); //uppercase, choix date ajd OU date manuelle printf("\nEntrez la date d'inscription (jj/mm/aaaa) : "); scanf("%d/%d/%d",&a.dateDAbo.jour,&a.dateDAbo.mois,&a.dateDAbo.annee); while(adherents_dateCheck(a.dateDAbo.jour,a.dateDAbo.mois,a.dateDAbo.annee) != 0) { printf("Cette date n'est pas valide.\n"); printf("\nEntrez la date d'inscription (jj/mm/aaaa) : "); scanf("%d/%d/%d",&a.dateDAbo.jour,&a.dateDAbo.mois,&a.dateDAbo.annee); } tadherents=adherents_creer(tadherents,&nbAdherents,a); } for(i=0;i<nbAdherents;i++) adherents_affichage(tadherents[i]); /* +++ /AJOUT +++ */ printf("\n"); for(i=0;i<nbAdherents;i++) { printf("Je libère la case %d.\n",i); free(tadherents[i]); } free(tadherents); } Adherent ** adherents_chargement(Adherent **tab, int *n) { FILE *fAdh; Adherent a; fAdh=fopen("adherents.txt","r"); if(fAdh == NULL) { printf("Erreur : Impossible d'ouvrir le fichier en lecture.\n"); exit(1); } a=adherents_lecture(fAdh); while(!feof(fAdh)) { tab=(Adherent**)realloc(tab, (*n+1) * sizeof(Adherent*)); if(tab == NULL) { printf("Erreur : Impossible d'allouer de la mémoire.\n"); exit(1); } tab[*n]=(Adherent *)malloc(sizeof(*tab[*n])); *tab[*n]=a; (*n)++; a=adherents_lecture(fAdh); } fclose(fAdh); return tab; } Adherent adherents_lecture(FILE *fp) { Adherent a; fscanf(fp,"%d%s%s%s%d%d%d%d",&a.identifiant,a.nomAd,a.prenomAd,a.mailAd,&a.dateDAbo.jour,&a.dateDAbo.mois,&a.dateDAbo.annee,&a.nbJeuEmp); return a; } void adherents_affichage(Adherent *a) { printf("%d %s\t%s\t%s\t%d/%d/%d\t%d\n",a->identifiant,a->nomAd,a->prenomAd,a->mailAd,a->dateDAbo.jour,a->dateDAbo.mois,a->dateDAbo.annee,a->nbJeuEmp); } int adherents_rechercheId(Adherent **tab, int n, int id) { int i; for(i=0; i <= n-1; i++) if(id == tab[i]->identifiant) return i; return -1; } Adherent ** adherents_supprimer(Adherent **tab, int *n, int id) { int i=adherents_rechercheId(tab, *n, id); if(i != -1) { printf("L'identifiant correspond a %s %s.\n",tab[i]->prenomAd, tab[i]->nomAd); printf("\nJe libère la case %d !\n",i); free(tab[i]); for(i; i<*n-1; i++) tab[i]=tab[i+1]; printf("L'adhérent a été supprimé.\n\n"); (*n)--; } else printf("\nCet identifiant n'existe pas.\n\n"); return tab; } Adherent ** adherents_creer(Adherent **tab, int *n, Adherent a) { Adherent **aux; int id, i, j; id=adherents_idNouveau(tab, *n); a.identifiant=id; a.nbJeuEmp=0; aux=(Adherent**)realloc(tab,(*n+1)*sizeof(Adherent*)); if(aux == NULL) { printf("Erreur : Impossible d'allouer de la mémoire.\n"); exit(1); } tab=aux; printf("\nJ'alloue à la case %d.\n",id-1); tab[id-1]=(Adherent*)malloc(sizeof(Adherent)); *tab[id-1]=a; (*n)++; return tab; } int adherents_emailCheck(char e[]) { if(*e =='\0') return -1; if(*e =='@') return 0; return adherents_emailCheck(e+1); } int adherents_emailExists(Adherent **tab, int n, Adherent a) { int i; for(i=0; i<n; i++) if(strcmp(a.mailAd,tab[i]->mailAd)==0) return i; return -1; } int adherents_dateCheck(int j, int m, int a) { if(m == 2 && j > 29) return -1; if(j < 1 || j > 31 || m < 1 || m > 12 || a < 1900 || a > 2099) return -1; return 0; } int adherents_idNouveau(Adherent **tab, int n) { int i; for(i=1;i<=n;i++) if(i!=tab[i-1]->identifiant) return i; return n+1; }
testprojet.c
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int jour; int mois; int annee; int heure; int minute; } Date; typedef struct { int identifiant; char nomAd[15]; char prenomAd[15]; char mailAd[40]; Date dateDAbo; int nbJeuEmp; } Adherent; void adherents_global(); Adherent ** adherents_chargement(Adherent **tab, int *n); Adherent adherents_lecture(FILE *flot); void adherents_affichage(Adherent *a); int adherents_rechercheId(Adherent **tab, int n, int id); Adherent ** adherents_supprimer(Adherent **tab, int *n, int id); Adherent ** adherents_creer(Adherent **tab, int *n, Adherent a); int adherents_emailCheck(char e[]); int adherents_dateCheck(int j, int m, int a); int adherents_emailExists(Adherent **tab, int n, Adherent a); int adherents_idNouveau(Adherent **tab, int n);
Je suis en première année de DUT Info, et je réalise un projet de C.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 #include "projet.h" int main(void) { adherents_global(); return 0; }
Il s'agit de la gestion d'une ludothèque, où mon programme doit être capable de gérer une liste d'adhérents (ajouter, supprimer, etc).
J'ai choisi de gérer mes adhérents avec un tableau dynamique de pointeurs sur des structures "Adherent".
Mon programme charge un fichier texte, remplit le tableau avec les informations du fichier, j'effectue mes opérations puis je sauvegarde.
J'ai donc une fonction pour supprimer, et une autre pour ajouter un adhérent. Ces deux fonctions marchent parfaitement... mais individuellement. Je m'explique.
Quand je vais vouloir supprimer un adhérent, puis en ajouter un nouveau, notre programme est censé récupérer le "trou" créé par la suppression pour le re-remplir.
Dans l'exemple que je vous donne, ça marche bien si j'essaie avec les adhérents d'ID 4 et 5. Mais si j'essaie avec 1, 2 et 3, il m'indique un double free() à la fin du programme, d'une case qui n'est même pas concernée !
Je vous invite sérieusement à tester mon programme pour comprendre le problème rapidement, c'est assez difficile à expliquer.
J'ai testé mon programme avec valgrind, voici ce qu'il m'indique :
Pour tenter de débugger j'ai ajouté des printf() avant chaque free() pour voir à quel moment la case en question est libérée, mais à aucun moment la case en question ne s'affiche.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
58
59
60
61
62
63
64 ==2107== Memcheck, a memory error detector ==2107== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==2107== Using Valgrind-3.10.0 and LibVEX; rerun with -h for copyright info ==2107== Command: ./test --leak-check=full --track-origins=yes -v ==2107== 1 MICHAUD Apolline apolline.m@gmail.com 2/3/2016 2 2 DODIER Marcelle marcelle.d@gmail.com 24/4/2016 1 3 VENNETIER Violaine violaine.v@gmail.com 1/1/2016 0 4 CHARBONNEAU Dominique dominique.c@gmail.com 12/12/2016 3 5 MARCHAND Eustache eustache.m@gmail.com 12/4/2016 2 Entrez l'ID de l'adhérent à supprimer : 2 L'identifiant correspond a Marcelle DODIER. Je libère la case 1 ! L'adhérent a été supprimé. 1 MICHAUD Apolline apolline.m@gmail.com 2/3/2016 2 3 VENNETIER Violaine violaine.v@gmail.com 1/1/2016 0 4 CHARBONNEAU Dominique dominique.c@gmail.com 12/12/2016 3 5 MARCHAND Eustache eustache.m@gmail.com 12/4/2016 2 Entrez l'adresse mail du nouvel adherent : test@test.fr Entrez le nom complet de l'adherent : NOUVEAU Monsieur Entrez la date d'inscription (jj/mm/aaaa) : 01/02/2013 J'alloue à la case 1. 1 MICHAUD Apolline apolline.m@gmail.com 2/3/2016 2 2 NOUVEAU Monsieur test@test.fr 1/2/2013 0 4 CHARBONNEAU Dominique dominique.c@gmail.com 12/12/2016 3 5 MARCHAND Eustache eustache.m@gmail.com 12/4/2016 2 5 MARCHAND Eustache eustache.m@gmail.com 12/4/2016 2 Je libère la case 0. Je libère la case 1. Je libère la case 2. Je libère la case 3. Je libère la case 4. ==2107== Invalid free() / delete / delete[] / realloc() ==2107== at 0x4C29E90: free (vg_replace_malloc.c:473) ==2107== by 0x400CB1: adherents_global (in <...>/test) ==2107== by 0x401472: main (in <...>/test) ==2107== Address 0x51e07a0 is 0 bytes inside a block of size 100 free'd ==2107== at 0x4C29E90: free (vg_replace_malloc.c:473) ==2107== by 0x400CB1: adherents_global (in <...>/test) ==2107== by 0x401472: main (in <...>/test) ==2107== ==2107== ==2107== HEAP SUMMARY: ==2107== in use at exit: 100 bytes in 1 blocks ==2107== total heap usage: 14 allocs, 14 frees, 1,336 bytes allocated ==2107== ==2107== LEAK SUMMARY: ==2107== definitely lost: 100 bytes in 1 blocks ==2107== indirectly lost: 0 bytes in 0 blocks ==2107== possibly lost: 0 bytes in 0 blocks ==2107== still reachable: 0 bytes in 0 blocks ==2107== suppressed: 0 bytes in 0 blocks ==2107== Rerun with --leak-check=full to see details of leaked memory ==2107== ==2107== For counts of detected and suppressed errors, rerun with: -v ==2107== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Par ailleurs, j'ai conscience qu'il y a des trucs dans mon code qui vous feront tilt, comme le while(!feof) pour lire dans mon fichier, ou les "(Adherent*) devant les malloc/realloc.
Ce sont les techniques que mon prof nous a apprises, et même si c'est pas très correct de faire comme ça (il est de la vieille école, comme on dit ^^), je fais avant tout mon projet pour la note qui m'y sera attribuée, alors tant pis...
Je vous serais VRAIMENT reconnaissant de m'aider, ce n'est pas le premier problème casse-tête comme ça que l'on rencontre, et ça commence à nous faire perdre un temps considérable...
Merci d'avance !
Partager