使用 fgets 从 stdin 读取,如果输入大于大小,则会出错

jac*_*wah 4 c

我正在创建一个带有提示的命令行应用程序。只要输入适合缓冲区,它就可以正常工作,但是当输入较大时,我会出现一些奇怪的行为。下面是一个简化的最小示例,它具有相同的错误。

int main()
{
    for (;;) {
        const int size = 8;
        char str[size];

        printf("> ");
        fgets(str, size, stdin);

        toupper_str(str);
        printf("Result: %s\n", str);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果输入小于size.

> asdf
Result: ASDF
> 
Run Code Online (Sandbox Code Playgroud)

当输入较大时,处理范围内的输入部分,并在下一次循环迭代中,立即从 返回给定输入的其余部分fgets。这导致输入的那部分也被处理和一些奇怪的输出。

> asdfghjk
Result: ASDFGHJ
> Result: K

> 
Run Code Online (Sandbox Code Playgroud)

我可以通过将最后一个字符与换行符进行比较来查看输入是否大于或等于 size。fgets只要它适合,就保留换行符。

fgets(str, size, stdin);
if (str[strlen(str) - 1] != '\n') {
    fprintf(stderr, "Input too long\n");
}
Run Code Online (Sandbox Code Playgroud)

当检测到这种情况时,如何阻止它在下一次迭代中读取剩余的过长输入?

我在这里看到过类似的问题,但没有人提出同样的问题。

chu*_*ica 6

如何阻止它在下一次迭代中读取剩余的过长输入?

代码需要 1) 检测输入是否“太长” 2) 消耗额外的输入。

fgets()不会溢出它的缓冲区。如果它确实填充了缓冲区,则缓冲区中的最后一个char'\0'。所以'\0'在阅读之前将其设置为非。然后代码知道是否整个缓冲区都被填满了。然后检查前面的char是否是'\n'. 如果它不是行尾,则附加char 可能存在于stdin

char str[100];  // Insure buffer is at least size 2
for (;;) {
  str[sizeof str - 1] = `x`;
  if (fgets(str, size, stdin) == NULL) {
    // No more to read or IO error
    break;
  }
  int extra_data_found = 0;
  if (str[sizeof str - 1] == '\0' && str[sizeof str - 2] != '\n') {
    // Cope with potential extra data in `stdin`: read and toss
    int ch;
    while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
      extra_data_found = 1;
    }
  }
  // Use `str` as needed, noting if additional unsaved data found
  foo(str, extra_data_found);
}
Run Code Online (Sandbox Code Playgroud)

注意:在文件错误时,fgets()返回NULL和内容str是未定义的。

注意:代替str[sizeof str - 1] == '\0',代码可以使用strlen(str) == sizeof str - 1. 这被愚弄了应该fgets()读取一个空字符'\0'

转角情况:
1. 典型的str将达到 98char然后'\n''\0'。是否确定是最后的 str是99char'\0'
2.如果#1没问题,那么典型的可能str有99char然后'\0'