Partage
  • Partager sur Facebook
  • Partager sur Twitter

Validité des entrées avec scanf

Question sur un code du tuto C du sdz

    3 avril 2022 à 20:53:18

    Bonsoir, dans les archives du tuto C à l'époque du sdz, j'aurais une question quand à ce code-ci :

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(int argc, char *argv[])
    {
      int choixMenu;
      
      printf("=== Menu ===\n\n");
      printf("1. Royal Cheese\n");
      printf("2. Mc Deluxe\n");
      printf("3. Mc Bacon\n");
      printf("4. Big Mac\n");
      printf("\nVotre choix ? ");
      scanf("%d", &choixMenu);
      
      printf("\n");
      
      switch (choixMenu)
      {
        case 1:
           printf("Vous avez choisi le Royal Cheese. Bon choix !");
           break;
        case 2:
           printf("Vous avez choisi le Mc Deluxe. Berk, trop de sauce...");
           break;
        case 3:
           printf("Vous avez choisi le Mc Bacon. Bon, ca passe encore ca ;o)");
           break;
        case 4:
           printf("Vous avez choisi le Big Mac. Vous devez avoir tres faim !");
           break;
        default:
           printf("Vous n'avez pas rentre un nombre correct. Vous ne mangerez rien du tout !");
           break;
      }
      
      printf("\n\n");
      
      return 0;
    }

    Si l'utilisateur entre une chaîne de caractère au lieu d'un nombre, choixMenu peut très bien (même si très peu probable) valoir 1, 2, 3 ou 4 non ?

    Dans ce cas, la sortie serait incorrecte, ne vaudrait-il pas mieux tester la valeur de retour de scanf avant le switch pour vérifier si l'entrée est un nombre ?

    • Partager sur Facebook
    • Partager sur Twitter
      3 avril 2022 à 21:03:20

      Chi_Iroh a écrit:

      Si l'utilisateur entre une chaîne de caractère au lieu d'un nombre, choixMenu peut très bien (même si très peu probable) valoir 1, 2, 3 ou 4 non ?

      Tu n'as pas essayé ?

      #include <stdio.h>
      
      int main(void)
      {
          int choixMenu = 123;
      
          scanf("%d", &choixMenu);
      
          printf("%d\n", choixMenu);
      
          return 0;
      }

      En donnant bien sûr une valeur initiale à la variable en question.


      • Partager sur Facebook
      • Partager sur Twitter
        3 avril 2022 à 21:11:29

        Oui, je sais qu'en initialisant manuellement avec 0 ou 123 par exemple c'est bon, mais dans ce code-là choixMenu n'est pas initialisé, donc sa valeur est  aléatoire non ?
        • Partager sur Facebook
        • Partager sur Twitter
          3 avril 2022 à 22:21:26

          Chi_Iroh a écrit:

          Oui, je sais qu'en initialisant manuellement avec 0 ou 123 par exemple c'est bon, mais dans ce code-là choixMenu n'est pas initialisé, donc sa valeur est  aléatoire non ?

          Oui et tenter d'y lire une valeur plus loin est un undefined behavior.

          Si la saisie n'est pas numérique, le scanf() échoue et l'entier est inchangé.
          Le prochain scanf() pourra lire le texte si "%s" "%c" ou "%[]", mais veut aussi lire un numérique, le codera continuera jusqu'au prochain scanf() texte.
          Autrement dit : on ne peut pas utiliser scanf() de manière saine si l'opérateur n'entre pas ce que l'on attend de lui!

          • Partager sur Facebook
          • Partager sur Twitter

          En recherche d'emploi.

            3 avril 2022 à 22:28:16

            Si une variable n'est pas initialisée, effectivement sa valeur est "aléatoire" (En fait, elle contient ce que la mémoire qui lui est réservé contenait avant sa réservation).

            Chi_Iroh a écrit:

            Dans ce cas, la sortie serait incorrecte, ne vaudrait-il pas mieux tester la valeur de retour de scanf avant le switch pour vérifier si l'entrée est un nombre ?

            Oui, c'est une solution.

            • Partager sur Facebook
            • Partager sur Twitter
              4 avril 2022 à 1:32:29

              Ou tu pourrais lire le texte avec fgets() et valider si la chaîne est bien composée de chiffres.
              Et tu as différents moyens de convertir en nombre.

              #include <stdio.h>
              #include <string.h>
              int main(void){
                  char entree[100];
                  fgets(entree, 100, stdin);
                  printf("%s", entree);
                  char *endl = strchr(entree, '\n');
                  if(endl) *endl = '\0';
                  // Je vérifie que ce ne sont que des chiffres.
                  int nombre;
                  sscanf(entree, "%d", &nombre);
                  printf("%d\n", nombre);
              }
              Je pense que pour avoir le nombre 1 en tapant un "caractère", il faut taper Control+A

              Je pense que le std::cin de C++ te causerait le même problème.

              Et c'est plus catastrophique en Python ... :)

              -
              Edité par PierrotLeFou 4 avril 2022 à 4:09:06

              • Partager sur Facebook
              • Partager sur Twitter

              Le Tout est souvent plus grand que la somme de ses parties.

                4 avril 2022 à 8:43:30

                Ce cours est obsolète.

                Concernant scanf, c'est fait pour lire de l'entrée correctement formatée, pas celle de l'utilisateur. Le seul moyen de lire « correctement » c'est de lire une ligne entière (avec fgets) et de l'analyser (quand on souhaite lire ligne par ligne, usuellement ce qu'on fait avec des prompts en terminal).

                -
                Edité par markand 4 avril 2022 à 8:44:47

                • Partager sur Facebook
                • Partager sur Twitter

                l'azerty est aux dispositions ce que subversion est aux SCM

                  4 avril 2022 à 11:58:36

                  Si tu veux resté sur scanf, tu peux nettoyer le buffer clavier avant de redemander une nouvelle saisie :

                  #include <stdio.h>
                  
                  void fflush_stdin(void)
                  {
                      int c;
                      while ((c = getchar()) != EOF && c != '\n');
                  }
                  
                  int main(void)
                  {
                      int choix;
                      printf("votre saisie : ");
                      while(scanf("%d", &choix)!=1)
                      {
                          fflush_stdin();
                          printf("vous devez saisir un nombre : ");
                      }
                  
                      printf("%d\n", choix);
                  
                      return 0;
                  }

                  -
                  Edité par rouIoude 4 avril 2022 à 11:59:27

                  • Partager sur Facebook
                  • Partager sur Twitter
                    5 avril 2022 à 0:00:13

                    Salut,

                    Le scanf, c'est pour soi. Si tu te fais un petit truc vite fait avec lequel tu ne joueras pas au con. Si l'utilisateur est tierce, il faut toujours partir de l'idée que ce sera un crétin fini et qu'il répondra 4587.325 quand on lui demandera son plat favori et "Lune" à "10-5 = ?".

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Bonhomme !! | Jeu de plateforme : Prototype.

                      5 avril 2022 à 0:39:55

                      drx a écrit:

                      Si l'utilisateur est tierce, il faut toujours partir de l'idée que ce sera un crétin fini et qu'il répondra 4587.325 quand on lui demandera son plat favori

                      Avec fgets, il peux aussi répondre cela !

                      drx a écrit:

                      "Lune" à "10-5 = ?".

                      idem !

                      scanf est aussi capable de gérer ces cas, avec du code en aval.

                      Ou il faut être attentif avec scanf, c'est pour les chaînes de caractère, à ne pas aller écrire en dehors du tableau de char qui réceptionne les caractères. Dans ce cas on peux effectivement privilégier fgets, mais il faut savoir que scanf est aussi capable de limiter le nombre de caractère qui seront mis dans le tableau de réception.



                      • Partager sur Facebook
                      • Partager sur Twitter

                      Validité des entrées avec scanf

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      • Editeur
                      • Markdown