fgets() 的行为、换行符及其在内存中的存储方式

Behavior of fgets(), newline character and how it gets stored in the memory

下面有这段代码,我很好奇如果我输入

,内存中会存储什么

"Hi"那我回车,会不会'H''i''\n''\0'存入内存

如果我输入

"Hello" 然后我回车, 'H' 'e' 'l' 'l' '\0' 会被存入内存然后 'o' '\n' 在缓冲区中

最后,如果我输入

"Hell" 然后我回车, 'H' 'e' 'l' 'l' '\0' 会存入内存然后 '\ n' 在缓冲区中

char str [5];

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

给定 fgets() 的定义:

char *fgets( char *str, int count, FILE *stream ); (until C99)

char *fgets( char *restrict str, int count, FILE *restrict stream ); (since C99)

Reads at most count - 1 characters from the given file stream and stores them in the character array pointed to by str. Parsing stops if a newline character is found, in which case str will contain that newline character, or if end-of-file occurs. If bytes are read and no errors occur, writes a null character at the position immediately after the last character written to str.

The behavior is undefined if count is less than 1. It is also not specified whether a null character is written if count==1.

fgets 将最大长度(大小)为 5 的输入行存储在 str 变量中,并以 null 终止它。

由于您提供的大小是 5,如果您输入 "Hello",它将存储 H e l l [=29=] 替换 'o''o' 不会存储,通常,'o''\n' 将保留在 stdin 缓冲区中,尽管这不是标准强制要求。

如果您输入 "Hell"stdin 缓冲区将具有 H e l l \n,因此当其存储的 '\n' 将被 '[=39=]' 替换,并且 '\n' 将保留在缓冲区中。

以同样的方式,如果该行小于 5 - 1,则不会替换任何内容,char array 以空结尾,即 "Hel" 将存储为 H e l \n [=44=]stdin 缓冲区将被清空。

这就是为什么您通常声明 char array 1 个字符比预期的实际最大大小大,并将其大小传递给 fgets:

fgets(str, sizeof(str), stdin);

注意 you should not use fflush(stdin).

来自 man fgets 在我的机器上:

char * fgets(char * restrict str, int size, FILE * restrict stream);

The fgets() function reads at most one less than the number of characters specified by size from the given stream and stores them in the string str. Reading stops when a newline character is found, at end-of-file or error. The newline, if any, is retained. If any characters are read and there is no error, a `[=16=]' character is appended to end the string.

这意味着您对将要存储在 str 缓冲区中的内容的判断是正确的。未读字符可能会被标准输入的后续读取读取,但这将取决于 OS 和您从哪里读取。 C 标准没有强制要求。

fgets(buf, n, stream) 读取输入并将其保存到 buf 直到 4 件事中的 1 发生。

  • 缓冲区快满了。一旦读取(并保存)了 n-1 个字符,'[=13=]' 就会附加到 buf。函数 returns bufstream 中可能还有剩余字符需要阅读。1

  • '\n' 是从 stream 读取的。 '\n' 附加到 buf'[=13=]' 附加到 buf。函数 returns buf已完全阅读。

  • 文件结束。如果之前读过一些字符,'[=13=]' 会附加到 buf。函数 returns buf。否则返回 NULL

  • 输入错误(罕见)。 NULL 返回。 buf 的状态不确定。

阅读 '\n' 与其他字符的唯一不同之处在于它通知 fgets() 停止阅读。


1 如果在没有 '\n' 的情况下读取完整的缓冲区,则读取并丢弃 的其余部分:

int ch;
while ((ch = fgetc(stream)) != '\n' && c != EOF) {
  ;
}