Forums Rue-Montgallet.com
Rue-Montgallet.comRue-Hardware.comRue-Occasion.comRue-DVD.comRue-Jeuxvideo.comRue-AudioVideo.comRue-Telephone.comForums
S'inscrire | S'identifier |
| Recherche avancée | Aide
 
 

Il y a 44 utilisateurs connus et inconnus. Pour voir la liste des connectés connus, cliquez ici

 Mot :   Pseudo :  
 
Bas de page
Auteur
 Sujet :

[Resolu] Transformation d'un fichier en liste doublement chainée

 
n°19133
Beamo
Profil : Jeune recrue
Posté le 30-12-2007 à 16:33:23  profilanswer
 

Bonjour,
 
Je cherche à transformer un fichier en liste doublement chainée.
Mon fichier contient un mot de moins de 32 caractères par ligne. Et je veux que chaque ligne soit un maillon de ma chaîne.
 

Code :
  1. #include<stdlib.h>
  2. #include<stdio.h>
  3. #include<string.h>
  4. #include<math.h>
  5. typedef struct liste_ {
  6.     char *mot;
  7.     struct liste_ *precedant;
  8.     struct liste_ *suivant;
  9. }
  10. liste;
  11. liste *initliste (char *mot) {
  12.     liste *L;
  13.     L = (liste*)malloc(sizeof(liste));
  14.     L->mot = mot;
  15.     L->precedant = NULL;
  16.     L->suivant = NULL;
  17.     return L;
  18. }
  19. void addendliste(char *mot, liste *L) {
  20.     liste *T, *tmp;
  21.     T = (liste*)malloc(sizeof(liste));
  22.     tmp = (liste*)malloc(sizeof(liste));
  23.     tmp = L;
  24.     while (tmp->suivant != NULL)
  25.         tmp = tmp->suivant;
  26.     T->mot = mot;
  27.     T->precedant = tmp;
  28.     T->suivant = NULL;
  29.     tmp->suivant = T;
  30. }
  31. int main() {
  32.     liste *L;
  33.     int length = 1;
  34.     char mot[32];
  35.     char tmp[32];
  36.     FILE *lect;
  37. /* transformation du dico en liste chainee */
  38.     lect = fopen ("fichier.txt", "r" );
  39.     fgets(mot, 32, lect);
  40.     strcpy (tmp, mot);
  41.     L = initliste(tmp);
  42.     while (fgets(mot, 32, lect)!= NULL) {
  43.         /*strcpy (tmp2, mot);*/
  44.         addendliste(mot, L);
  45.         length++;
  46.     }
  47.     fclose (lect);
  48.     printf("L: %sL->suivant: %s", L->mot, L->suivant->mot);
  49.     return 0;
  50. }


 
Mon gros soucis est que à chaque fois que je fais un fgets il écrase un des maillons (car cela pointe vers la même adresse...). J'ai essayé d'utiliser un char xxx[32] en tant que buffeur mais cela ne m'a pas aidé...
 
Des idées ? :)
 
Merci,
Beamo


Message édité par Beamo le 07-01-2008 à 11:22:24
n°19134
cmoila
Profil : Membre
Posté le 01-01-2008 à 21:04:04  profilanswer
 

Salut,
Il y a une contradiction entre ta phrase " je veux que chaque ligne soit un maillon de ma chaîne " et la structure que tu définis en l’appelant "liste". Ta structure n’est pas la liste, mais simplement un élément (maillon) de la liste (chaine).  
C’est ce qui t'as fait te prendre les pieds dans le tapis, car tu n’as pas su où tu devais stocker les mots. Et du coup tu les as stocké nulle part, d’où le pb.  
Par suite, il y a une ambigüité dans ta fonction initliste(), et une grave erreur de fuite mémoire dans addendlist().
 
Les mots que tu lis dans le fichier doivent bien être stockés quelques part. Or toi, tu ne stockes dans ton maillon de chaine qu’un pointeur. Mais il pointe vers quoi ?
Le mieux c’est de les mettre dans les éléments(maillons), d’autant que tu as choisi de faire une allocation mémoire par malloc() pour chaque élément.

Code :
  1. const int  MaxLongMot = 32;
  2. typedef struct ElemtListe_ {
  3.     char                  mot[MaxLongMot];
  4.     struct ElemtListe_   *precedant;
  5.     struct ElemtListe_   *suivant;
  6. }
  7. SElemtListe;


J’ai commencé par créer une constante globale pour la longueur maxi du mot. Ce qui permet d’éviter des erreurs ailleurs dans le prog si l’on change sa valeur. Et "mot" est un tableau de char.  
Note que je mets un "S" devant le nom de mes structures pour me rappeler que c’est un type de données et pas une variable.
 
Ensuite je crée une structure pour la liste elle-même. Elle ne contient que 2 choses pour l’instant, mais peut être (sans doute) au fur et a mesure que le prog grandira elle pourra s’étoffer.

Code :
  1. typedef struct {
  2.     SElemtListe  *Elemt1;   // pointeur sur le 1er élément de la liste, Si NULL, la liste est vide
  3.     int           nbElemt;  // c  ton "length" que je mets là   
  4. }
  5. SListe;


 
