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 :

Problème avec fgets


Sujet :

C

  1. #1
    Membre régulier
    Inscrit en
    Avril 2008
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 8
    Par défaut Problème avec fgets
    Bonjour,

    J'ai un problème que je ne parviens pas à comprendre : Dans la fonction saisieLettre(), j'appelle userInput(). Dans celle si, dans gdb je vois que le printf() ne se fait que lors du getchar() de viderBuffer() ... il ne reste pourtant normalement rien dans stdin mais même si c'était le cas, pourquoi le printf() attendrait le getchar() pour s'effectuer ?

    Quelqu'un peut il m'expliquer ?

    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
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
     
    #include <stdio.h>
    #include <string.h>
    #include "input.h"
     
    void pendu(const char *);
    void affichageMot(const char *);
    char saisieLettre(const char *);
    char *verifLettre(const char,const char *, const char *, char *);
    int partieFinie(const char *,const char *,const int);
    void epilogue(const char *,const int);
     
    int main(int argc, char **argv)
    {
      char mot[30];
      char phrase[] = "Entrez le mot à rechercher (max. 30 caractères)";
      while (!userInput(phrase, mot, 30))
          {
    	  printf("Une erreur s'est produite ... ");
          }
      pendu(mot);
     
      return 0;
    }
     
     
    /*************************************************************************
     * Nom              : pendu()                                            *
     *-----------------------------------------------------------------------*
     * Fonction         : Jeu du pendu.                                    *
     *-----------------------------------------------------------------------*
     * Paramètres       : mot → Le mot à deviner.                            *
     *-----------------------------------------------------------------------*
     * Valeur de retour :   *
     ************************************************************************/
    void pendu(const char *mot)
    {
        /* Déclaration des variables */
     
        char lettre, propose[26], ok[30], test[30], copieTest[30];
        int fini, i, mauvRep, cptLettreDejaProposee;
     
        /* Initialisation des variables */
     
        lettre = ' ';
        mauvRep = 0;
        cptLettreDejaProposee = 0;
        for (i = 0; i < strlen(mot); i++)
    	{
    	    test[i] = '-';
    	}
        test[i] = '\0';
     
        fini = 0;
     
        while (!fini)
    	{
    	    affichageMot(test);
    	    lettre = saisieLettre(propose);
    	    cptLettreDejaProposee++;
    	    propose[cptLettreDejaProposee-1] = lettre;
    	    strncpy(ok, verifLettre(lettre, mot, test, copieTest), 30);
    	    if (strcmp(ok, test) == 0)
    		{
    		    mauvRep++;
    		}
    	    else
    		{
    		    strncpy(test, ok, 30);
    		    /* strncpy ne plaçant pas un null byte de terminaison en cas de source
    		       plus longue que la destination, il est préférable de le faire. */
    		    ok[29]= '\0';
    		}
    	    fini = partieFinie(test, mot, mauvRep);
    	}
        affichageMot(test);
        epilogue(mot, fini);
    }
     
    void affichageMot(const char *test)
    {
        printf("%s\n",test);
    }
     
    char saisieLettre(const char *propose)
    {
        char lettre[2];
        char phrase[] = "Entrez une lettre de l'alphabet (et une seule)";
     
        while (!userInput(phrase, lettre, 1) || !(lettre[0] >= 97 && lettre[0] <= 122) || strchr(propose, lettre[0]))
    	{
    	    printf("Erreur ... ");
    	}
        return lettre[0];
    }
     
    char *verifLettre(const char lettre, const char *mot, const char *test, char *copieTest)
    {
        int i = 0;
        strncpy(copieTest, test, 30);
        while (mot[i] != '\0')
    	{
    	    if (lettre == mot[i])
    		{
    		    copieTest[i] = lettre;
    		}
    	    i++;
    	}
        return copieTest;
    }
     
    int partieFinie(const char *test, const char *mot, const int mauvRep)
    {
        int etatPartie = 0;
        if (strcmp(test, mot) == 0)
    	{
    	    etatPartie = 1;
    	}
        else if (mauvRep > 5)
    	{
    	    etatPartie = 2;
    	}
        return etatPartie;
    }
     
    void epilogue(const char *mot,const int fini)
    {
        if (fini)
    	{
    	    printf("Bravo, vous avez gagne !");
    	}
        else
    	{
    	    printf("Perdu ! Le mot qu'il fallait deviner était %s.", mot);
    	}
    }
    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
    #include <stdio.h>
    #include <string.h>
    #include "input.h"
     
    /**************************************************************************
     * Nom              : userInput()                                         *
     *------------------------------------------------------------------------*
     * Fonction         : Demande à l'utilisateur d'entrer une chaine de      *
     *                    caractère et s'occupe d'éviter un buffer overflow.  *
     *------------------------------------------------------------------------*
     * Paramètres       : phrase → Phrase affichée à l'utilisateur.           *
     *                    mot    → Variable ou sera stocké ce mot.            *
     *                    taille → Longueur que fgets récupèrera.             *
     *------------------------------------------------------------------------*
     * Valeur de retour : 1   → Si l'opération c'est déroulée sans problème.  *
     *                    0   → Si une erreur est survenue.                   *
     **************************************************************************/
    int userInput(char *phrase, char *mot, int taille)
    {
      char *enter;
      int done;
     
      printf("%s : ", phrase);
     
      if (fgets(mot, taille, stdin))
        {
          enter = strchr(mot, '\n');
          if (enter)
    	{
    	  *enter = '\0';
    	  done = 1;
    	}
          else
    	{
    	    viderBuffer();
    	    done = 0;
    	}
        }
      else
        {
          done = 0;
        }
     
      return done;
    }
    /**************************************************
     * Nom        : viderBuffer()                     *
     *------------------------------------------------*
     * Fonction   : Vide le contenu du buffer stdin.  *
     *------------------------------------------------*
     * Paramètres : Aucun.                            *
     *------------------------------------------------*
     * Retour     : Rien.                             *
     **************************************************/
    void viderBuffer(void)
    {
      int c;
      do
          {
    	  c = getchar();
          }
      while(c != '\n' && c != EOF);
    }

  2. #2
    Invité(e)
    Invité(e)
    Par défaut
    Bonjour,

    Les fonction de sortie standard sont bufferisées, c'est à dire qu'elles attendent d'être pleines ou qu'on leur dise pour afficher leur contenu. (getchar est l'un des événement qui déclenche l'affichage)

    Pour forcer l'affichage du printf, on peut :
    • ajouter '\n' (ce qui fait sauter une ligne)
    • appeler 'fflush(stdout)'


    Je pense que dans ton cas, ajouter 'fflush(stdout);' après chaque printf suffirait.

  3. #3
    Membre régulier
    Inscrit en
    Avril 2008
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 8
    Par défaut
    D'accord, je comprends mieux, merci

  4. #4
    Membre régulier
    Inscrit en
    Avril 2008
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 8
    Par défaut
    Encore une petite question : Quelle est la différence entre stdin._IO_read_base et stdin._IO_read_end ? En fait je cherche à savoir ce que contient stdin car j'ai un fgets() qui se fait sans que j'entre quelque chose malgré qu'il stdin soit censé être vide ...

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 485
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 485
    Par défaut
    Citation Envoyé par mabu Voir le message
    Pour forcer l'affichage du printf, on peut :
    • ajouter '\n' (ce qui fait sauter une ligne)
    • appeler 'fflush(stdout)'


    Je pense que dans ton cas, ajouter 'fflush(stdout);' après chaque printf suffirait.
    On peut aussi et surtout utiliser setbuf()

  6. #6
    Membre régulier
    Inscrit en
    Avril 2008
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 8
    Par défaut
    Citation Envoyé par Cedscredi Voir le message
    Encore une petite question : Quelle est la différence entre stdin._IO_read_base et stdin._IO_read_end ? En fait je cherche à savoir ce que contient stdin car j'ai un fgets() qui se fait sans que j'entre quelque chose malgré qu'il soit censé être vide ...
    Quelqu'un sait ou je peux trouver des informations à ce sujet ( sur la structure de stdin ) ? Mes recherches restent infructueuses ...

    Edit :

    Donc voila, je comprends mieux le fonctionnement de stdin grâce à gdb mais toujours pas la cause de mon problème : Lors du premier appel à userInput() pour demander à l'utilisateur d'entrer le mot à deviner, tout se passe bien. Lors du deuxième appel, dans saisieLettre(), dans gdb je vois que le programme passe le fgets() sans rien demander. Pourtant, avant le fgets(), si je fais un p stdin._IO_read_ptr, je constate qu'il ne pointe sur rien et logiquement, il devrait donc demander des données non ? Il ne demande qu'au getchar() de viderBuffer() ... Je suis pourtant presque sur que stdin est vide lors de l'appel de fgets().

  7. #7
    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
    fgets() lit un caractère de moins que la valeur spécifiée en 2ieme argument (il garde le dernier caractère pour mettre le 0 terminal).
    saisieLettre() passe la valeur 1 comme argument pour fgets(). Donc fgets() ne lit rien.

    stdin est un FILE* et FILE est un type qui dépend de l'implémentation (De toute façon, on devrait avoir stdin->_IO_read_base et non pas stdin._IO_read_base).

  8. #8
    Membre régulier
    Inscrit en
    Avril 2008
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 8
    Par défaut
    Oui, je te remercie. Donc suffisait que je lui dise de prendre 3 caractères pour la lettre, le \n et le \0.
    Bonne journée !

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

Discussions similaires

  1. Probléme avec fgets
    Par Lucas42 dans le forum C
    Réponses: 2
    Dernier message: 18/11/2007, 03h08
  2. Problème avec fgets() et strlen()
    Par condor_01 dans le forum C
    Réponses: 6
    Dernier message: 28/10/2007, 12h41
  3. Problème avec fgets
    Par fabpeden dans le forum C
    Réponses: 13
    Dernier message: 15/05/2007, 10h25
  4. problème avec fgets
    Par salseropom dans le forum C
    Réponses: 1
    Dernier message: 03/08/2006, 14h54
  5. Problème avec fgets et tube...
    Par tchingoo dans le forum POSIX
    Réponses: 5
    Dernier message: 22/08/2003, 17h03

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