Validating a character input in C

我的梦境 提交于 2021-02-05 12:23:17

问题


I have a project where I want to validate a character input in C. I am new to the C language and also not very experienced in programming. I have tried to make a loop for validation but it is not working.

#include<stdio.h>

void main(){
    char input;

    do {
        scanf("%c", &input);

        while ( (input != 'a') && (input != 'b') && (input != 'c') );
            printf ("wrong input");

    switch(input){

    case 'a':
        break;

    case 'b':
        break;

    case 'c':
        break;

    } while ( input != 'c');

回答1:


Taking user input in C, isn't difficult, but you must pay careful attention to what is being read, and what is left in stdin unread (which will bite you on your next input). One of the functions that gives new C-programmers fits is scanf(). It is full of many pitfalls. The pitfall relevant here is the use of the "%c" format specifier and any additional extraneous characters left in stdin.

The "%c" and "%[..]" conversion specifiers (and for @chux the "%n" specifier) do not ignore leading whitespace. This is a problem since pressing the Enter key generates a '\n' character in stdin. This means that if the user enters something other than 'a', 'b', or 'c', the next character to be read from stdin is '\n'. Unless you empty the '\n' from stdin before your next input with "%c", the '\n' character will be taken as the next input -- your code appearing to skip the next input. (it didn't skip anything -- the '\n' was waiting to be read -- so scanf() read it as input).

To avoid this problem, you can place a whitespace character (a space) before the " %c" format specifier which will cause scanf() to ignore any number of whitespace characters in sequence before the next non-whitespace character. Since a '\n' is whitespace, it will extract and discard the '\n' from stdin allowing your next character of input to be read.

But.... then you run into the next pitfall -- what if the user slips and enters "de" as input. That's leaves 'e' as an extraneous character left unread in stdin after the 'd' is read. A space won't help you ignore non-whitespace characters.

There is a Better Way -- Line-Oriented Input

Instead of reading a character-at-a-time from stdin, when taking user input, it is better to read a line-at-a-time with fgets() or POSIX getline(). That way, given a reasonably sized character array to hold the characters in the line, an entire line of input is consumed. There isn't any possibility of extraneous characters being left in stdin to bite you on your next input. And if you are interested in the first character input by the user, just check the first character in the array holding the line, e.g. array[0] or simply *array.

All user-input can, and should be taken with a line-oriented input function. If you need to convert parts of the line into separate values, then you can use sscanf() or a string processing function like strtok(), etc.. The benefit is you can separately validate the read of the input and then the conversion of values.

How to Require Certain Input

The approach to requiring the user to enter specific input is straight-forward. You simply loop continually prompting for, and reading and validating the user input, until the user provides the requested input. If valid input is provided, you simply break; the read-loop. If an invalid input is received, you simply output an error and loop again until you get the input you require.

A short example for your case would be:

#include <stdio.h>

#define MAXC 1024       /* if you need a constant, #define one (max chars per-line) */

int main (void) {
    
    char line[MAXC];    /* declare buffer to hold each line of input */
    
    while (1) {         /* loop continually until the user provides valid input */
        fputs ("\nenter a, b or c : ", stdout);         /* prompt for input */
        
        if (fgets (line, MAXC, stdin) == NULL) {        /* read entire line */
            puts ("(user canceled input)");             /* handle manual EOF */
            return 0;
        }
        
        /* check 1st char in array to see if it is valid, if so, break loop */
        if (line[0] == 'a' || line[0] == 'b' || line[0] == 'c')
            break;
        
        /* otherwise, invalid input provided, throw error -- repeat */
        fputs ("  error: invalid input, not 'a', 'b' or 'c'\n", stderr);
    }
    
    printf ("\nyou entered: '%c'\n", *line);    /* output value */
}

The approach is just as described:

  1. loop continually,
  2. prompt for input,
  3. read and validate the input, allowing the user to cancel input by generating a manual EOF with Ctrl + d (or Ctrl + z on windows) and gracefully exit if they do.
  4. test the input against your criteria, an 'a', 'b' or 'c', and if you get good input, break; the read-loop, and finally
  5. on invalid input, handle the error and repeat the process until you get the required input.

(note: unless you are programming a micro-controller in a freestanding environment (without any OS), then the proper invocations of main() are int main (void) and int main (int argc, char *argv[]) (which you will see written with the equivalent char **argv). See: C11 Standard - §5.1.2.2.1 Program startup(p1). See also: What should main() return in C and C++?)

Example Use/Output

With any input routine you write, when you are done -- go try and break it. Test it thoroughly. Think of all the dumb things a user might do and see if your code handles it correctly. If it fails, go fix it and try again. For example:

$ ./bin/fgetschar_abc

enter a, b or c : My dog has fleas!
  error: invalid input, not 'a', 'b' or 'c'

enter a, b or c : Cat has none!
  error: invalid input, not 'a', 'b' or 'c'

enter a, b or c : Lucky cat!
  error: invalid input, not 'a', 'b' or 'c'

enter a, b or c : Okay, okay!
  error: invalid input, not 'a', 'b' or 'c'

enter a, b or c : b

you entered: 'b'

(try entering multiple characters with your current code and see what happens...)

Now you can add your switch() statement and be assured that the only character that is the first character in line (e.g. line[0], or just *line) is an 'a', 'b' or 'c'. If you prefer to have a single character variable rather than using the first character in line, then just assign the first character in line to your variable, e.g.

char input = line[0];

Implementing the switch() is left to you. Let me know if you have any additional question.



来源:https://stackoverflow.com/questions/64673688/validating-a-character-input-in-c

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