Ma fonction  InitListe() est différente de la tienne qui n’était qu’un cas particulier de la fonction AddEndListe().
A propos de cet identifiant, je me permets de te dire que mélanger la très belle langue française avec  l’horrible dialecte rosbif, n’est pas conseillé par l’Académie des Arts et Belles-Lettres.

Code :
  1. void InitListe( SListe *liste )  {
  2.     if  ( !liste )  return;    // remarque ce petit test de sécurité, qui peut etre un jour ne sera pas inutile  
  3.     liste->Elemt1 = NULL;
  4.     liste->nbElemt = 0;   
  5. }


 
La fonction main() devient plus claire :

Code :
  1. int main() {
  2.    
  3.     FILE   *lect;
  4.     SListe  liste;                           // une liste est crée dans la pile
  5.     char    mot[MaxLongMot];
  6. /* transformation du dico en liste chainee */
  7.     InitListe(&liste);
  8.     lect = fopen("fichier.txt", "r" );   
  9.  
  10.     while ( fgets(mot, MaxLongMot, lect) ) {
  11.        
  12.         AjouteMotFinListe(mot,&liste);      // stocke le mot en fin de liste, et fait l'incrémentation du nb d'éléments de la liste   
  13.     }
  14.     fclose(lect);
  15.     return 0;
  16. }


 
Il ne te reste plus qu'a faire une fonction AjouteMotFinListe() qui fonctionne meme pour le premier élément de la liste. Note que cette fonction devra demander par malloc() de la memoire pour l'élément en question. Et donc il te faudra tot ou tard ecrire une fonction SupprimeMotListe() qui appelera free() pour libérer cette mémoire. La règle de programmation étant, qu'à chaque malloc(), il faut son free().
 
 
 
Et bien sûr le plus important : Bonne Année 2008, à tous les pros et apprentis programmeurs C/C++ qui passent par ce forum.


Message édité par cmoila le 02-01-2008 à 12:57:25
n°19138
Beamo
Profil : Jeune recrue
Posté le 07-01-2008 à 11:22:03  profilanswer
 

Bonjour,
 
Merci pour ton aide.
 
Je ne suis pas pour créer une structure pour la liste et une pour les maillons.
 
J'ai pu résoudre mon problème en utilisant un strdup()
(malloc (strlength) + strcpy) de ma chaine de caractère ce qui me permet d'éviter l'écrasement à chaque fgets.
 
Beamo

n°19142
cmoila
Profil : Membre
Posté le 08-01-2008 à 18:30:25  profilanswer
 

Ben j'espère que t'as regardé la gestion mémoire. parce que strdup() c'est plus piegeant qu'utile. Vaut bien mieux mettre toi meme le malloc(). Ensuite tu as donc mis 2 appels malloc() par maillon créé donc bonjour la fragmentation du tas si la chaine est souvent modifiée.
 
Pour savoir s'il faut ou non une structure liste et une structure élement, tu peux déja te demander si tu fais la différence entre un "char" et une chaine de char c'est a dire ce qui est appelé une "str" dans la bibliothèque C standard.
Sache qu'en C++, donc programmation objet, j'aurais pas créé 2 structures mais 4 classes ! 2 classes de base pour la gestion de la liste et ses éléments, et dérivé 2 classes, une pour les mots, et une pour la liste de mots. Le but étant la simplification et la réutilisation du code.
 

n°19144
Beamo
Profil : Jeune recrue
Posté le 09-01-2008 à 17:18:12  profilanswer
 

Alors oui j'ai en fait utilisé un malloc et un strcpy à la place du strdup.
Et j'ai retiré un des mallocs lors de ma création de maillon =)
 
Encore merci pour ton aide
 
Beamo


Message édité par Beamo le 09-01-2008 à 17:18:48
n°19145
cmoila
Profil : Membre
Posté le 09-01-2008 à 21:42:05  profilanswer
 

Je pense que c'est bien mieux que tu aies utilisé directement malloc() puis strcpy(), car au fur et à mesure que le programme grandira, se posera la question de la gestion memoire. Et une recherche dans le listing des malloc(), est plus simple et évidente que srtdup() et autre chose du meme genre. (ce genre de "choses" n'existent plus en C++, où on est obligé d'utiliser le mot clé "new" pour avoir de la memoire).
 
Effectivement le 2ème malloc() de ta creation de maillon etait une pure fuite de mémoire, car il ne servait à rien et son pointeur était immédiatement perdu. C'est la raison pour laquelle je n'ai pas corrigé cette fonction. Mais comme tu en as rajouté un, tu as toujours 2 malloc().
Proverbe de développeur : "Deux malloc de suite, c'est au moins un malloc de trop !"  
Dans cette fonction de création de maillon, tu fais (si j'ai bien compris) 2 malloc() : Un pour les pointeurs de maillon chaine (suivant, precedent, mot) et un pour caser le mot. Réflechis à une méthode pour avoir qu'un seul malloc(). (Pour en avoir zéro ou presque zéro, ca va être beaucoup plus compliqué).  
 
Autre chose : Es tu vraiment sûr de ta stratégie algorithmique dans ta recherche du dernier maillon de la chaîne ?

n°19146
Beamo
Profil : Jeune recrue
Posté le 10-01-2008 à 09:46:06  profilanswer
 

Comme je te disai, j'ai un peu revu ma fonction addendliste :
 

Code :
  1. liste *ajoutfinliste(char *mot, liste *Fin) {
  2.         liste *T;
  3.         T = (liste*)malloc(sizeof(liste));
  4.         T->mot = mot;
  5.         T->precedant = Fin;
  6.         T->suivant = NULL;
  7.         Fin->suivant = T;
  8.         return T;
  9. }


 
Comme il y avait plus de 160000 mots à stoquer, j'y gagne en tps de rajouter une variable pour la fin de la liste.
 
Beamo


Message édité par Beamo le 10-01-2008 à 09:46:25
n°19148
cmoila
Profil : Membre
Posté le 10-01-2008 à 19:27:19  profilanswer
 

Ah, je vois que tu as compris que de parcourir toute la liste pour trouver la fin, n'est pas très efficace. Surtout avec des milliers de maillons.
Du coup, tu dois creer un pointeur de fin de liste, ce qui te fait une nouvelle variable qui caractérise l'état de la liste dans son ensemble et que je mettrais dans ma structure SListe, et que toi tu te contente de mettre en variable de main() ce qui alourdi encore cette fonction.
 
Ensuite, un certain nombre d'actions à faire à chaque ajout de maillon, ne sont pas misent dans la fonction ajoutefinliste() mais en dehors : L'incrementation du nb de mot, et la mise à jour du pointeur fin, et surtout la réservation memoire pour caser le mot !
Imagine que tu aies dans un autre endroit du prog besoin d'ajouter un maillon. Tu recopies cette partie ?
Et tu sembles avoir gardé ta fonction intliste() qui n'est qu'un cas particulier de ajoutefinliste().
 
Pour que tu te rendes compte, voila, dans mon style le meme code que toi (memes fonctionnalités et algo) :
 

Code :
  1. const int  MaxLongMot = 32;
  2. typedef struct ElemtListe_ {
  3.     char                 *Mot;     // je remets un pointeur pour reservation memoire séparée
  4.     struct ElemtListe_   *precedant;
  5.     struct ElemtListe_   *suivant;
  6. }
  7. SElemtListe;
  8. typedef struct {
  9.     SElemtListe  *Elemt1;     // pointeur sur le 1er élément de la liste, NULL si liste vide
  10.     SElemtListe  *ElemtFin;  //  pointeur vers le dernier
  11.     int           nbElemt;   // c  ton "length" que je mets là   
  12. }
  13. SListe;
  14. void InitListe( SListe *liste ) 
  15. {
  16.     if  ( !liste )  return;    // test de sécurité   
  17.    
  18.     liste->Elemt1 = liste->ElemtFin = NULL;
  19.     liste->nbElemt = 0; 
  20. }
  21. int main()
  22. {
  23.     FILE   *lect;
  24.     SListe  liste;                // une liste est crée dans la pile
  25.     char    motTmp[MaxLongMot];     //  stockage temporaire du mot
  26.     InitListe(&liste);
  27.     lect = fopen("fichier.txt", "r" ); 
  28.     while ( fgets(motTmp, MaxLongMot, lect) ) {
  29.         AjouteMotFinListe(motTmp, &liste);   // stocke le mot en fin de liste, et maj des variables
  30.     }
  31.     fclose(lect);
  32.     printf("%d mots ont été lu et stocké.\n", liste.nbElemt);
  33.     return 0;
  34. }
  35. int  AjouteMotFinListe(char *mot, SListe *liste)
  36. {
  37.     if ( !mot || !liste )  return 0;   // test
  38.    
  39.     SElemtListe *nouvElemt = (SElemtListe*)malloc(sizeof(SElemtListe));
  40.     if ( !nouvElemt )  return 0;
  41.     char *nouvMot = (char*)malloc(strlen(mot)+1);
  42.     if ( !nouvMot )  return 0;
  43.     if ( liste->nbElemt == 0 ) {   // cas du 1er élément
  44.         liste->Elemt1 = nouvElemt;
  45.         nouvElemt->precedant = nouvElemt->suivant = NULL ;
  46.     }
  47.     else {          // cas général
  48.         liste->ElemtFin->suivant = nouvElemt;  // Chainage
  49.         nouvElemt->precedant = liste->ElemtFin;
  50.         nouvElemt->suivant = NULL;
  51.     }
  52.  
  53.     nouvElemt->Mot = strcpy(nouvMot, mot);
  54.     liste->ElemtFin = nouvElemt;
  55.     liste->nbElemt++;
  56.     return 1;
  57. }


 
Il y a donc bien 2 malloc par ajout de mot, donc 320000 ! C'est un sacré pb meme en divisant par 2 en faisant une allocation globale pour le maillon et son mot.


Message édité par cmoila le 10-01-2008 à 19:37:16

Aller à :
Ajouter une réponse