关于同时使用 fgets() 和 stdin 的机制

About the mechanism of using fgets() and stdin together

我想更好地理解 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包含bbb\n,然后被打印出来。

循环 3: 当文件流已到达末尾时,程序将要求我输入(第二次)(EOF)。

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

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

fgets() 手册页中的所有内容,无论您问什么。只需要正确阅读它,上面写着

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

fgets() reads in at most one less than sizecharacters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte (aq[=26=]aq) is stored after the last character in the buffer.

如果输入是 aaaabbbb 并且在 fgets() 第二个参数中您将大小指定为 6 即它将少读取一个 5 字符并终止 [=17=]将被添加,所以第一次 inputBuff 保持 aaaab 并且由于仍然 EOF\n 没有发生所以下一次 inputBuff 保持 bbb\n 作为最后也存储了新行。

你还应该检查 fgets() 的 return 类型并检查 \n 是否出现然后中断循环。例如

char *ptr = NULL;

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

您的程序的行为比您预期的要微妙一些:

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

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

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

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

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