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 :

lecture de caractères


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Mai 2008
    Messages
    45
    Détails du profil
    Informations personnelles :
    Âge : 36

    Informations forums :
    Inscription : Mai 2008
    Messages : 45
    Par défaut lecture de caractères
    Bonjour,
    j'essaye de faire une liste de chevaux de course en C, voici ma structure:
    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
     
    struct Liste_ch
     
    {
     
           char Nom[20];
     
           int age;
     
           char sexe;
     
           int courses;
     
           int victoires;
     
           char driver[20];
     
           struct Liste_ch *next;
     
    };
    j'ai définis une fonction pour ajouter un élément à la liste que voice:
    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
    // fonction d'ajout d'un cheval à la liste de course.
     
     
     
    liste_ch* ajouter_cheval(liste_ch *lcheval)
     
    {
     
              liste_ch *l;
     
              if((l=(liste_ch*)malloc(sizeof(liste_ch)))==NULL)
     
              {printf("Erreur d'allocation !\n");
     
              exit(-1);
     
              }
     
     
     
              printf("Entrer le nom du cheval:\n");
     
              scanf("%s",l->Nom);
     
              printf("Entrer l'age:\n");
     
              scanf("%d",&l->age);
     
              printf("Entrer le sexe M/F/H: \n");
     
              l->sexe = getchar();
     
              printf("Entrer le nombre de courses du cheval:\n");
     
              scanf("%d",&l->courses);
     
              printf("Entrer le nombre de victoires du cheval:\n");
     
              scanf("%d",&l->victoires);
     
              printf("Entrez le nom du driver:\n");
     
    	  scanf("%s",l->driver);
     
     
     
              l->next= lcheval;
     
              lcheval = l;
     
     
     
              return(l);
     
              }
    le premier souci que j'ai eu c'est que je peux pas utiliser la fonction "gets" pour lire mes chaines de caractères, le compilateur envois ce message:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    In function `ajouter_cheval':
    liste.c:(.text+0xf9): warning: the `gets' function is dangerous and should not be used.
    je veux bien utiliser "gets" à la place de " scanf("%s") ".
    le deuxième souci c'est quand je veux lire le caractère sexe, à l'éxecution du programme ça saute toujours cette étape, et je peux rien entrer,
    je sais pas ou est l'erreur, quelqu'un peut m'aider ??
    merci.


    Marouane.

  2. #2
    Membre Expert
    Profil pro
    Inscrit en
    Août 2006
    Messages
    1 104
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 1 104
    Par défaut
    Salut

    1) Concernant gets :
    N'utilisez jamais gets(). Comme il est impossible de savoir à l'avance combien de caractères seront lus par gets(), et comme celui-ci écrira tous les caractères lus, même s'ils débordent du buffer, cette fonction est extrèmement dangereuse à utiliser. On a déjà utilisé ce dysfonctionnement pour créer des trous de sécurité. UTILISEZ TOUJOURS fgets() A LA PLACE DE gets().
    ( http://man.developpez.com/man3/fgets.3.php )

    2) Il faut vider le buffer clavier avant d'appeler getchar.

  3. #3
    Membre averti
    Inscrit en
    Mai 2008
    Messages
    45
    Détails du profil
    Informations personnelles :
    Âge : 36

    Informations forums :
    Inscription : Mai 2008
    Messages : 45
    Par défaut
    Salut,
    merci jeroman pour ta réponse,
    j'ai modifier ma fonction en ésperant que ça resoudera le problème, mais je crois que j'ai pas bien fait, voici la partie du code qui m'interesse:
    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
     
              printf("Entrer l'age:\n");
     
              scanf("%d",&l->age);
     
              fflush(stdin);
     
    	  printf("Entrer le sexe M/F/H: \n");
     
              l->sexe = getchar();
     
              printf("Entrer le nombre de courses du cheval:\n");
     
              scanf("%d",&l->courses);
     
              printf("Entrer le nombre de victoires du cheval:\n");
     
              scanf("%d",&l->victoires);
     
    	  fflush(stdin);
     
              printf("Entrez le nom du driver:\n");
     
    	  fgets(l->driver,20,stdin);
    mais ça saute toujours les deux étapes de lecture, du "sexe" et du "driver",

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

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

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par jeroman Voir le message
    2) Il faut vider le buffer clavier avant d'appeler getchar.
    Non. Un buffer clavier ne peut pas être vidé (fflush(stdin) donne un comportement indéterminé) et de toute façon n'a pas besoin d'être vidé.
    En effet, si toutes les saisies ont été bien faites avec fgets() suivi éventuellement de sscanf(), le clavier est toujours vide quand le programme arrive à la saisie suivante.

    Citation Envoyé par Elaich Voir le message
    Salut,
    merci jeroman pour ta réponse,
    j'ai modifier ma fonction en ésperant que ça resoudera le problème, mais je crois que j'ai pas bien fait, voici la partie du code qui m'interesse:
    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
     
              printf("Entrer l'age:\n");
     
              scanf("%d",&l->age);
     
              fflush(stdin);
     
    	  printf("Entrer le sexe M/F/H: \n");
     
              l->sexe = getchar();
     
              printf("Entrer le nombre de courses du cheval:\n");
     
              scanf("%d",&l->courses);
     
              printf("Entrer le nombre de victoires du cheval:\n");
     
              scanf("%d",&l->victoires);
     
    	  fflush(stdin);
     
              printf("Entrez le nom du driver:\n");
     
    	  fgets(l->driver,20,stdin);
    mais ça saute toujours les deux étapes de lecture, du "sexe" et du "driver",

    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
     
              char saisie[80];
              printf("Entrer l'age:\n");
              fgets(saisie, 80, stdin);
              sscanf(saisie, "%d",&l->age);
     
    	  printf("Entrer le sexe M/F/H: \n");
              l->sexe = getchar();
     
              printf("Entrer le nombre de courses du cheval:\n");
              fgets(saisie, 80, stdin);
              sscanf(saisie, "%d",&l->courses);
     
              printf("Entrer le nombre de victoires du cheval:\n");
              fgets(saisie, 80, stdin);
              sscanf("%d",&l->victoires);
     
              printf("Entrez le nom du driver:\n");
    	  fgets(l->driver,20,stdin);
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Non. Un buffer clavier ne peut pas être vidé (fflush(stdin) donne un comportement indéterminé) et de toute façon n'a pas besoin d'être vidé.
    En effet, si toutes les saisies ont été bien faites avec fgets() suivi éventuellement de sscanf(), le clavier est toujours vide quand le programme arrive à la saisie suivante.
    Petit bémol, le buffer n'est pas toujours vide après un fgets(), notamment lorsque la taille de la ligne est plus importante que celle du buffer (par exemple si je saisie 90 caractères dans ton exemple).

    Dans ce cas, il faut bel et bien vider le buffer clavier. Mais effectivement, il ne faut pas utiliser fflush() pour réaliser cette opération mais lire tout les caractères supplémentaires (chercher fclean() dans le forum pour plus d'info à ce sujet).

  6. #6
    Membre averti
    Inscrit en
    Mai 2008
    Messages
    45
    Détails du profil
    Informations personnelles :
    Âge : 36

    Informations forums :
    Inscription : Mai 2008
    Messages : 45
    Par défaut
    Salut,
    merci Sve@r, ta solution marche mais pas tout a fait, d'abord je comprend pas pourquoi je dois écrire dans une chaîne de caractère puis lire depuis cette chaîne, pourquoi pas lire depuis le clavier directement, plus pratique , non ? avec fgets(...,...,stdin), je dois seulement vider le tampon après chaque lecture, est ce qu'il y a une solution simple à ce problème ?
    Et merci.


    Marouane

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 827
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

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

    Informations forums :
    Inscription : Février 2006
    Messages : 12 827
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Elaich Voir le message
    Salut,
    merci Sve@r, ta solution marche mais pas tout a fait, d'abord je comprend pas pourquoi je dois écrire dans une chaîne de caractère puis lire depuis cette chaîne, pourquoi pas lire depuis le clavier directement, plus pratique , non ? avec fgets(...,...,stdin)
    Marouane
    Le gros problème d'un scanf("%d", ...) c'est que ça attend une entrée formatée. Ici il lui faut du nombre et ne traitera que du nombre.
    Mais celui qui répond à l'ordinateur peut entrer ce qu'il veut. Et s'il entre "toto" au lieu du nombre attendu, ou "12toto", le scanf récupère la valeur "12" mais laissera la chaine "toto" dans le buffer stdin.
    Ensuite, si par hasard tu fais un scanf("%s", nom) ou même un fgets(), la fonction récupèrera la chaine "toto" qui y est restée depuis la saisie précédente. D'où le conseil malheureux du vidage du buffer stdin que t'as traduit par un fflush(stdin) inutile.

    Et même si tu entres bien le nombre "12" comme il faut, tu termines tout de même ta saisie par un "<return>". Ben ce <return> n'étant pas du nombre, scanf le laisse dans le stdin.

    Dans la solution que je te présente, on commence par saisir une string. Quoi que soit ce qui est entré, il va intégralement dans la variable "saisie" et disparait donc du clavier => plus de problème de fflush(stdin).
    Ensuite avec sscanf(), tu extraits de la chaine le nombre attendu. Tu peux même tester la réussite de l'opération car sscanf() te renvoie le nombre réel de variables qui ont pu être remplies donc si sscanf() ne donne pas 1, c'est qu'il n'a pas fonctionné => permet de reboucler sur la saisie si tu le désires

    Citation Envoyé par Elaich Voir le message
    , je dois seulement vider le tampon après chaque lecture, est ce qu'il y a une solution simple à ce problème ?
    Oui, celle-là car le tampon est automatiquement vidé par fgets(). C'est une des meilleures solutions préconisées (et elle n'est pas de moi mais je crois de Emmanuel Delahaye, le cador du C de ce forum).

    Avec cette méthode, tu peux même créer un fichier contenant les réponses attendues et donner le fichier à manger à ton programme via un pipe. Ton programme déroulera et ingurgitera sans problème les réponses prévues dans le fichier (chose qui ne fonctionne pas quand on vide le buffer après la saisie car on court le risque de vider une info utile)

    Citation Envoyé par gl Voir le message
    Petit bémol, le buffer n'est pas toujours vide après un fgets(), notamment lorsque la taille de la ligne est plus importante que celle du buffer (par exemple si je saisie 90 caractères dans ton exemple).
    Exact. Je pense que 80 est une bonne valeur mais peut ne pas suffire face à ce qu'on nomme communément "test du crétin".

    Citation Envoyé par gl Voir le message
    Dans ce cas, il faut bel et bien vider le buffer clavier. Mais effectivement, il ne faut pas utiliser fflush() pour réaliser cette opération mais lire tout les caractères supplémentaires (chercher fclean() dans le forum pour plus d'info à ce sujet).
    Perso je préfère éviter de vider le buffer clavier (pour les raisons que je mentionne plus haut). Si vraiment on doit faire une saisie "cretin proof", je conseillerais alors de passer par un getline() qui adapte automatiquement la zone à remplir en fonction du nombre de caractères saisis.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. Réponses: 3
    Dernier message: 19/01/2009, 14h43
  2. [bios] Lecture de caractère et état du clavier
    Par homeostasie dans le forum C
    Réponses: 17
    Dernier message: 27/07/2007, 00h26
  3. [SAX] Lecture des caractères
    Par alex'l dans le forum Format d'échange (XML, JSON...)
    Réponses: 1
    Dernier message: 12/04/2007, 16h42
  4. Lecture du caractères UTF-16 fichier
    Par Jamlan dans le forum C
    Réponses: 4
    Dernier message: 27/12/2006, 14h41
  5. Réponses: 1
    Dernier message: 20/03/2006, 09h46

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