问题
I've encountered a problem when validating a single-char scanf input in C and I cannot find an existing solution that works...
The scenario is: a method is taking a single letter 'char' type input and then validating this input, if the criteria is not met, then pops an error message and re-enter, otherwise return this character value.
my code is:
char GetStuff(void)
{
char c;
scanf("%c", &c);
while(c != 'A' || c != 'P')
{
printf("invalid input, enter again (A for AM or P for PM): ");
scanf ("%c", &dtChar);
}
return c;
}
however, i got the infinite loop of error message no matter what input I type in. I read some other posts and guess it's the problem that %c specifier does no automatically get rid of the newline when I hit enter, and so far I have tried:
putting a white space before/after %c like:
scanf(" %c", &c);
write a separate method or include in this
GetStuff
method to clean the newline like:void cleanBuffer(){ int n; while((n = getchar()) != EOF && n != '\n' ); }
Can anyone help me with this problem please? Thank you in advance.
回答1:
#include <stdio.h>
char GetStuff(void) {
char c;
scanf("%c", &c);
getchar();
while ((c != 'A') && (c != 'a') && (c != 'P') && (c != 'p')) {
printf("invalid input, enter again (A for AM or P for PM): ");
scanf ("%c", &c);
getchar();
}
return c;
}
int main(void) {
printf("Calling GetStuff()...\n");
char x = GetStuff();
printf("User entered %c\n", x);
return 0;
}
You are using while (c != 'A' || c != 'P')
as your loop conditional, but this will always return true. What you meant to use is the && "and" operator, instead of the || "or" operator.
Also, call getchar()
after your scanf statements, to capture the newline. This should work the way you want it to.
回答2:
Inside loop you are taking input in dtChar
but your loop condition checks variable c
which is not updated in the loop, that is causing infinite loop
Also you would change your condition
while(c != 'A' || c != 'P')
to
while(c != 'A' && c != 'P')
If you want user to enter either 'A' or 'P'
回答3:
Please consider the following snippet:
#include <stdio.h>
#include <ctype.h>
char GetStuff(void)
{
char c;
do {
printf("Please enter A for AM or P for PM: ");
scanf ("%c", &c);
// clean input buffer (till the end of line)
while(getchar()!='\n');
} while(toupper(c) != 'A' && toupper(c) != 'P');
return c;
}
int main(void)
{
printf("Your input is'%c'\n", GetStuff());
return 0;
}
Note the points:
- condition
while(c != 'A' || c != 'P')
will be always true (just because one character cannot be 'A' and 'P' at the same time), so usewhile(c != 'A' && c != 'P')
instead - No need for two
scanf
if you usedo..while
loop - After entering a char with
scanf
it is recommended to clean all characters from buffer, e.g. withwhile(getchar()!='\n');
(this will clean all input including incorrect and redundant characters) - use
toupper
to avoid making 4 comparison (actually singlec=toupper(c)
inside loop can minimize your while aswhile(c != 'A' && c != 'P')
)
UPDATE:
To add message "Invalid input" and adding some other useful improvement subjected befor... new code is as:
#include <stdio.h>
#include <ctype.h>
void CleanBuffer(){
int n;
while((n = getchar()) != EOF && n != '\n' );
}
char GetStuff(void)
{
char c;
do {
printf("Please enter A for AM or P for PM: ");
scanf (" %c", &c);
c = toupper(c); // here letter become uppercase
CleanBuffer();
} while( (c != 'A' && c != 'P')?printf("Invalid input! "):0 );
return c;
}
int main(void)
{
printf("You have entered: %c\n", GetStuff());
return 0;
}
Note: function will return 'A' or 'P' in uppercase, so if this is not needed change the code as in example before update (use two toupper
and do not change c
after scanf
). Also you can use tolower
as an option (of course with comparing to 'a'
and 'p'
).
回答4:
Another possible solution. As others mentioned the condition was to be done with &&. Anyway the big problem is how to remove what's left on the console input line. Since the console works by lines, we remove everything up to the next '\n'
. If the user already left something on the input line before calling GetStuff()
, it would be useful to add a call to SkipRestOfTheLine()
before the while loop.
In general I suggest to start with a while(1)
loop, before making it nicer (such as in the cleanBuffer()
you posted).
#include <stdlib.h>
#include <stdio.h>
void SkipRestOfTheLine(void)
{
while (1) {
int c = fgetc(stdin);
if (c == EOF || c == '\n')
break;
}
}
char GetStuff(void)
{
while (1) {
int c = fgetc(stdin);
if (c == EOF)
exit(EXIT_FAILURE); // Deal with this case in an appropriate way
if (c == 'A' || c == 'P')
return c;
printf("invalid input, enter again (A for AM or P for PM): ");
SkipRestOfTheLine();
}
}
int main(void)
{
char c = GetStuff();
return 0;
}
回答5:
try this,
char GetStuff(void)
{
char c;
scanf("%c", &c);
while (((c != 'A') || (c != 'a')) && ((c != 'P') || (c != 'p'))==1)
{
printf("invalid input, enter again (A for AM or P for PM): ");
scanf ("%c", &dtChar);
}
return c;
}
I hope this works, some time because of not given proper bracket it is stuck in the loop.
来源:https://stackoverflow.com/questions/47862201/c-scanf-input-single-character-and-validation