IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Liste chainée et fichier texte


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Inscrit en
    Octobre 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2006
    Messages : 233
    Par défaut Liste chainée et fichier texte
    Bonjour,

    Voila: j'ai d'un part un fichier texte (*.txt) dont je lit tout les carcatère et de l'autre une liste chainé composé donc de structure avec les élément suivant:

    code ascii de la lettre (type char)
    frequence de la lettre dans le texte (type int)
    pointeur vers prochaine structure (type *struct)

    A chaque caractère, je recherche si la lettre existe déjà dans la liste chainé et incrémente la valeur de "fréquence" de la structure correspondante. Si ce n'est pas le cas,on ajoute un nouvelle élément en début de liste. Mais lorsque je veux lire le premier élément (genre la fréquence du premier carcatère par exemple, windows me renvoie une erreur)


    Peut être est-ce mal codé ?

    Je joint donc le code source en espérant que vous trouviez la solution!

    Merci d'avance!


    déclaration structure et pointeur sur structure
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //définition des types
    typedef struct lettre_ lettre;
    typedef lettre *ptr_lettre;
    typedef FILE * fichier;
     
    struct lettre_
    {
    char code_ascii;        
    int frequence;        
    ptr_lettre suivant;
    };
    Chaque caractère est stocké dans un char element, puis j'exécute un"ajouter_lettre(element,L);" avec L de type ptr_lettre

    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
    void ajouter_lettre(char ascii,ptr_lettre actuel)
    {
        ptr_lettre inter=NULL;
     
        if(actuel==NULL) //ajout nouvelle lettre
        {
            inter=(ptr_lettre)malloc(sizeof(lettre));
            inter->code_ascii=ascii;
            inter->frequence=1;
            inter->suivant=actuel;
            actuel=inter;
        }
        else
        { 
               if((actuel->code_ascii)==ascii) 
                     (actuel->frequence)++;
               else 
                    ajouter_lettre(ascii,actuel->suivant);
        }
    }
    La structure de tête a été initialisé à NULL évidement

  2. #2
    Membre éclairé Avatar de richard_sraing
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Avril 2005
    Messages
    483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Responsable de service informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Avril 2005
    Messages : 483
    Par défaut
    Si je ne me trompe pas, lorsque tu vérifie

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if(actuel==NULL) //ajout nouvelle lettre
    Tu vérifie juste si tu as déjà un élément, non? Si actuel == NULL, alors tu n'a encore aucun élément dans ta liste, je me trompe? Donc dès que tu aura écrit un élément dedans, tu ne passera plus jamais dedans.

    Il se peut que je me trompe complètement, si tel est le cas, je m'en excuse.

  3. #3
    Membre éclairé
    Inscrit en
    Octobre 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2006
    Messages : 233
    Par défaut suite
    Merci de ta réponse!

    En fait le dernier élément de la liste voit la valeur de struct *suivant NULL et je teste donc si on n'est pas au dernier élément. Donc je sé pas si ça vien de là?

    Si quelqu'un a une idée ?merci

  4. #4
    Membre émérite Avatar de stephl
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2007
    Messages
    643
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2007
    Messages : 643
    Par défaut
    Lorsque vous faites:
    dans votre fonction d'ajout, vous modifiez la variable locale (le paramètre) de la fonction, mais en aucun cas le pointeur que vous avez passé en paramètre dans la fonction appelante. Il faut utiliser un pointeur de pointeur ou une valeur de retour pour votre fonction d'ajout.

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Visiblement, tu as voulu la jouer en fonction récursive, et le problème vient sans doute de là...

    Je peux te proposer deux solutions différentes:
    • garder la fonction récursive, mais modifier le type de retour de celles ci, pour avoir un prototype du genre de
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      ptr_lettre ajouter_lettre(char ascii,ptr_lettre actuel);
      et modifier uniquement la ligne
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      ajouter_lettre(ascii,actuel->suivant);
      en
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      actuel->suivant=ajouter_lettre(ascii,actuel->suivant);
      tout en n'oubliant pas un
      juste avant la dernière accolade fermante
    • utiliser, tout simplement, une boucle itérative, au lieu d'une fonction récursive
      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
       
      /* renvoie un ptr_lettre sur le premier élément de la chaine
          pour le cas où la chaine de départ est vide à la base
       */
      ptr_lettre ajouter_lettre(char ascii,ptr_lettre debut)
      {
          /* La première chose à faire, c'est de s'assurer que a chaine
              n'est pas vide
           */
          if(debut==NULL)
          {
              /* Si elle est vide, on crée le premier élément */
              debut=malloc(sizeof(*debut));
              if(debut!=NULL)
              {
                  debut->suivant=NULL;
                  debut->code_ascii=ascii;
                  debut->frequence=1;
              }
              /* il faudrait, idéalement prévoir le cas où l'allocation a éhcoué ;) */
          }
          else
          {
              /* sinon, on parcoure la liste à la recherche de l'élément qui nous
               *  intéresse
               * Pour cela, il nous faut un "flag" trouvé et un pointeur temporaire
               */
              int trouve=0;
              ptr_lettre actuel=debut;
              do
              {
                  /* C'est peut etre le caractère qu'on cherche
                   */
                  if(actuel->code_ascii==ascii)
                  {
                      actuel->frequence++;
                      trouve=1;
                  }
                  /* On est peut etre au dernier élément sans avoir trouvé
                   * si c'est le cas, il faut rajouter un nouvel élément
                   */
                  if(actuel->suivant==NULL && trouve==0)
                  {
                      ptr_lettre temp=malloc(sizeof(*temp));
                      if(temp!=NULL)
                      {
                          temp->suivant=NULL;
                          temp->code_ascii=ascii;
                          temp->frequence=1;
                          actuel->suivant=temp;
                      }
                      /* il faudrait, idéalement, prévoir le cas où l'allocation a
                       * échoué ;)
                       */
                          trouve=1;
                  }
                  actuel=actuel->suivant;
              }while(trouve!=1);
          }
          /* on renvoie le premier élément de la liste */
          return debut;
      }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre chevronné
    Avatar de Foobar1329
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    283
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France, Finistère (Bretagne)

    Informations forums :
    Inscription : Juin 2006
    Messages : 283
    Par défaut
    Hello,

    Citation Envoyé par kuja2053
    Bonjour,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //définition des types
    typedef struct lettre_ lettre;
    typedef lettre *ptr_lettre;
    typedef FILE * fichier;
     
    struct lettre_
    {
    char code_ascii;        
    int frequence;        
    ptr_lettre suivant;
    };
    Ce n'est pas "mal" codé mais il y a des alias de type à bannir, ceux qui cachent le fait qu'une variable a un type pointeur vers quelquechose. Il faut commencer par supprimer les affreux typedefs ptr_lettre et fichier.

    Ensuite, j'ai beaucoup de mal à voir l'intérêt de la récursion pour ta problématique. En partant de ton raisonnement initial avec pour type une liste chaînée, l'algorithme est simple :
    Si la lettre lue existe dans la liste de lettres, Alors,
    incrémenter le compteur de la lettre
    Sinon
    ajouter la lettre à la liste de lettres avec un compteur initialisé à 1.

    La solution par liste chaînée pour cette problématique est très encombrante, surtout si cela ne concerne que des caractères ASCII.

    Avec une liste basique :

    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
     
    #include <stdlib.h>
    #include <stdio.h>
    #include <ctype.h>
     
    typedef struct lettre lettre;
     
    struct lettre
    {
       int code_ascii;        
       int frequence;        
       lettre * suivant;
    };
     
    /* Renvoie !=0 si la lettre existe dans la liste, 0 sinon. La position de la
       structure correspondante dans la liste est stockée dans position */
    int lettreExiste(lettre * listeLettres, const char ascii, int * position) {
     
       int existe = 0; 
       int cpt = 0;
       if (listeLettres) {
          lettre * noeudParcours = listeLettres;
          while (noeudParcours != NULL) {
             if (noeudParcours->code_ascii == ascii) {
               existe = 1;
               if (position) {
                  *position = cpt;
               } 
               break;
             }
             noeudParcours = noeudParcours->suivant;
             ++cpt;
          }
       }
       return existe; 
    }
     
    /* Ajoute une lettre dans la liste et renvoie la nouvelle lettre créée */
    lettre * ajouter_lettre(lettre * listeLettres, const char ascii) 
    {  
         lettre * nouvelleLettre = NULL;
         nouvelleLettre = malloc(sizeof(*nouvelleLettre));
         if (nouvelleLettre) {
            nouvelleLettre->suivant = NULL;
            nouvelleLettre->code_ascii = ascii; 
            nouvelleLettre->frequence = 1; 
            listeLettres->suivant = nouvelleLettre;
         }
         return nouvelleLettre;
    }
     
    /* Retourne la lettre située à la position pos dans la liste */
    lettre * lettreDeLaPosition(lettre * listeLettres, const int pos) 
    {  
         int cpt=0;
         lettre * lettre = listeLettres;
         while(cpt < pos) {
           lettre = lettre->suivant;
           ++cpt;
         }
     
         return lettre;
    }
     
    int main(int argc, char ** argv) {
     
      lettre lettreBidonDebutListe = { EOF, 0, NULL };
      lettre * noeudListeLettre = NULL, 
             * noeudListeParcours = NULL, 
             * noeudAdetruire = NULL;
     
      FILE * file = NULL;
      int ch = EOF, position=-1;
     
      if (argc != 2)  {
        fprintf(stderr,"Bad number of arguments.\n");
        fprintf(stderr,"Usage: cptascii <file>\n");
        exit(EXIT_FAILURE);
      }
     
      file = fopen(argv[1], "r");
      if (!file) {
        fprintf(stderr,"Error: cannot open file %s\n", argv[1]);
        exit(EXIT_FAILURE);
      }
     
      /* traitement */
      noeudListeLettre = &lettreBidonDebutListe;
      while ((ch=fgetc(file)) != EOF) {
         if (isalnum((unsigned)ch)) {
            if (!lettreExiste(&lettreBidonDebutListe, ch, NULL)) {
                noeudListeLettre = ajouter_lettre(noeudListeLettre, ch);
            }
            else if (lettreExiste(&lettreBidonDebutListe, ch, &position)) {
                lettre * l = lettreDeLaPosition(&lettreBidonDebutListe, position);
                l->frequence++;
            }
         }
      }
     
      /* affichage résultat */  
      for (noeudListeParcours=lettreBidonDebutListe.suivant; 
             noeudListeParcours != NULL ; 
             noeudListeParcours=noeudListeParcours->suivant ) 
      {
        printf("%c:\t%d\n", noeudListeParcours->code_ascii, noeudListeParcours->frequence);
      }
     
      /* libération mémoire */
      while (lettreBidonDebutListe.suivant != NULL) 
      {
         noeudAdetruire = lettreBidonDebutListe.suivant;
         lettreBidonDebutListe.suivant = lettreBidonDebutListe.suivant->suivant;
         free(noeudAdetruire);
      }  
     
      fclose(file);
     
      return 0;
     
    }
    Une solution bien plus simple avec un tableau :

    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
    #include <ctype.h>
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(int argc, char ** argv) {
     
      int ch = EOF; 
      int ascii_letters[128] = { 0 };
      FILE * file = NULL;
     
      if (argc != 2)  {
        fprintf(stderr,"Bad number of arguments.\n");
        fprintf(stderr,"Usage: cptascii <file>\n");
        exit(EXIT_FAILURE);
      }
     
      file = fopen(argv[1], "r");
      if (!file) {
        fprintf(stderr,"Error: cannot open file %s\n", argv[1]);
        exit(EXIT_FAILURE);
      }
     
      while ((ch=fgetc(file)) != EOF) {
        if (isalnum((unsigned)ch)) {
          ascii_letters[ch]++;
        }
      }
     
      for (ch=0; ch<128; ++ch) {
        if (ascii_letters[ch] > 0) {
          printf("%c:\t%d\n", ch, ascii_letters[ch]);
        }
      }
     
      fclose(file);
     
      return 0;
     
    }
    A+

  7. #7
    Membre éclairé
    Inscrit en
    Octobre 2006
    Messages
    233
    Détails du profil
    Informations personnelles :
    Âge : 40

    Informations forums :
    Inscription : Octobre 2006
    Messages : 233
    Par défaut suite
    Je répond avec bqs bqs de retard mais ne vous inquiété pas vos commentaires m'ont servis et je vous en remercie @+

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 8
    Dernier message: 21/01/2014, 19h21
  2. [Mac] Modif en chaine sur fichiers textes
    Par klang dans le forum AppleScript
    Réponses: 2
    Dernier message: 09/03/2012, 16h14
  3. Extraire liste d'un fichier texte.
    Par JLtaratata dans le forum VBScript
    Réponses: 2
    Dernier message: 13/01/2012, 21h36
  4. fichier texte et Liste Chainée
    Par alexglvr dans le forum Débuter
    Réponses: 20
    Dernier message: 05/11/2008, 11h34
  5. Problème listes chaînées et fichier texte
    Par khayyam dans le forum Pascal
    Réponses: 2
    Dernier message: 24/01/2007, 20h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo