Hum..... :roll:
Version imprimable
C'est vrai que sa à été traité, mais je pensais que sa venait d'autre part ..
La confiance règne :mouarf:
Le problème de tri dans ta version initiale venait bien de là. qsort() te donne des pointeurs sur tes objets, les tiens étant de type char*, il y avait donc un niveau d'indirection non pris en compte.
Pourrais-tu fournir un code minimaliste reproduisant le problème pour la libération de la mémoire STP ? Histoire de compiler et exécuter.
Je suis borné :mrgreen:
Voici mon main.c simplifié :
dico.h :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 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<ctype.h> #include "dico.h" int main() { FILE* fichier = NULL; int nb_lignes_fic = 0; /** * Lecture trié des mots du dictionnaire **/ fichier = open_file(MY_FILE, "r"); if(fichier == NULL) perror("Erreur : "); else { nb_lignes_fic = nombre_lignes(fichier); afficher_tab(fichier_trier(charger_fichier(alloc_fichier_tab(fichier, nb_lignes_fic),fichier), fichier, nb_lignes_fic), nb_lignes_fic); // Libération de la mémoire free_fichier_tab(alloc_fichier_tab(fichier, nb_lignes_fic), nb_lignes_fic); } fclose(fichier); return 0; }
dico.c :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 /** * * Prototypes de fonctions du fichier dico.h * **/ #ifndef DEF_DICO #define DEF_DICO #define LENGTH_MOT_MAX 30 #define MY_FILE "dictionnaires.txt" FILE *open_file(const char* fic, const char* mode); void ecrire_fichier(const char *chaine, FILE* ficher); void lire_fichier(FILE *fichier); int nombre_lignes(FILE *fichier); int compareString(const void* str1, const void* str2); char** alloc_fichier_tab(FILE *fichier, int nb_lignes); char** charger_fichier(char** pTableau, FILE* fichier); char** fichier_trier(char** pTableau, FILE* fichier, int nb_lignes); void afficher_tab(char** pTableau, int nb_lignes); void free_fichier_tab(char** pTableau, int nb_lignes); #endif
La seul erreur de compilation que j'ai c'est avec -Wextra :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
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 #include<stdio.h> #include<stdlib.h> #include<string.h> #include "dico.h" /** * Retourne un pointeur sur le fichier **/ FILE *open_file(const char* fic, const char* mode) { return fopen(fic, mode); } /** * Renvoie le nombre de ligne du fichier **/ int nombre_lignes(FILE *fichier) { int nb_lignes = 0; int c; do{ c = fgetc(fichier); if (c == '\n') nb_lignes++; }while (c != EOF); rewind(fichier); return nb_lignes; } /** * Compare 2 chaînes de caractère **/ int compareString(const void* str1, const void* str2) { // renvoie 0 si chaîne identique // renvoie un nombre positif si les caractères de la chaîne 1 sont supérieur à ceux de la chaîne 2 // renvoie un nombre négatif sinonn char *a = *(char**)str1, *b = *(char**)str2; return strcmp(a,b); } /** * Chargement du fichier en mémoire **/ char** alloc_fichier_tab(FILE *fichier, int nb_lignes) { char** pTableau_char; // Tableau de pointeur sur tableau de char int i; // Allocation mémoire du fichier if(nb_lignes > 0) { pTableau_char = malloc(nb_lignes * sizeof(char *)); if(pTableau_char == NULL) puts("Echec"); else { // Allocation mémoire des lignes du fichiers for(i=0;i<nb_lignes;i++) { pTableau_char[i] = malloc(LENGTH_MOT_MAX * sizeof(char)); if(pTableau_char[i] == NULL) puts("Echec"); } } } return pTableau_char; } /** * Copie du fichier en mémoire **/ char** charger_fichier(char** pTableau, FILE* fichier) { char buffer[LENGTH_MOT_MAX]; int i = 0; for(i=0; fgets(buffer, LENGTH_MOT_MAX, fichier) != NULL; i++) strcpy(pTableau[i], buffer); // Retour au début du fichier rewind(fichier); return pTableau; } /** * On trie le fichier en mémoire **/ char** fichier_trier(char** pTableau, FILE* fichier, int nb_lignes) { qsort(pTableau, nb_lignes, sizeof(*pTableau), compareString); return pTableau; } /** * On affiche le fichier trié **/ void afficher_tab(char** pTableau, int nb_lignes) { int i = 0; for(i=0;i<nb_lignes;i++) printf("%s", pTableau[i]); } /** * On libère la mémoire **/ void free_fichier_tab(char** pTableau, int nb_lignes) { int i = 0; for(i=0;i<nb_lignes;i++) { free(pTableau[i]); } free(pTableau); }
Valgrind m'indique que toute la mémoire n'ai pas libéré je me demande pourquoi.Code:
1
2
3
4 dico.c: In function alloc_fichier_tab: dico.c:166:32: erreur: unused parameter fichier [-Werror=unused-parameter] compilation terminated due to -Wfatal-errors. cc1: all warnings being treated as errors
Code:
1
2
3
4
5
6
7
8
9 ==4396== ==4396== HEAP SUMMARY: ==4396== in use at exit: 266 bytes in 8 blocks ==4396== total heap usage: 17 allocs, 9 frees, 1,100 bytes allocated ==4396== ==4396== 266 (56 direct, 210 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2 ==4396== at 0x4C2B3F8: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) ==4396== by 0x400F3C: alloc_fichier_tab (dico.c:174) ==4396== by 0x400B58: main (main.c:22)
Essaye d'être précis également dans l'origine des messages : ce que tu montres n'est pas un résultat de compilation, c'est le résultat de Valgrind. Ce n'est pas un compilateur mais un débogueur mémoire. Il vau mieux de ne pas confondre les outils pour mieux comprendre leurs rôles ;)
Bonjour,
Ce code est plutôt correct. Mais j'aurais préféré un prototype comme celui-ci : FILE *open_file(const char* fic, const char* mode). De plus, partant de l'hypothèse que ta fonction ne contient qu'une seule instruction, on peut dire qu'elle ne sert à rien mais ce n'est qu'un point de vue. ;)Code:
1
2
3
4 FILE *open_file(const char* fic, char* mode) { return fopen(fic, mode); }
Code vraissemblablement correct (du moins d'après le code source). Cependant, tu parcours ton fichier caractère par caractère, ce sera long et embettant pour le PC lorsque ton fichier sera trog gros.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 int nombre_lignes(FILE *fichier) { int nb_lignes = 0; int c; do{ c = fgetc(fichier); if (c == '\n') nb_lignes++; }while (c != EOF); rewind(fichier); return nb_lignes; }
Dans la fonction char** alloc_fichier_tab(FILE *fichier, int nb_lignes), pourquoi passer le nombre de ligne en paramètre ? On peut le calculer à partir dpremier argument (FILE* fichier) non ? De plus, tu écris :char** pTableau_char; // Tableau de pointeur sur tableau de char. Relis un peu le commentaire. ;) Le reste du code semble plutôt correct.
Passons à la suite.
Le code de cette fonction, à mon humble avis, n'est pas bon. Souviens toi du rôle de ta variable LENGTH_MOT_MAX et regardes ensuite ce que tu fais aux lignes 10 et 11. LENGTH_MOT_MAX est le nombre maximal de mots par ligne. Tu dois donc faire quelques réglages pour déterminer le nombre exact de mots pour chaque ligne avant de faire le strcopy de la ligne 11.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 /** * Copie du fichier en mémoire **/ char** charger_fichier(char** pTableau, FILE* fichier) { char buffer[LENGTH_MOT_MAX]; int i = 0; for(i=0; fgets(buffer, LENGTH_MOT_MAX, fichier) != NULL; i++) strcpy(pTableau[i], buffer); // Retour au début du fichier rewind(fichier); return pTableau; }
Pour le reste, il n'y a vraiment rien de compliqué. On fera les modifications ensemble, une fois que tout ce qui précède sera bien fait.
Remarque : Ce que je vais dire pourrait te mettre mal mais s'il te plaît, take it easy. J'ai l'impression que tu te lances dans un projet (la création d'une bibliothèque de fonctions qui gère un dictionnaire) mais en réalité tu ne sais pas trop ce que tu veux faire. Penses-y encore. On ne crée pas des fonctions pour le plaisir d'en créer. Non, non et non. Un programme est avant tout une suite coordonnée de variables, d'instructions, de fonctions, etc. S'il te plaît reprends tout à zéro. C'est qu'en même étrange que tu te retrouves avec tant de lignes de codes qui, malheureusement, ne font pas ce que tu attends d'elles.
Essayes de bien coordonner tes idées et ensuite on verra. Sur ce, bon courage ! :)
J'ai l'impression qu'il n'y a que toi ici qui parle de bibliothèque.Citation:
J'ai l'impression que tu te lances dans un projet (la création d'une bibliothèque de fonctions qui gère un dictionnaire)
Et je ne pense qu'il faille tout reprendre depuis zéro. Le code fonctionne, non ? En revanche, il y a des améliorations possibles. Un ou deux const en effet. Pourquoi changer la méthode de comptage des lignes (avant faite avec fgets()) ? Pour ce qui est du problème de libération mémoire, Dr Memory (genre de Valgrind pour Windows) ne me dit rien et je ne vois pas de problème dans le code (mais la libération de mémoire à deux niveaux de pointeurs, ça me perd un peu...).
Humm ... Bktero. ;) Les algorithmes qu'il utilise ne sont pas très corrects, à mon avis (et j'en avais déjà un peu parlé). Et quand je parle de bibliothèque, il s'agit en effet d'un amalgame : je me suis trompé. ;) Par ailleurs, cela m'étonnerait que son tri fonctionne (j'avais fait quelques remarques).
Par ailleurs, il n'est pas impossible que ce soit moi qui me trompe. Et d'ailleurs, pas besoin de tant de fonctions pour charger un dictionnaire. La dernière fois que je l'ai fait, il m'a fallu seulement une fonction :
Courage !Code:
1
2 bool load_dict_mmap(const char *pathname, dict *d) ;
@leMédaillon : Le const je l'ai rajouté chez moi oublié de le retranscrire ici.
Sinon je ne comprends pas vraiment ce que tu veux dire par "pourquoi passer le nombre de ligne en paramètre ? On peut le calculer à partir du premier argument (FILE* fichier.
Pour le reste je débute en C donc j'essaie de me faire mes propres exercices pour m'améliorer.
Mon tri marche bien après plusieurs essaie sa fonctionne correctement.
Merci pour votre aide en tout, cela à été utile et ne peux me faire que progresser.
Parfait : je suis content que tu t'en sois sorti presque tout seul. Sinon, je parlais de la fonction suivante :
Pourquoi passer le nombre de lignes en paramètre s'il peut être calculé à partir du premier argument ? ;)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 char** alloc_fichier_tab(FILE *fichier, int nb_lignes) { char** pTableau_char; // Tableau de pointeur sur tableau de char int i; // Allocation mémoire du fichier if(nb_lignes > 0) { pTableau_char = malloc(nb_lignes * sizeof(char *)); if(pTableau_char == NULL) puts("Echec"); else { // Allocation mémoire des lignes du fichiers for(i=0;i<nb_lignes;i++) { pTableau_char[i] = malloc(LENGTH_MOT_MAX * sizeof(char)); if(pTableau_char[i] == NULL) puts("Echec"); } } } return pTableau_char; }
Pour éviter de recalculer à chaque fois le nombre de lignes de mon fichier j'ai préférer les calculer une fois lors de l'appel à la fonction nombre_lignes dans mon main et de passer le résultat au fonction qui en avais besoins.
Que me conseillez-vous pour continuer mon apprentissage ?
On ne passe un paramètre à une fonction que lorsque celle-ci en a vraiment besoin. C'est comme si tu voulais créer un MMORPG et que tu vas recruter un forgeron. :marteau: (Oui oui je sais c'est exagéré). Par contre, la raison que tu donnes n'est pas vraiment valable, vu que tu ne réutilises pas ta fonction maintes fois (ou bien je me trompe ?). :)
Je l'utilise 5, 6 fois certes c'est pas énormes mais je prends en compte ta remarque.
J'ai supprimé ma fonction file_open(...), c'est qu'elle n'était pas de très grande utilité.
C'est relatif après tout. Et d'une certaine façon, on ne peut guère te condamner parce que tu essayes de factoriser du code tu sais. :) Enfin, tu nous a signalé tout à l'heure que ton tri fonctionnait. Tu as essayé sur un fichier de quelle taille ? (Je suis en effet un peu fatigué et je pourrais pas tester tout ça). Une bonne sieste nous fera d'ailleurs à tous du bien parce que sinon, voici ce qui risque d'arriver : :bug:
J'ai testé sur un fichier de 78000 mots environs et sa marche :D
Super alors ! :yaisse2:
Félicitation et bonne après-midi à tous !
Merci à tous pour votre aide ;).
Résolu.