在使用getchar() 时,您作为 C 程序员的主要工作是考虑输入缓冲区中的所有字符。当您输入a 并按Return 时,getchar(); 读取'a',但将按Return 生成的'\n' 留在输入缓冲区stdin。在循环的下一次旅行中,代码似乎绕过任何提示而无需等待输入 -- 为什么?,因为 getchar() 已经有一个字符了等待阅读——'\n'。
因此,任何这些面向字符的输入问题,您都必须戴上会计的帽子,并考虑stdin中留下的每个字符。有几种方法可以做到这一点。 Paxdiablo 展示了一个非常好的方法。另一种类似的方法利用辅助函数读取并丢弃stdin 中保留的所有字符。例如,如果您打算输入'a',但一只猫踩到了键盘,将"asdfdeeees" 留在了输入缓冲区中,则在读取'a' 之后,以下字符仍然是"sdfdeeees\n"。您需要一种简单的方法来丢弃所有剩余的字符。
下面提供了一个名为empty_stdin 的简单辅助函数,通过不断读取直到遇到'\n' 或EOF(它可以返回最后一个字符(或EOF)以允许检查供用户在 Linux 上使用 Ctrl + D 或在windoze 上使用 Ctrl + Z 手动取消输入。
#include <stdio.h>
/* helper function - empty all chars that remain in stdin */
int empty_stdin()
{
int c = getchar(); /* get 1st char remaining in stdin */
while (c != '\n' && c != EOF) /* while not '\n' or EOF, get next */
c = getchar();
return c;
}
int main (void) {
while (1) { /* infinite loop for input */
int c;
printf ("Enter a character (press q to exit): ");
c = getchar(); /* read character */
if (c == '\n') /* is it a newline? */
continue; /* if so, continue */
if (c == EOF) { /* end-of-file, from ctrl+d, or ctrl+z (windoze) */
putchar ('\n'); /* tidy up with \n */
break; /* bail */
}
if (c == 'q') /* did user quit? */
break; /* bail */
printf ("'%c' is integer: %d\n", c, c);
if (empty_stdin() == EOF) {
putchar ('\n'); /* tidy up with \n */
break;
}
}
return 0;
}
使用/输出示例
以下是一个会话的输出,其中单个字符、多个字符(根本没有字符,只需按 Return 即可,并且可以毫无问题地处理每种可能的情况:
$ ./bin/getchar_min
Enter a character (press q to exit): A
'A' is integer: 65
Enter a character (press q to exit): BC and other stuff
'B' is integer: 66
Enter a character (press q to exit):
Enter a character (press q to exit): Z
'Z' is integer: 90
Enter a character (press q to exit): a
'a' is integer: 97
Enter a character (press q to exit): z
'z' is integer: 122
Enter a character (press q to exit): Q
'Q' is integer: 81
Enter a character (press q to exit): q
查看所有问题,查看所有答案,然后戴上会计师的帽子。看看每一个是如何成功的,在再次提示输入更多输入之前考虑缓冲区中的所有字符。同样重要的是检查EOF,这是用户在不使用'q'或生成SIGINT中断信号的情况下发出输入取消信号的唯一方法,例如Ctrl + C 在 Linux 上。如果您有任何其他问题,请告诉我。
编辑
注意:我在捕获每个 EOF 后添加了一个“整理 \n”,以便在执行结束时提供适当的换行符(因此,您的下一个终端提示不会在您的最后一次输入提示之后开始程序 -- 1/2 跨终端 :)