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 :

Inverser 2 mots dans un fichier


Sujet :

C

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 8
    Par défaut Inverser 2 mots dans un fichier
    Bonsoir

    J'ai un exercice qui consite à écrire une fonction qui prend en paramètre un fichier texte (qui contient sur chaque ligne un nom et un prénom) et qui doit inverser sur chaque ligne le nom et le prénom et en plus de numeroté chaque ligne.

    Le fichier se présente de cette manière:


    ....
    nom1 prenom1
    nom2 prenom2
    etc...

    Le fichier final doit être:
    ...
    1 prenom1 nom1
    2 prenom2 nom2
    etc...

    La seule contrainte à cette exercice est que je dois utilisée les fonctions fseek et ftell.

    J'ai commencé à écrire ma fonction mais elle ne compile pas :/

    code:
    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
    #include <stdio.h>
    #include <stdlib.h>
     
    void inverse (char *filename);
    int main () {
     
      inverse ("tp");
     
      return 0;
    }
     
     
     
    void inverse (char *filename) { 
      FILE *fp=fopen (filename, "r+");
      rewind (fp);
      int i=0;
      char s[1000];
      char nom [20];
      char prenom [20];
      long pos;
      while (!feof (fp)) {
        pos = ftell (fp);
        i++;
        fgets (s, 1000, fp);
        sscanf (s, "%s %s\n" ,nom ,prenom);
        fseek (fp, pos, SEEK_SET);
        fprintf (fp, "%d %s %s\n", i, prenom, nom);
        s[1000]= '\0';
        fgets (s, 1000, fp);
        //fseek (fp, 0L, SEEK_CUR);
        if (i==2)
          break;
      }
      //rewind (fp);
      fclose (fp);
    }
    Merci d'avance pour vos solutions

  2. #2
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    Pour commencer, ta fonction ne prend pas fichier texte, mais une chaine de caractère,
    ensuite, feof() ne fait pas ce que tu crois : http://c.developpez.com/faq/?page=es_general#ES_feof

    Enfin, la fonction fseek() souffre de grosses limitations:

    7.19.9.2 The fseek function
    Synopsis
    1 #include <stdio.h>
    int fseek(FILE *stream, long int offset, int whence);
    Description
    2 The fseek function sets the file position indicator for the stream pointed to by stream.
    If a read or write error occurs, the error indicator for the stream is set and fseek fails.
    3 Forabinary stream, the newposition, measured in characters from the beginning of the
    file, is obtained by adding offset to the position specified by whence.The specified
    position is the beginning of the file if whence is SEEK_SET,the current value of the file
    position indicator if SEEK_CUR,orend-of-file if SEEK_END.Abinary stream need not
    meaningfully support fseek calls with a whence value of SEEK_END.
    4 Foratextstream, either offset shall be zero, or offset shall be a value returned by
    an earlier successful call to the ftell function on a stream associated with the same file
    and whence shall be SEEK_SET.
    5 After determining the newposition, a successful call to the fseek function undoes any
    effects of the ungetc function on the stream, clears the end-of-file indicator for the
    stream, and then establishes the newposition. After asuccessful fseek call, the next
    operation on an update stream may be either input or output.
    Returns
    6 The fseek function returns nonzero only for a request that cannot be satisfied.

  3. #3
    Membre Expert
    Avatar de nbenbourahla
    Homme Profil pro
    Inscrit en
    Juin 2009
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2009
    Messages : 41
    Par défaut
    Bonjour

    Vu que sur chaque ligne ya le nom et le prénom dont la taille est variable, ce que je te conseillerai :

    - faire un petit getline afin de récupérer toute la ligne quelques soit sa taille
    - découper la ligne selon un délimiteur dans ton cas un espace (comme sa tu as le nom et le prénom) la fonction existe mais je me rappel plus du nom
    - fait vraiment gaffe en utilisant fseek (http://www.linux-kheops.com/doc/man/...3/fseek.3.html)
    - http://linux-france.unixtech.be/arti...3/ftell-3.html
    - Pour détecter la fin du fichier regarde du coté de EOF
    - evite sscanf et fprintf tant que possible (regarde du coté de read, fread, twrite, write)

    de rien
    Bonne chance

  4. #4
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    J'ai commencé à écrire ma fonction mais elle ne compile pas :/
    Bizarre. Quelles sont les erreurs signalées par le compilateur ? Je ne vois guère, si ton compilateur est Ansi, que le mélange des déclarations de variables et du code exécutable (dans ce cas, déplacer rewind() plus bas)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     ....
     FILE *fp=fopen (filename, "r+");
      rewind (fp);
      int i=0;
      char s[1000];....
    Par contre, ceci est faux (et inutile)
    L'indice de s[] doit être compris entre 0 et 999 inclus.

    Je suis très sceptique sur la possibilité de faire ce que tu veux : tu écris plus que ce que tu lis et ce faisant, tu vas écrabouiller la suite du fichier.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        sscanf (s, "%s %s\n" ,nom ,prenom);
    ....
        fprintf (fp, "%d %s %s\n", i, prenom, nom);

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 8
    Par défaut
    Bonjour à tous et merci pour vos réponse rapide.


    Alors @ nicolas.sitbon:
    Pour commencer, ta fonction ne prend pas fichier texte, mais une chaine de caractère,
    Donc ce que je devrai passer en paramètre devrait plus ressembler à ça?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void inverser (FILE *filename
    ensuite, feof() ne fait pas ce que tu crois : http://c.developpez.com/faq/?page=es_general#ES_feof
    Merci pour l'info, (mais ça me parait bizarre quand même, on avait fait d'autre exercice sur les fichiers, et on a toujours utiliser ça pour voir si on a atteint la fin du fichier)
    je vais modifier ça et donc je devrai plutôt mettre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int c;
    while ((c = fgetc(fp)) != EOF)
     {
        pos = ftell (fp);
        i++;
        ....
    Et enfin je comprend pour fseek, je ne comprend pas trop d'ailleurs son "utilité" ici mais dans mon cas, l'exo m'impose l'utilisation de fseek et ftell (difference de barême dans la notation)


    @ Nakilu:
    Ah je ne connais pas cette fonction mais est ce que l'utilisation de fgets() ici est fausse?

    découper la ligne selon un délimiteur dans ton cas un espace (comme sa tu as le nom et le prénom) la fonction existe mais je me rappel plus du nom
    Après quelques recherches, j'ai trouvé la fonction char *strtok(char *s, const char *delim).
    Mais je ne vois pas comment l'utiliser ici :/

    vite sscanf et fprintf tant que possible (regarde du coté de read, fread, twrite, write)
    Oui mais encore ce qui est embetant c'est que scanf et fprint sont des fonctions qui sont egalement imposé dans l'exo :/

    @diogene:

    Lorsque je compile, je rencontre une seule erreur qui me dit "Erreur de segmentation" D'après wiki, cette erreur est du que ma fonction tente d'acceder à une zone mémoire qu'il n'as pas le droit. Je ne vois pas à quel endroit et ça ne m'avance guere :S

    Ouit tout à fait d'accord, ça ne sert à rien je le vire de suite.

    Je suis très sceptique sur la possibilité de faire ce que tu veux : tu écris plus que ce que tu lis et ce faisant, tu vas écrabouiller la suite du fichier.
    Ba l'idée pour moi était de recuperer avec fgets s chaque ligne du fichier que je place dans une chaine s. je traite ligne par ligne. Ensuite avec cette chaine j'extrait le nom et le prénom que je place aussi dans des chaine nom et prénom (mais je ne sais pas du tout si j'ai le droit de recuperer comme ça, ça m'a parut trop simple) et ensuite avec le fprintf de réecrive dans le fichier avec nom et prénom inversé. (mais je ne sais pas non plus si j'ai le droit d'écrire ça comme ça aussi :S) Oui le but est "d'ecrabouiller" le fichier original pour le remplacer par le nom/prénom inversé.

    Sinon que me suggères tu?


    Merci d'avance pour vos réponse, iReNu

  6. #6
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Lorsque je compile, je rencontre une seule erreur qui me dit "Erreur de segmentation"
    Un telle erreur ne peut se produire à la compilation mais à l'exécution du programme. Elle aurait pu être provoquée par le s[1000] illégal.
    Oui le but est "d'ecrabouiller" le fichier original pour le remplacer par le nom/prénom inversé.
    J'avais compris, mais ce n'est pas le sens de ma remarque : tu vas écraser des parties du fichier que tu n'as pas encore lues.
    Par exemple, suppose que ton fichier commence comme ça (en notant < la fin de ligne)
    a1111 a222<b1111 b222<....
    je lis et j'écris la première ligne, le fichier devient :
    1 a1111 a222<1111 b222<....
    la deuxième ligne est détruite avant d'être lue !

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 8
    Par défaut
    Oui au temps pour moi, ce n'est pas à la compilation que ça plante mais à l'execution mais malgré que j'ai enlevé le s[1000] =\0 mais le problème persiste. Toujours cette erreur de segmentation

    Par exemple, suppose que ton fichier commence comme ça (en notant < la fin de ligne)
    a1111 a222<b1111 b222<....
    je lis et j'écris la première ligne, le fichier devient :
    1 a1111 a222<1111 b222<....
    la deuxième ligne est détruite avant d'être lue
    Si je comprend bien mon problème vient de mon fprintf. Je ne vois vraiment plus comment je dois faire, aurait une solution à me proposer stp?

  8. #8
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    - Pour le plantage, es-tu sûr que les noms et prénoms ne dépassent pas 19 caractères ?

    - Normalement, entre une lecture et une écriture, il doit y avoir une instruction de positionnement du fichier (par exemple fseek , c'est ton cas) et entre une écriture et une lecture également ou un fflush. Ce n'est pas ton cas et j'ignore si cela peut amener à ce genre d'erreur à l'exécution.

    - Note, qu'en plus, une ouverture en r+ d'un fichier texte peut aboutir sur certaines implémentations à l'ouverture d'un fichier binaire.

    Je ne sais pas comment résoudre ton problème de façon propre en utilisant un seul fichier que l'on modifie.
    Peut-être que d'autres auront une solution ?

    (accessoirement, pourquoi est ce qu'il y a deux fgets dans ta boucle ?)

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 8
    Par défaut
    Oui j'ai bien pris soin que de mettre des exemples de noms et prénoms qui n'excedent pas 6 caractères.



    - Normalement, entre une lecture et une écriture, il doit y avoir une instruction de positionnement du fichier (par exemple fseek , c'est ton cas) et entre une écriture et une lecture également ou un fflush. Ce n'est pas ton cas et j'ignore si cela peut amener à ce genre d'erreur à l'exécution.
    Donc si je comprend bien après le fprintf, il faudrai que je mette un fflush pour vider le flux fp? je vais essayer ça.

    - Note, qu'en plus, une ouverture en r+ d'un fichier texte peut aboutir sur certaines implémentations à l'ouverture d'un fichier binaire.
    Pourquoi r+? Qu'aurais t-il fallut que je mette? Dans ce cas, ma fonction ouvre le fichier et le modifie donc il m'a paru logique d'utiliser r+ pour la lecture et l'écriture sur le fichier.

    (accessoirement, pourquoi est ce qu'il y a deux fgets dans ta boucle ?)
    Oui c'est vrai. Je ne sais plus pourquoi je l'ai écris une deuxième fois mais en me relisant, je ne lui trouve pas d'utilité.. A moins que je ne me trompe.

    Si quelqu'un pourrait éclairer ma lanterne!

  10. #10
    Membre émérite
    Inscrit en
    Juillet 2005
    Messages
    512
    Détails du profil
    Informations forums :
    Inscription : Juillet 2005
    Messages : 512
    Par défaut
    Ton exercice tel qu'exposé ne me semble pas réalisable.
    Pour que ça fonctionne, il faudrait que ton fichier soit déjà formaté pour contenir le numéro de classement, les champs nom et prénom avec une longueur fixe dans le fichier.

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    57
    Détails du profil
    Informations personnelles :
    Âge : 17
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 57
    Par défaut
    Salut,

    Pourquoi ne pas lire le fichier et stocker les informations (par exemple dans une liste chainée), fermer le fichier, et le rouvrir mais cette fois dans le but de le réécrire avec les informations que tu as déjà stockées?

    genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     ouvrir fichier en lecture seule
    lire le fichier et stocker
    fermer le fichier
     
    ouvrir le fichier en écriture seule
    écrire les informations stockées dans le format désiré
    fermer le fichier
    Sinon, une autre manière de faire serait d'ouvrir le fichier, et qu'en même temps que tu le lis tu écris dans un deuxième fichier, puis une fois que c'est fini tu supprimes le premier fichier et renomme le deuxième.

    Mais dans tous les cas, tu ne peux pas lire et modifier ligne par ligne car le deuxième format prend plus d'espace que le premier format. (ajout des caractères de numérotations)

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    8
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 8
    Par défaut
    Bonsoir à tous et merci pour vos réponses.

    Ton exercice tel qu'exposé ne me semble pas réalisable.
    Pour que ça fonctionne, il faudrait que ton fichier soit déjà formaté pour contenir le numéro de classement, les champs nom et prénom avec une longueur fixe dans le fichier.
    Ah? pourtant j'ai eu cette exercice à mon dernier partiel!! :S

    Salut,

    Pourquoi ne pas lire le fichier et stocker les informations (par exemple dans une liste chainée), fermer le fichier, et le rouvrir mais cette fois dans le but de le réécrire avec les informations que tu as déjà stockées?

    genre:
    Code :

    ouvrir fichier en lecture seule
    lire le fichier et stocker
    fermer le fichier

    ouvrir le fichier en écriture seule
    écrire les informations stockées dans le format désiré
    fermer le fichier

    Sinon, une autre manière de faire serait d'ouvrir le fichier, et qu'en même temps que tu le lis tu écris dans un deuxième fichier, puis une fois que c'est fini tu supprimes le premier fichier et renomme le deuxième.

    Mais dans tous les cas, tu ne peux pas lire et modifier ligne par ligne car le deuxième format prend plus d'espace que le premier format. (ajout des caractères de numérotations)
    Oui effectivement cette methode marche, c'était justement la deuxième possibilité de cette exercice en passant par un deuxième fichier (que j'ai pu faire) mais la première methode (en utilisant fseek et ftell) qui est plus dur (d'ou la difference de bareme pour les 2 possibilités) m'interresse et j'aimerai pouvoir l'appliquer!

    Merci d'avance!

  13. #13
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    La première méthode n'implique pas du tout d'utiliser fseek et ftell.
    Elle dit de lire l'intégralité du fichier et de le stocker en mémoire puis de le réécrire ensuite. Ce n'est pas du tout le problème que tu exposes depuis le début de ce post.

    Mais dans tous les cas, tu ne peux pas lire et modifier ligne par ligne car le deuxième format prend plus d'espace que le premier format. (ajout des caractères de numérotations)
    C'est ce que je me tue (avec d'autres) à te dire depuis le début.

  14. #14
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Par défaut
    En maintenant correctement le pointeur de fichier en lecture et la taille du fichier après écriture, il doit être possible de lire suffisamment de lignes "par avance" (avant l'écriture donc), pour faire en sorte de ne jamais écrire sur des données qui n'ont pas encore été lues (on peut par exemple envisager de lire ces lignes et de les stocker dans une liste chainée). Pour cela, il suffit de lire autant de ligne que nécessaire de telle sorte que le pointeur de lecture soit toujours supérieur à la taille actuelle écriture additionnée de la prochaine nouvelle ligne (tenant compte des digits ajoutés pour le numéro). Il est possible de faire cette lecture, juste avant l'écriture de la ligne courante, donc lorsque celle-ci est déjà formatée, et que l'on dispose de sa taille réelle.
    Bien entendu, la quantité de mémoire nécessaire pour lire est croissante.

  15. #15
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Je pense qu'il n'est pas trop dûr de faire simplement l'inversion "sur place" sur un fichier texte, vu qu'il n'y a pas de modification de la taille de la ligne.

    La boucle principale ressemblerait à ceci:
    Code X : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    POUR chaque ligne du fichier
    	ftell() avant de lire la ligne
    	Lire la ligne en mémoire
    	ftell()
    	Inverser les deux mots en mémoire (sans doute passer par un second buffer) 
    	fseek() pour revenir au début de la ligne
    	Écrire la ligne modifiée dans le fichier
    	fseek() pour s'assurer d'être à la fin (il me semble que la norme exige un fseek() quand on passe de lecture à écriture et vice verse)

    Par contre, pour ajouter le numéro, c'est une autre histoire. Pour l'ajout du numéro, je serais plutôt du genre à faire une copie ligne-à-ligne traditionnelle...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. occurrence d'un mot dans un fichier
    Par vallytiana dans le forum Langage
    Réponses: 10
    Dernier message: 18/01/2006, 17h10
  2. Réponses: 4
    Dernier message: 16/12/2005, 17h43
  3. lire un mot dans un fichier
    Par ibtisss dans le forum Langage
    Réponses: 3
    Dernier message: 08/11/2005, 12h14
  4. Réponses: 8
    Dernier message: 18/01/2005, 10h58
  5. Comment changer des mots dans un fichier?
    Par ptitbonum dans le forum Linux
    Réponses: 5
    Dernier message: 07/04/2004, 23h42

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