0

I have written a program that asks a user to input a character A, B or C. If the user enters another character, it outputs the message and asks the user to input character again. User enters the character two times. It outputs the message two times. How can I fix this problem?

char player1, player2;

do
{
    printf("Enter Player 1 choice ('A','B','C') \n");

    scanf("%c", &player1);

    if(player1 != 'A' && player1 != 'B' && player1 != 'C')
    {
        printf("Invalid input! \n");
    }
   
} while (player1 != 'A' && player1 != 'B' && player1 != 'C');


do
{
    printf("Enter Player 2 choice ('A','B','C') \n");

    scanf("%c", &player2);

    if(player2 != 'A' && player2 != 'B' && player2 != 'C'){

        printf("Invalid input! \n");
    }
    
} while (player2 != 'A' && player2 != 'B' && player2 != 'C');


return 0;

1 Answers1

1

this is due to the buffer, when the user enters 1 char like A for example then presses enter, what is stored in the buffer is A\n, which are 2 characters. if the user enters 2 chars like A then K then press enter, what is stored in the buffer is AK\n, when you use scanf, it will read only the first char which is A then it will leave the other characters in the buffer. then you have to flush your buffer, you can use fflush(stdin); to do that but it's UB (undefined behavior and not portable) for most compilers, the other way to do that is to use the fgets method with a dummy char array, so instead of writing :

scanf("%c", &player1);

you can write

scanf("%c", &player1);

fgets(dummyBuffer, sizeof(dummyBuffer), stdin);

where dummyBuffer is a dummy char buffer defined at the beginning. and you can use it to clear your buffer.

and here is the full code with this only small modification:

#include <stdio.h>

int main(void){
    char player1, player2;
    char dummyBuffer[20];

    do
    {
        printf("Enter Player 1 choice ('A','B','C') \n");

        scanf("%c", &player1);

        fgets(dummyBuffer, sizeof(dummyBuffer), stdin);

        if(player1 != 'A' && player1 != 'B' && player1 != 'C')
        {
            printf("Invalid input! \n");
        }

    } while (player1 != 'A' && player1 != 'B' && player1 != 'C');


    do
    {
        printf("Enter Player 2 choice ('A','B','C') \n");

        scanf("%c", &player2);

        fgets(dummyBuffer, sizeof(dummyBuffer), stdin);

        if(player2 != 'A' && player2 != 'B' && player2 != 'C'){

            printf("Invalid input! \n");
        }

    } while (player2 != 'A' && player2 != 'B' && player2 != 'C');


    return 0;
}

and this is the output:

Enter Player 1 choice ('A','B','C')
D
Invalid input!
Enter Player 1 choice ('A','B','C')
A
Enter Player 2 choice ('A','B','C')
K
Invalid input!
Enter Player 2 choice ('A','B','C')
B
abdo Salm
  • 1,678
  • 4
  • 12
  • 22
  • 1
    You could also make player a string, use only fgets() and check if *player == ... (no more scanf) – Déjà vu Sep 24 '22 at 16:46
  • If you use `fgets` to consume the rest of the line, you have to worry about the size of the buffer. Better to use `fgetc` in a loop, or something like `scanf("%*[^\n]%*c");` – HAL9000 Sep 24 '22 at 16:55
  • 1
    [Don't use `fflush(stdin)`](https://stackoverflow.com/questions/2979209/using-fflushstdin). It is undefined behavior _per the Standard_; though it does work occasionally it is not portable. Instead use the idiomatic `int c; while ((c = getchar()) != '\n' && c != EOF) continue;` after calling `scanf` to clear the input stream. – ad absurdum Sep 24 '22 at 17:04
  • 1
    Robust code needs to check whether an entire line was read by `fgets`. It is OK for toy code to avoid this complication, but still it is easy to improve even toy programs. Here, if a user enters more than 19 characters the code will misbehave. Better to use a generous size for `dummyBuffer`, e.g., `char dummyBuffer[1024] = { 0 };`. This ensures that longer erroneous input can be handled. – ad absurdum Sep 24 '22 at 17:15
  • 1
    @HAL9000 Or just plain `scanf(" %c", ...)` to have `scanf` automatically skip over and white-space, including newline. Or simply forget that `scanf` even exist, and use `fgets` and parse the string in an appropriate way (perhaps with `sscanf`, but then remember to always check what it [*returns*](https://en.cppreference.com/w/c/io/fscanf#Return_value)). – Some programmer dude Sep 24 '22 at 20:48