fgets在换行符之前设置null char后清除输入流

Mik*_*t25 2 c fgets

我有一个程序,用户输入两个输入。由于我无法控制用户输入的内容,因此用户可以超过数组的固定大小。由于fgets() appends在空字符之前将换行符保留在末尾,因此如果用户超出预期大小时无法容纳换行符,则空字符会截断输入。当用户点击Enter时,换行符是否仍存在于输入流中?如果是这样,这是为什么fgets()由于第一个输入中的换行符而第二次跳过的原因吗?

#include <stdio.h>
int main(){
    char str[5];
    fgets(str,5,stdin);
    printf("Output:%s",str);

    fgets(str,5,stdin);
    printf("Output:%s",str);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输入示例 ABCDE\n

输出量

Output:ABCDOutput:E
Run Code Online (Sandbox Code Playgroud)

读取该SO答案后,fgets()不再提示用户 ,问题似乎不是通过刷新输入流fflush(stdin),但我听到了相互矛盾的信息,因为这会导致不确定的行为。我的最后一个问题是,如果是导致问题的保留换行符,清除输入流的合适方法是什么?

Joh*_*ger 5

用户可以超过数组的固定大小。由于fgets()在空字符之前将换行符附加到末尾

不,不是的。它将从输入读取的字符写入提供的缓冲区,直到并包括第一个换行符,或者直到指定的缓冲区大小用完(字符串终止符少一个字节),或者直到发生错误或流结束到达,以先到者为准。换行符不是由fgets(); 它来自输入。

,如果当用户超出预期大小时换行符无法容纳,则空字符会截断输入。用户点击回车时的换行符是否仍然存在于输入流中?

所有由用户输入但未复制到缓冲区中的字符仍等待在流中读取。如果用户输入了换行符,那将包括换行符。

如果是这样,这是否是 fgets() 由于第一个输入中的换行符而第二次跳过的原因?

fgets()不会跳过,但它会从前一个调用停止将字符从输入传输到缓冲区的地方开始。没有字符丢失。这意味着如果第一个调用没有返回整个内容,第二个调用将返回第一个输入行的一部分。您需要以一种或另一种方式考虑输入不符合您的行长度期望的可能性。

问题似乎不是通过以下方式刷新输入流fflush(stdin)

不,不是。刷新用于将缓冲输出发送到底层输出设备。刷新输入流会产生未定义的行为。原则上,这可能表现为缓冲区转储,并且给定的实现甚至可能指定此类行为,但您不希望这样,因为缓冲的数据可能多于您想要摆脱的数据。

但我听说过相互矛盾的信息,因为这会导致未定义的行为。我的最后一个问题是,如果是保留的换行符导致问题,那么清除输入流的适当方法是什么?

您从输入中读取,直到您阅读了换行符。有很多 I/O 函数可供选择来实现这一点。 fgets()本身可能很方便,因为您已经在使用它:

char str[5];

if (fgets(str, 5, stdin)) {
    printf("Output:%s", str);
    // read and consume the tail of the line, if any (overwrites str)
    while (!strchr(str, '\n') && fgets(str, 5, stdin)) { /* empty */ }
}
Run Code Online (Sandbox Code Playgroud)


chu*_*ica 5

fgets() 读到

1)换行
2)缓冲区已满
3)文件结束
4)输入错误(稀有)

此代码读取并处理#3和#4

 #define N 5
 char buf[N];
 if (fgets(buf, sizeof buf, stdin) == NULL) {
   // Handle EOF or Error
   return EOF;
 }
Run Code Online (Sandbox Code Playgroud)

区分是否'\n'存在...(#1中的#2)

 // look for a lack of \n
 if (strchr(buf, '\n') == NULL) {
Run Code Online (Sandbox Code Playgroud)

如果是这样,请阅读直到找到它为止EOF

   int ch;
   while ((ch = fgetc(stdin)) != '\n' && ch != EOF);
 }
Run Code Online (Sandbox Code Playgroud)

-

不要使用以下代码。可以通过读取空字符作为第一个字符来利用它。

 size_t len = strlen(buf);
 if (buf[len - 1] != '\n') {  // bad way to detect \n
Run Code Online (Sandbox Code Playgroud)

可以用

 if (len > 0 && buf[len - 1] != '\n') {  // Good
Run Code Online (Sandbox Code Playgroud)