我有一个项目,我想验证 C 中的字符输入。我是C语言的新手,在编程方面也不是很有经验。我试图创建一个循环进行验证,但它不起作用。
#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');
在 C 中获取用户输入并不困难,但您必须仔细注意正在读取的内容,以及未读stdin
的内容(这会在下次输入时咬你)。使新的C程序员适合的功能之一是scanf()
。它充满了许多陷阱。这里相关的陷阱是使用"%c"
格式说明符和stdin
中留下的任何其他无关字符。
"%c"
和"%[..]"
转换说明符(对于@chux"%n"
说明符)不会忽略前导空格。这是一个问题,因为按Enter键会在stdin
中生成一个'n'
字符。这意味着如果用户输入'a'
、'b'
或'c'
以外的内容,则从stdin
中读取的下一个字符是'n'
。除非您在下一次输入之前stdin
清空'n'
"%c"
,否则'n'
字符将被视为下一个输入 - 您的代码似乎跳过下一个输入。(它没有跳过任何内容 -'n'
正在等待读取 - 所以scanf()
将其作为输入读取)。
若要避免此问题,可以在" %c"
格式说明符之前放置一个空格字符 (space
),这将导致scanf()
忽略下一个非空格字符之前的任意数量的空格字符。由于'n'
是空格,它将从stdin
中提取并丢弃'n'
,从而读取输入的下一个字符。
但。。。。然后你会遇到下一个陷阱 - 如果用户滑倒并输入"de"
作为输入怎么办。这使得'e'
在阅读'd'
后stdin
中未被读取的无关字符。空格不会帮助您忽略非空格字符。
有更好的方法 -- 面向线的输入
与其一次从stdin
中读取一个字符,不如在接受用户输入时,最好使用fgets()
或 POSIXgetline()
一次读取一行。这样,给定一个大小合理的字符数组来保存行中的字符,则会消耗整行输入。stdin
中不可能留下无关的字符来咬你下一次输入。如果您对用户输入的第一个字符感兴趣,只需检查数组中保存该行的第一个字符,例如array[0]
或干脆*array
.
所有用户输入都可以,并且应该使用面向行的输入函数。如果需要将行的一部分转换为单独的值,则可以使用sscanf()
或字符串处理函数,例如strtok()
等。好处是您可以分别验证输入的读取,然后验证值的转换。
如何要求某些输入
要求用户输入特定输入的方法很简单。您只需循环不断提示,读取和验证用户输入,直到用户提供请求的输入。如果提供了有效的输入,您只需break;
读取循环。如果收到无效输入,您只需输出错误并再次循环,直到获得所需的输入。
您的案例的一个简短示例是:
#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 */
}
该方法如前所述:
- 循环不断,
- 提示输入,
- 读取并验证输入,允许用户通过使用 Ctrl +d(或在 Windows 上生成手动
EOF
(或在 Windows 上生成Ctrl + z)来取消输入,并在这样做时正常退出。 - 根据您的标准、
'a'
、'b'
或'c'
测试输入,如果得到良好的输入,break;
读取循环,最后 - 在无效输入时,处理错误并重复该过程,直到获得所需的输入。
(注意:除非您在独立环境(没有任何操作系统)中对微控制器进行编程,否则main()
的正确调用是int main (void)
和int main (int argc, char *argv[])
(您将看到使用等效char **argv
编写)。 参见:C11 标准 - §5.1.2.2.1 程序启动(p1)。另请参阅:main() 在 C 和 C++ 中应该返回什么?
示例使用/输出
对于你编写的任何输入例程,当你完成时 - 去尝试打破它。彻底测试它。想想用户可能做的所有愚蠢的事情,看看你的代码是否正确处理它。如果失败,请修复它并重试。例如:
$ ./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'
(尝试使用当前代码输入多个字符,看看会发生什么...
现在,您可以添加switch()
语句,并确保line
中唯一的字符是第一个字符(例如line[0]
,或简称*line
)是一个'a'
、'b'
或'c'
。如果您更喜欢使用单个字符变量而不是使用line
中的第一个字符,那么只需将line
中的第一个字符分配给您的变量,例如
char input = line[0];
实施switch()
由您决定。如果您有任何其他问题,请告诉我。