0

I am experiencing a strange behaviour of while loop in the following program.

#include <stdio.h>

int main ()
{

    char confirm;

    printf("Do you want to proceed? (Y/N):\n");
    scanf(" %c", &confirm);
    while (confirm != 'Y' && confirm != 'y' && confirm != 'N' && confirm != 'n')
    {
         printf("Please enter a valid answer (Y/N):\n");
         scanf(" %c", &confirm);
    }
 return 0;
}

Basically, I want the program only to accept 'Y', 'N', 'y' or 'n' characters. The above code works but when I enter a string as input, it prints "Please enter a valid answer (Y/N):" as many times as the characters of the string. Something like below:

Do you want to proceed? (Y/N):
a
Please enter a valid answer (Y/N):
adsfaf
Please enter a valid answer (Y/N):
Please enter a valid answer (Y/N):
Please enter a valid answer (Y/N):
Please enter a valid answer (Y/N):
Please enter a valid answer (Y/N):
Please enter a valid answer (Y/N):

How can I get rid of this. Can somebody help?

3
  • You might be better off reading an entire line rather than a single character. You can use fgets to read a line of input. Commented Jun 19, 2020 at 5:54
  • Just a guess: what about the whitespae in front of ` %C` in scanf Commented Jun 19, 2020 at 6:31
  • @Mike it will not help, removing whitespace will read the newline character I guess. Commented Jun 19, 2020 at 6:40

2 Answers 2

2

scanf() takes the input that matches the format string, returning the number of characters consumed. Any character that doesn't match the format causes it to stop scanning and leaves the invalid character still in the buffer.

To let the strange not happen, the possible ways to fix this issues:

  1. Use fgets() to take the string and compare - recommended.
  2. Use fflush(stdin) - not recommended.

Aside: Use int confirm rather than using char for it. The reason is:

A char is required to accept all values between 0 and 127 (included). So in common environments it occupies exactly one byte (8 bits). It is unspecified by the standard whether it is signed (-128 - 127) or unsigned (0 - 255).

An int is required to be at least a 16 bits signed word, and to accept all values between -32767 and 32767. That means that an int can accept all values from a char, be the latter signed or unsigned.

Note: You may use char confirm when you specifically needs to store characters.

Reference: Difference between char and int when declaring character.

Example 1 (recommended):

#include <stdio.h>
#define MAX_LENGTH 100

int main(void) {
    char confirm[MAX_LENGTH];

    printf("Enter a valid command (Y/N): ");
    fgets(confirm, MAX_LENGTH, stdin); // using fgets() here

    while (confirm[0] != 'Y' && confirm[0] != 'y' \
           && confirm[0] != 'N' && confirm[0] != 'n') {

        printf("Please enter a valid answer (Y/N): ");
        fgets(confirm, MAX_LENGTH, stdin); // using fgets() here
    }

    return 0;
}

Expected sample output should be:

$ gcc -o prog prog.c; ./prog
Enter a valid command (Y/N): asdf
Please enter a valid answer (Y/N): asdlfasdf asdf a
Please enter a valid answer (Y/N): 234
Please enter a valid answer (Y/N): n

Example 2:

Do something like:

while (...)
{
     printf("Please enter a valid answer (Y/N):\n");
     fflush(stdin);
     scanf(" %c", &confirm);
}

Then you may expect this output:

Do you want to proceed? (Y/N):
d
Please enter a valid answer (Y/N):
asdf
Please enter a valid answer (Y/N):
asdfasd
Please enter a valid answer (Y/N):
n
Sign up to request clarification or add additional context in comments.

11 Comments

The value of confirm is only used to compare with character constants. They should be pretty well in range for a char on any implementation.
Also your linked reference tells: "If you want to store only characters in a variable, you should declare it as char. Using an int would just waste memory, and could mislead a future reader." What is the point of using int here?
It's much better to simply read a line rather than flushing stdin, which is almost always a bad idea.
Well, I find it rather strange to suggest some change that does not apply to the question at all. It would apply if there was some fgetc involved. BTW: What will happen if you use int together with %c as you suggest? 3 bytes of the int will not be updated at all.
@Gerhardh The point of answering a question on stack overflow is to show the best way to solve a problem. This question was about fgets in the sense that an experienced C programmer would recognize that's the best way to solve it. Often a literal answer to a specific question only serves to lead OP further down the wrong path, such as flushing stdin. Regarding the data type of confirm, you're right, it needs to be char if used as it is with scanf. With getchar you would use an int.
|
0

I tried the following. Don't know whether it is a good approach, but it works.

#include <stdio.h>

int main ()
{
    char confirm[256];

    printf("Do you want to proceed? (Y/N):\n");
    scanf("%256s", confirm);
    while (confirm[0] != 'Y' && confirm[0] != 'y' && confirm[0] != 'N' && confirm[0] != 'n')
    {
         printf("Please enter a valid answer (Y/N):\n");
         scanf("%256s", confirm);
    }

printf("%s\n", confirm);
}

give the output

Do you want to proceed? (Y/N):
somestring
Please enter a valid answer (Y/N):
234234
Please enter a valid answer (Y/N):
YES
YES

1 Comment

Edit: if the input is "some string" then line "Please enter a valid answer (Y/N):" appears two times.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.