如何确定使用 fgets() 读取的字符数?

How to determine number of characters that were read with fgets()?

这是手册页中对 fgets() 的描述:

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

RETURN VALUE
  fgets() returns s on success, and NULL on error or  when  end  of  file
  occurs while no characters have been read.

它不遵循 read 的模式,失败时 returns -1 成功时读取的字节数。相反,它 returns a char* 失败时 NULL 成功时 s 。这没有给我任何关于输入多长时间的信息。所以如果我有这样的东西:

char input_buffer[256];
fgets(input_buffer, sizeof(input_buffer), stdin);

fgets 调用之后,有什么方法可以在不首先对缓冲区进行零初始化的情况下判断输入多长时间?

谢谢。

是的。如果成功,它总是以 null 终止。所以它将是 strlen(buf).

来自标准 7.21.7.2

char *fgets(char * restrict s, int n,FILE * restrict stream); The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array.

How to determine number of characters that were read with fgets()?

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

检查 fgets() return 值后使用 strlen(s)

if (fgets(s, size, stream)) {
  printf("number of characters that were read: %zu\n", strlen(s));
} else if (feof(stream)) {
  printf("number of characters that were read:0 End-of-file\n");
} else  {
  printf("number of characters that were read unknown due to input error\n");
}

这有效除非一个空字符 '[=15=]'被读取为strlen()会遇到'[=15 =]' 在函数附加的一个之前。在这种情况下,fgets() 之后的 strlen(s) 将报告较小的值。

有各种技巧可以预填充 s 然后调用 fgets(),但未定义未读缓冲区的其余部分会发生什么。存在其他缺点。

如果 空字符 作为有效输入流的一部分是一个问题,请使用 fgetc() 或类似 getline().


空字符 是文本的常见情况是文本被编码为 UTF-16。当然,代码不应使用 fgets() 来阅读该文本,但这需要先验知识。许多读取 text 的代码由于错误地假设文本文件是非空字符文本文件而以神秘的方式失败。

此外,即使文本文件据说缺少 空字符 ,以下代码会发生什么情况?

if (fgets(s, size, stream)) {
  size_t len = strlen(s);
  s[--len] = '[=12=]';  // poor way to lop off the trailing \n, this could be UB
}

这样的代码调用未定义的行为,黑客利用:在开头的文件中插入一个空字符 =]行。 (请参阅 this and this 以了解更好的解决方案以降低潜力 \n

健壮的代码不假定文本格式正确并采取措施检测异常。


学究注解:fgets(char *s, int size, FILE *stream);size < 2 存在病态问题。