web-dev-qa-db-fra.com

C: plusieurs scanf, lorsque j'entre une valeur pour un scanf, il saute le second scanf

J'ai ce bloc de code (fonctions omises car la logique fait partie d'un devoir):

#include <stdio.h>

int main()
{
    char c = 'q';
    int size; 

    printf("\nShape (l/s/t):");
    scanf("%c",&c);

    printf("Length:"); 
    scanf("%d",&size);

    while(c!='q')
    {
        switch(c)
        {
            case 'l': line(size); break; 
            case 's': square(size); break;
            case 't': triangle(size); break; 
        }


        printf("\nShape (l/s/t):");
        scanf("%c",&c);

        printf("\nLength:"); 
        scanf("%d",&size);
    }

    return 0; 
}

Les deux premiers Scanf fonctionnent très bien, pas de problème une fois que nous entrons dans la boucle while, j'ai un problème où, lorsque vous êtes censé être invité à entrer un nouveau caractère de forme, il saute à la place vers le printf de Longueur et attend de prendre une entrée à partir de là pour un caractère, puis plus tard une décimale à la prochaine itération de la boucle.

Itération pré-boucle:

Scanf: Forme. Fonctionne très bien
Scanf: Longueur. Aucun problème

Boucle 1.

Scanf: Forme. Ignore ce
Scanf: longueur. Problème, ce scanf est mappé au caractère de forme.

Boucle 2
Scanf: Forme. Ignore ce
Scanf: longueur. Problème, ce scanf correspond maintenant à la taille int.

Pourquoi ça fait ça?

20
Snow_Mac

scanf("%c") lit le caractère de nouvelle ligne dans le ENTER clé.

Lorsque vous tapez, disons 15, Vous tapez un 1, Un 5, Puis appuyez sur la touche ENTER clé. Il y a donc maintenant trois caractères dans le tampon d'entrée. scanf("%d") lit le 1 et le 5, les interprétant comme le nombre 15, mais le caractère de nouvelle ligne est toujours dans le tampon d'entrée. La scanf("%c") lira immédiatement ce caractère de nouvelle ligne, et le programme passera ensuite à la scanf("%d") suivante, et attendra que vous entriez un nombre.

Le conseil habituel est de lire des lignes entières d'entrée avec fgets et d'interpréter le contenu de chaque ligne dans une étape distincte. Une solution plus simple à votre problème immédiat consiste à ajouter une getchar() après chaque scanf("%d").

38

Le problème de base est que scanf() quitte la nouvelle ligne après le numéro dans le tampon, puis le lit avec %c Lors de la passe suivante. En fait, c'est une bonne démonstration de pourquoi je n'utilise pas scanf(); J'utilise un lecteur de ligne (fgets(), par exemple) et sscanf(). C'est plus facile à contrôler.

Vous pouvez probablement le sauver en utilisant " %c" Au lieu de "%c" Pour la chaîne de format. Le blanc fait que scanf() saute les espaces blancs (y compris les retours à la ligne) avant de lire le caractère.

Mais il sera plus facile à long terme d'abandonner scanf() et fscanf() et d'utiliser fgets() ou équivalent plus sscanf(). En dehors de tout cela, le rapport d'erreurs est beaucoup plus facile lorsque vous avez toute la chaîne avec laquelle travailler, pas les driblets laissés par scanf() après son échec.

Vous devez également, toujours, vérifier que vous obtenez une valeur convertie à partir de scanf(). L'entrée échoue - régulièrement et horriblement. Ne le laissez pas détruire votre programme parce que vous n'avez pas vérifié.

19
Jonathan Leffler

Utilisez la fonction

void seek_to_next_line( void )
{
    int c;
    while( (c = fgetc( stdin )) != EOF && c != '\n' );
}

pour effacer votre tampon d'entrée.

6
noMAD

Essayez d'ajouter un espace dans le scanf.

scanf(" %d", &var);
//     ^
//   there

Cela entraînera scanf() pour éliminer tous les espaces blancs avant de faire correspondre un entier.

5
Jon Z.

Le caractère '\n' Est toujours laissé dans le flux d'entrée une fois le premier appel à scanf terminé, donc le deuxième appel à scanf() le lit. Utilisez getchar().

2
Gargi Srinivas

Lorsque vous tapez la forme et ENTRÉE, la forme est consommée par le premier scanf, mais la touche ENTREE ne l'est pas! Le deuxième scanf attend un nombre. L'entrée est ignorée car considérée comme un espace blanc et le scanf attend une entrée valide (un nombre) qui, là encore, se termine par l'entrée. Eh bien, le nombre est consommé, mais l'entrée n'est pas, donc le premier scanf à l'intérieur du temps l'utilise et votre invite de forme est ignorée ... ce processus se répète. Vous devez ajouter un autre% c dans les scanfs pour gérer la touche ENTER. J'espère que ça aide!

1
guga

Vous pouvez également utiliser scanf("%c%*c", &c); pour lire deux caractères et ignorer le dernier (dans ce cas '\ n')

0
Byeonggon Lee