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

Bibliothèque standard C Discussion :

Scanf, fgets et buffer.


Sujet :

Bibliothèque standard C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 121
    Par défaut Scanf, fgets et buffer.
    Bonjour,

    j'ai posté il y a un petit moment pour un problème de saisie au clavier.

    Le problème était qu'il y avait à la fois des scanf et des fgets dans mon programme.

    Suivant les conseils j'ai donc obtenu les deux fonctions :
    - saisieChaine
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void saisieChaine(char *chaine, size_t size, FILE *file){
       int saisie_OK = 0;
       while (saisie_OK == 0){
          fgets (chaine, size, file);
          saisie_OK = !fclean (chaine, file);
          if (saisie_OK==0){
            fprintf (stderr, "Saisie trop longue, recommencez\n");
          }
       }
    }
    et
    - fclean
    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
    int fclean(char *chaine, FILE *file){
      int erreur = 0;
      if (chaine != NULL && file != NULL){
        char *sautLigne = strchr(chaine, '\n');
        //si la saisie n'a pas ete tronquee 
        if (sautLigne != NULL){  
          //on remplace '\n' par '\0' 
          *sautLigne = '\0';  
        }
        //si la saisie a ete tronquee, on purge le flux d'entree
        else{  
          int c;
          while ((c = fgetc (file)) != '\n' && c != EOF);
          erreur = 1;
        }
      }
      return erreur;
    }
    Cela marche très bien mon problème est plutôt de comprendre pourquoi ça ne marchait pas ^^.

    Donc mes questions sont :
    1) quel est le problème quand on utilise scanf et fgets dans un même programme (un problème de buffer si j'ai bien compris mais j'aimerais bien avoir des details).
    2) a quoi sert a ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
          while ((c = fgetc (file)) != '\n' && c != EOF);
    A purger le flux d'entrée daccord mais quel est le problème si on ne la met pas ?


    Merci d'avance pour vos réponses

  2. #2
    Rédacteur/Modérateur
    Avatar de Trap D
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    4 942
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 4 942
    Par défaut
    Le problème est qu'il est TRRRRRRRRRRRRRES diffiicile d'utiliser scanf, et qu'en principe, on utilise fgets avec les fonctions de conversions nécessaires ensuite.
    scanf laisse le '\n' dans le tampon de saisie donc en général le fgets suivant le lit, pour lui c'est une validation de saisie donc on a une saisie vide et un décalage dans les saisies.
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : La Madeleine à la veilleuse de Georges de La Tour

  3. #3
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par SAKDOSS Voir le message
    1) quel est le problème quand on utilise scanf et fgets dans un même programme (un problème de buffer si j'ai bien compris mais j'aimerais bien avoir des details).
    2) a quoi sert a ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
          while ((c = fgetc (file)) != '\n' && c != EOF);
    A purger le flux d'entrée daccord mais quel est le problème si on ne la met pas ?
    Pour ça, il faut comprendre le fonctionnement de fgetc() (qui est la fonction d'entrée 'atomique' du C, qui sert à coder les autres fonctions comme scanf() et fgets()) :

    http://emmanuel-delahaye.developpez.com/notes.htm#fgetc

    ensuite, une fois qu'on a compris que scanf() ne lisait pas le '\n', on comprend qu'un fgets() suivant un scanf() n'est pas bloquant.

    La purge sert donc à s'assurer que les caractères non traités par scanf() (au minimum, un '\n', ne sont plus présents dans le flux entrant et l'appel à la fonction d'entrée sera bien bloquante.

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 121
    Par défaut
    Hmm daccord merci.

    Donc si je n'utilise que des fgets, la purge n'est pas utile ?

  5. #5
    Expert éminent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 68
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par SAKDOSS Voir le message
    Donc si je n'utilise que des fgets, la purge n'est pas utile ?
    Si, mais pour d'autres raisons. Quand on a pas trouvé le '\n', c'est que tous les caractères n'ont pas été lus. Si on décide de les ignorer, on purge le flux.

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 121
    Par défaut
    Daccord je vois merci bien

  7. #7
    Expert confirmé
    Avatar de Melem
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2006
    Messages
    3 656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Janvier 2006
    Messages : 3 656
    Par défaut
    Soit le programme suivant :
    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
    #include <stdio.h>
     
    int main()
    {
        char buffer[8];
     
        printf("1. Entrez une chaine sans espace : ");
        scanf("%7s", buffer);
        printf("%s\n", buffer);
     
        printf("2. Entrez une chaine sans espace : ");
        scanf("%7s", buffer);
        printf("%s\n", buffer);
     
        return 0;
    }
    scanf, avec le format %s, va passer tous les caractères blancs (espaces, tabulations, etc.) puis commence effectivement la saisie à la rencontre d'un premier caractère non blanc. Elle s'arrête dès qu'elle aura de nouveau rencontrer un caractère blanc.

    Ici, si l'utilisateur tapepuis, tout se passe bien puisque abcd fait moins de 7 caractères.

    Par contre, si l'utilisateur tape, seuls les 7 premiers caractères seront placés dans buffer c'est-à-dire azertyu. Il reste encore donc 4 caractères dans le buffer du flux d'entrée standard : iop<ENTREE>. A la prochaine saisie, ces caractères seront immédiatement lus. scanf va donc lire iop car elle s'arrête à la rencontre d'un caractère blanc. Il reste donc encore un caractère dans le buffer de stdin : <ENTREE>.

    En langage C, <ENTREE> = '\n'.

    Il faut donc tout simplement savoir comment fonctionne la fonction qu'on utilise. Par exemple, scanf("%s", ...) ne prend pas les caractères blancs alors que fgets lit tous les caractères (y compris le '\n').

    Purger le buffer de stdin est nécessaire lors qu'il y reste encore des caractères non lus autrement dit tant qu'on n'a pas lu le caractère '\n' (qui est la marque de fin de ligne). Pour purger ce buffer, il suffit de lire tous les caractères jusqu'au dernier et pas de quartier.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    void PurgeStdin()
    {
        int c;
     
        c = getchar();
        while (c != EOF && c != '\n')
            c = getchar();
    }
    Le test c != EOF est nécessaire car EOF est la valeur renvoyée par getchar en cas d'erreur (fin de fichier rencontrée par exemple).

Discussions similaires

  1. fgets + scanf et gestion des espaces
    Par Yunchi dans le forum Débuter
    Réponses: 7
    Dernier message: 02/03/2009, 15h35
  2. scanf vs fgets
    Par _SamSoft_ dans le forum C
    Réponses: 86
    Dernier message: 06/09/2007, 14h27
  3. stencil buffer
    Par patapetz dans le forum OpenGL
    Réponses: 6
    Dernier message: 26/02/2004, 17h23
  4. Affichage en passant par un buffer...
    Par Sirotilc dans le forum MFC
    Réponses: 5
    Dernier message: 27/05/2002, 21h00
  5. Alpha blending et Z-buffer directx 8
    Par Cesar4 dans le forum DirectX
    Réponses: 1
    Dernier message: 23/05/2002, 12h58

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