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 :

scanf non fonctionelle


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Nouveau candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2020
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2020
    Messages : 1
    Par défaut scanf non fonctionelle
    Bonjour je ne trouve pas mon erreur :'(

    sylvainc@sylvain--pc:~/programme/Langage_C_Partie_4$ vim lire_donnees_au_clavier.c
    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
     
    #include <stdio.h>
     
    int main(void)
    {
            //Nous avons vus dans le cours précèdant
     
            int monage = 29;
     
            printf("Mon âge est de %d ans \n", monage);
     
            /*Ce que l'on voudrais faire c'est apprendre à demmander à l'utilisateur 
             * de saisir les données lui même
            */
     
            int ageutilisateur = 0;
     
            printf("Quel âge avez vous ? ");
            scanf("%d", &ageutilisateur);
            printf("Vous avez donc %d ans \n", ageutilisateur);
     
            /*Le & est très important pour le scanf
             * mavariable  : contenu de la variable (example mavariable = A)
             * &mavariable : C'est l'adresse ou est stocker la variable
            */
     
            signed char lettre = 'A';
            printf("Choisissez une lettre :> ");
            scanf("%c", &lettre);
            printf("La lettre choisis est :> %c ", lettre);
     
            return 0;
    }
    sylvainc@sylvain--pc:]~/programme/Langage_C_Partie_4$ gcc lire_donnees_au_clavier.c -o liredonneesauclavier
    sylvainc@sylvain--pc:~/programme/Langage_C_Partie_4$ ./liredonneesauclavier
    Mon âge est de 29 ans
    Quel âge avez vous ? 30
    Vous avez donc 30 ans
    Choisissez une lettre :> La lettre choisis est :>
    sylvainc@sylvain--pc:~/programme/Langage_C_Partie_4$


    Pourquoi mon deuxième scanf est ignoré ?

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 836
    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 836
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par sylvain666 Voir le message
    Pourquoi mon deuxième scanf est ignoré ?
    C'est un problème archi-connu.

    Le souci de scanf(), c'est qu'il attend une entrée formatée avec exactitude. Et que ce que tape l'utilisateur est tout sauf formaté avec exactitude. Même avec la meilleure volonté du monde, il ne peut pas donner à scanf() ce qu'elle attend. Et si ce qui est donné n'est pas comme il faut, alors la fonction l'ignore et ce quelque chose reste jusqu'à ce qu'il puisse être traité. On ne fait pas saisir quelque chose via scanf() à un humain. Malheureusemernt quand on apprend le C, on est obligé d'arriver assez vite à la saisie et les méthodes de saisies viables étant assez complexes, on passe alors, pour simplifier, par scanf(). Ce qui est un bon pis-aller mais seulement au début. Ensuite il faudra l'abandonner.

    Donc l'erreur: à ta première saisie, tu tapes "30" ok. Mais tu valides cette saisie par l'appui sur la touche <return>, qui est un caractère réel ('\n' exactement), lequel caractère vient s'ajouter à ta saisie. Le clavier contient donc '3', '0', '\n'. Le scanf() attend un nombre, il ne récupère que le nombre (le '3' et '0') et laisse tout ce qui n'est pas nombre (donc le '\n') dans le clavier.
    A la saisie suivante tu demandes à scanf() de récupérer un caractère. Ok, il a à sa disposition le caractère '\n' déjà présent, il ne s'embête pas à attendre que tu tapes quelque chose, il le récupère comme demandé.

    Pour corriger: chaque fois que tu feras saisir un nombre ou un simple caractère, il te faudra ajouter l'instruction fgetc(stdin) juste après, pour virer ce '\n'. Plus tard tu apprendras à faire des saisies plus robustes (parce que cette solution simpliste ne fonctionne que si tu joues le jeu et si par exemple tu tapes "toto" là où on te demande ton âge, elle ne fonctionnera pas).

    Et attention à ne pas formater ton cerveau sur des idées figées qui contiennent une certaine dose d'erreur car le "&" n'est pas systématique pour scanf() (cf ton commentaire). Parce que pour faire saisir une chaine, on ne le met pas.
    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]

  3. #3
    Membre très actif
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Par défaut
    Bonjour,

    Attention, l'erreur n'est pas simplement due au fait que scanf doit avoir une entrée formatée avec exactitude/ s'assurer que la saisie effectuée au clavier par l'utilisateur devra être la même que celle spécifiée dans le format. Non ; c'est juste que la fonction scanf n'est absolument pas adaptée pour des entiers et où des nombres à virgule flottante à partir d'une d'entrée car, l'entrée en question peut contenir des nombres non représentables par le type d'argument voulu ou format attendu et c'est là où est réellement le problème et la difficulté de scanf.

    Une des solutions, c'est l'utilisation d'une fonction de saisie sécuriser et ensuite procéder à une conversion de la saisie avec les fonctions telles que strtol(). Ce qui garantie et vérifie bien que l'on a un entier ou nombre à la virgule flottante valide et représentable du type. À noter également que cette solution traite tous les caractères de fin y compris les caractères d'espacement, comme une condition d'erreur.



    Code C : 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
     
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
     
     
    /*
        Attention, le code source ci-dessous 
        est susceptible de comporter des erreurs.
    */
     
     
    bool f_get_numeric( long *dt ){
     
        char *p = NULL;
        char buffer[BUFSIZ];
     
        /* no crash test snip memset return */
        (void)memset(buffer, 0x0, BUFSIZ); 
     
        errno = 0x0;
        if( NULL == fgets(buffer, BUFSIZ, stdin) ){
            (void)fprintf(stderr, "Error(%d)\t:%s\n",
                errno, strerror(errno) );
            return false;
        }
     
        *dt = strtol(buffer, &p, 0xA);
        if( errno == ERANGE ){
            (void)fprintf(stderr, 
                "Error(%d)\t: valeur hors plage\n\t:%s\n",
                errno, strerror(errno) );
            return false;
        }else if( buffer == p ){
            (void)fprintf(stderr, "Erreur\t: Saisie no valid\n");
            return false;
        }else if('\n' != *p && '\0' != *p){
            (void)fprintf(stderr, 
                "Erreur\t: detection de caractere\n");
            return false; 
        }
        return true;
    }
     
     
    int main( void ){
        long dt = 0x0;
        if( false == f_get_numeric(&dt) )
            return EXIT_FAILURE;
        (void)fprintf(stderr, "(ret)\t:%ld\n", dt );
        return EXIT_SUCCESS;
    }


    à bientôt.

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

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

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 599
    Par défaut
    Bonjour,

    Dans les solutions simples pour résoudre le Retour Chariot qui reste dans le buffer de réception, il y la possibilité d'ajouter une espace à la fin de la chaîne de récupération.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     printf("Quel âge avez vous ? ");
            scanf("%d ", &ageutilisateur);  // note l'espace juste après le %d, il permet d'enlever le '\n' qui resterait
            printf("Vous avez donc %d ans \n", ageutilisateur);
            char lettre;
            printf("Choisissez une lettre :> ");
            scanf("%c ", &lettre); // note l'espace juste après le %c, ici aussi on enlève le '\n' de trop
            printf("La lettre choisie est :> %c", lettre );
    Attention, ça ne fonctionne que si l'opérateur tape exactement ce que l'on attend de lui (par exemple une simple entier suivi de CR si on attend un entier, ...) Pour les cas plus complexes, tu verras plus tard.

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 836
    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 836
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sambia39 Voir le message
    Attention, l'erreur n'est pas simplement due au fait que scanf doit avoir une entrée formatée avec exactitude/ s'assurer que la saisie effectuée au clavier par l'utilisateur devra être la même que celle spécifiée dans le format. Non ; c'est juste que la fonction scanf n'est absolument pas adaptée pour des entiers et où des nombres à virgule flottante à partir d'une d'entrée car, l'entrée en question peut contenir des nombres non représentables par le type d'argument voulu ou format attendu et c'est là où est réellement le problème et la difficulté de scanf.
    Pas ici. Ici il attend un entier, il tape "30" tout est ok. Il n'y a absolument aucun souci de nombre "non représentable".

    PS: Tu devrais écrire encore plus gros qu'on te voit mieux...

    Citation Envoyé par dalfab Voir le message
    Dans les solutions simples pour résoudre le Retour Chariot qui reste dans le buffer de réception, il y la possibilité d'ajouter une espace à la fin de la chaîne de récupération.
    Joli !!!
    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]

  6. #6
    Membre très actif
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Pas ici. Ici il attend un entier, il tape "30" tout est ok. Il n'y a absolument aucun souci de nombre "non représentable".

    PS: Tu devrais écrire encore plus gros qu'on te voit mieux...
    Joli !!!
    Non. Tout n'est pas Ok. Tu ne vois que le développeur qui apprend à utiliser la fonction scanf et non l'utilisateur qui utilise le programme et qui est susceptible d'effectuer une saisie erronée et l'astuce d'un espace après le "%d " est une fausse bonne idée.


    L'espace après "%d " dit à la fonction scanf de faire correspondre l'espace (ou le vide pour la compréhension) à zéro ou plusieurs caractères d'espacement, jusqu'à ce que la correspondance n'aboutisse pas/ échoue. Pour être plus précis scanf va tenter de faire correspondre les caractères d'espacement jusqu'à ce qu'il n'y ait plus de correspondance et en faisant cela, scanf ne retournera que si l'ensemble de la correspondance recherchée est réellement manquante ou que l'on atteint la fin du fichier en d'autres termes (scanf devient bloquante), a force d'attendre, vous allez devoir vider le buffer par vous-même selon votre système d'exploitation soit CTRL+D (GNU/ Linux ou Unix) ou CTRL+C (Windows) donc pas joli.


    PS: pour ce qui est de l'écriture, il doit avoir une erreur de police de caractères.

Discussions similaires

  1. [2012] Requête dateadd non fonctionelle
    Par sihem_info dans le forum Développement
    Réponses: 4
    Dernier message: 27/09/2016, 16h11
  2. Qu'est ce qu'une analyse fonctionelle
    Par sandrine dans le forum Débats sur le développement - Le Best Of
    Réponses: 22
    Dernier message: 28/02/2015, 19h03
  3. [AC-2003] Listes deroulantes dependantes non fonctionelles
    Par Dupont D'Isigny dans le forum IHM
    Réponses: 2
    Dernier message: 23/01/2014, 09h13
  4. Ancre sous opéra non fonctionelle
    Par pkpasutiliserlemail dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 07/11/2011, 20h31
  5. getchar et scanf : valeur non prise en compte
    Par Angelina007 dans le forum C
    Réponses: 8
    Dernier message: 25/10/2007, 13h47

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