循环中的fgetc(stdin)产生奇怪的行为

时间:2012-08-21 22:18:56

标签: c fgetc

我有这段代码

while(1){
    printf("hello world !\n");
    fgetc(stdin);
}

当它运行时,我输入一个这样的字母:

hello world !
a

它会忽略下一个循环中的fgetc(stdin)并打印hello world两次而不等待输入。

hello world !
a
hello world !
hello world !
a
hello world !
hello world !
a
hello world !
hello world !
a
hello world !
hello world !

我试过在fgetc(stdin)之前或之后放fflush(stdin),但它仍然会产生相同的行为,我做错了什么?

4 个答案:

答案 0 :(得分:8)

那是因为你实际上输入了两个字符:'a'和换行符。此外,由于终端通常是行缓冲的,因此只有在您按下换行符后,程序才会看到您的输入。输入更长的文本行也会提供信息。

如果要更改此行为,您有两种选择:读取整行(即所有字符到换行符或文件结尾)或将终端切换到非规范模式。如果您正在使用像文本编辑器这样的交互式终端应用程序,后者就有意义了。有关详细信息,请参阅termios manpage。简而言之,您需要将MIN和TIME选项设置为零,以便在数据可用时立即从终端返回。如果确实沿着这条路走下去,请确保在退出时切换回终端,包括接收信号。

fflush()会影响输出,而不会影响输入。

答案 1 :(得分:5)

终端往往是行缓冲的,这意味着流内容可以逐行访问。

因此,当fgetc从STDIN开始读取时,它正在读取一个完整的行,其中包括结束该行的换行符。这是你正在阅读的第二个角色。

至于fflush,那是用于刷新输出缓冲区而不是输入缓冲区。

所以,你想要做的是通过读取输入缓冲区直到它为空,或者只是显式地忽略换行符来清除输入缓冲区。

答案 2 :(得分:2)

有两个字符:a\n(换行符)。你的循环读取读取a,然后循环并打印“hello world!”。然后它看到\n并循环并打印“hello world!”。在终端中键入a + \n时,它会将两个字符存储在stdin缓冲区中。如果有可用的char,fgetc(stdin);将从stdin缓冲区读取,否则它将等待,直到将char添加到缓冲区。

由于终端是行缓冲的(即,在到达换行符之前不将内容发送到程序),您有以下几种选择:

  • 将整行读入缓冲区,但只取第一个字符
  • 忽略换行符
  • 关闭线路缓冲

要关闭线路缓冲,请查看http://c-faq.com/osdep/cbreak.htmlhttp://www.flipcode.com/archives/_kbhit_for_Linux.shtml以及http://ubuntuforums.org/showthread.php?t=225713(虽然我此处未测试任何代码)。

答案 3 :(得分:1)

您有两个字符'a''\n'。这就是问题,因为fgetc只会读取一个字符。这是documentation

如果您只输入'\n' - 仅限输入 - 您将获得预期的行为。

希望它有所帮助!