关于将fgets()和stdin一起使用的机制

时间:2018-06-14 09:30:11

标签: c stdin fgets

我希望更好地了解使用fgets()stdin。 以下是我的代码:

int main()
{
    char inputBuff[6];
    while(fgets(inputBuff, 6, stdin))
    {
        printf("%s", inputBuff);
    }
    return 0;
}

假设输入为aaaabbbb,按Enter键。通过使用循环计数,我明白在下一次输入之前,循环实际上会运行两次(包括我输入的aaaabbbb)。

循环1:输入字符后,aaaabbbb\n将存储在stdin文件流的缓冲区中。 fgets()将从文件流中检索特定数量的数据并将其放入inputBuff。在这种情况下,它将一次检索5(6 - 1)个字符。因此,当fgets()已经运行一次时,inputBuff将存储aaaab,然后进行打印。

循环2:然后,由于bbb\n保留在文件流中,fgets()将第二次执行,以便inputBuff包含{{1}然后被打印出来。

循环3:程序将在文件流到达末尾(bbb\n)时询问我的输入(第二次)。

问题:在EOF流没有数据留在缓冲区(fgets())之后,stdin似乎只会询问我的键盘输入。我只是想知道为什么我不能使用键盘在循环2中输入任何内容,而EOF只是继续从fgets()流中检索5个字符并将多余的数据留在文件流中以供下次检索。我对stdinstdin有任何误解吗?谢谢你的时间!

3 个答案:

答案 0 :(得分:1)

fgets()仅在'\ n'或EOF之前读取。之后的所有内容都将留在stdin中,因此当您再次调用fgets()时会被读取。但是,您可以通过使用getc()从stdin中删除多余的字符,直到达到\ 0。您可能需要查看联机帮助页。

答案 1 :(得分:1)

无论你问什么,fgets()的手册页都有。只需要正确阅读它,它说

  

char *fgets(char *s, int size, FILE *stream);

     

fgets()最多只读取更少   来自流并将它们存储到s指向的缓冲区中。读   在 EOF或换行符后停止。如果读取换行符,则为   存储在缓冲区中。存储终止空字节(aq \ 0aq)   在缓冲区中的最后一个字符之后。

如果输入为aaaabbbb且在fgets()第二个参数中,您指定的大小为6,即它将读取少一个5字符,并且终止\0将是已添加第一次inputBuff保留aaaab,因为仍然EOF\n未发生,因此下次inputBuff保留bbb\n为新行也最后存储。

此外,您应该检查fgets()的返回类型并检查是否发生\n然后打破循环。例如

char *ptr = NULL;

while( (ptr = fgets(inputBuff, 6, stdin))!= NULL){
          if(*ptr == '\n')
                   break;
          printf("%s", inputBuff);
}

答案 2 :(得分:1)

你的程序的行为比你期望的更微妙:

fgets(inputBuff, 6, stdin)stdin读取最多5个字节,并在获取换行符时停止读取,换行符存储在目标数组中。

因此,当您正确诊断时,第一个调用读取5个字节aaab并打印它们,第二个调用读取4个字节bbb\n并打印它们,然后第三个调用获取一个空输入流等待用户输入。

棘手的部分是stdin如何从用户那里获得输入,也称为控制台输入。

默认情况下,控制台输入和stdin通常都是行缓冲,因此无论传递给fgets()的缓冲区大小如何,都可以输入完整的输入行。然而,如果您可以将stdin设置为未缓冲且控制台输入为未烹饪,则第一个fgets()确实会在您输入后立即读取前5个字节。

控制台输入是一个复杂的主题。这是一篇关于其内部运作的深入文章:https://www.linusakesson.net/programming/tty/