在执行下面的一小段代码时,每次我输入一个字符,输出都会重复,我不明白为什么。有人能给我解释一下为什么会这样吗?ps:刚刚开始我的c编程之旅。
如果我打印了一个字符,比如'a',我应该输出1,然后另一个提示符要求我再次输入一个字符,但是我得到了1,一个提示符,然后又是1,然后另一个提示符要求我输入一个字符。
#include <stdio.h>
int main()
{
int usr_ch;
for ( usr_ch = 0; (usr_ch != 'q');){
printf("Enter a single character: (enter 'q' to stop)\n");
usr_ch = getc(stdin);
printf("%d\n", (usr_ch != 'q') ? 1 : 0));
}
return 0;
}
input: u
output:
Enter a single character: (enter 'q' to stop)
1
Enter a single character: (enter 'q' to stop)
1
Enter a single character: (enter 'q' to stop)
2条答案
按热度按时间siotufzp1#
您已经有了一个很好的答案,解释了用户按ENTER键时生成的额外
'\n'
字符。从问题下面的注解继续,以及@AllanWard关于使用fgets()
的注解,它可以提供将所有单个字符作为输入并在只按ENTER键时结束输入的功能。还有许多其他好处。使用
fgets()
阅读行时,将输入读入缓冲区(字符数组或分配的内存块)。* 不要节省缓冲区大小... *fgets()
读取并包括它填充的缓冲区中的尾随'\n'
。这意味着消耗了整行输入,如果缓冲区大小足够,则包括尾随的'\n'
。'\n'
不会留在输入缓冲区(stdin
)中未读取。这将避免您遇到的问题。要访问数组中的第一个字符,你所需要做的就是去引用指针。(数组在访问时被转换成指向它的第一个元素的指针,C18标准-6.3.2.1(p3))。所以如果你声明
char line[1024];
来保存输入,只需引用*line
就可以访问第一个字符。使用
fgets()
避免了新的C程序员使用scanf()
时遇到的所有陷阱,并且避免了'\n'
未被读取的情况。(以及不是很新的C程序员)使用fgets()
接受所有用户输入(或POSIXgetline()
,其行为方式相同,但也可以提供自动分配以处理任意长度的字符串)除了接受输入之外,您还可以通过几个简单的测试确保用户只输入了一个可打印的字符。这允许您根据需要处理个别错误情况。使用
fgets()
并处理几个可预见错误情况的简短示例可以写成:(**注:**这些只是你可以使用的分类测试的几个例子。你可以随意添加或删除。你甚至可以为不可打印的字符提供一个查找表,并输出一个表示,例如
'\t'
,当一个字符被按下时,这完全取决于你。)使用/输出示例
下面将练习所涵盖的每种错误情况(
'\t'
字符用于不可打印字符),例如使用
getc()
、fgetc()
或getchar()
将单个字符作为输入绝对没有错,但是必须处理任何未读的附加字符(包括尾随的'\n'
)。那么如果用户连续按两次ENTER键,或者一只猫踩在键盘上产生500次按键?这就是fgets()
可以提供帮助的地方。另一种方法,不幸的是在不同操作系统之间不可移植,是将终端置于原始无缓冲(非规范)模式,在这种模式下输入立即被处理。对于Linux,您可以使用
tcsetattr()
。(您也可以使用setvbuf
,请参阅man 3 setbuf在无缓冲,行缓冲或全缓冲输入之间切换)对于Windows,可以使用getch()
。值得在您继续学习C语言时探索每一个。如果您有进一步的问题,请让我知道。
edqdpe6u2#
默认情况下,当您输入“u\n”时,stdin是面向行的,因此
getc()
将首先返回u
,并在下一次调用中返回\n
。在这种情况下,使用
do
-while
-循环(或者在循环体末尾有一个break的for(;;)
)会更自然。然后读取循环中的一个字母,直到找到一个你喜欢的字母(即不是\n
)。处理EOF是一个好主意。以下是示例运行:
A您也可以只对一行使用
fgets()
,或使用scanf(" %c", &usr_ch)
忽略前导白色。