C: scanf input single character and validation

江枫思渺然 提交于 2021-02-20 04:52:02

问题


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:

  1. putting a white space before/after %c like:

    scanf(" %c", &c);
    
  2. 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 use while(c != 'A' && c != 'P') instead
  • No need for two scanf if you use do..while loop
  • After entering a char with scanf it is recommended to clean all characters from buffer, e.g. with while(getchar()!='\n'); (this will clean all input including incorrect and redundant characters)
  • use toupper to avoid making 4 comparison (actually single c=toupper(c) inside loop can minimize your while as while(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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!