繁体   English   中英

使用fgets从stdin读取,如果输入大于大小,则发生bug

[英]Read from stdin with fgets, bug if input is greater than size

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

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

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

        toupper_str(str);
        printf("Result: %s\n", str);
    }
}

如果输入的size小于size ,则效果很好。

> asdf
Result: ASDF
> 

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

> asdfghjk
Result: ASDFGHJ
> Result: K

> 

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

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

当检测到此错误时,如何停止它在下次迭代中读取其余太长的输入?

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

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

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

fgets()不会溢出缓冲区。 如果确实填满了缓冲区,则缓冲区中的最后一个char'\\0' 因此,在读取之前将其设置为非'\\0' 然后代码知道整个缓冲区是否已满。 然后检查前面的char是否为'\\n' 如果不是行尾, stdin 可能存在其他char

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);
}

注意:发生文件错误时, fgets()返回NULL并且str的内容未定义。

注意:代码可以使用strlen(str) == sizeof str - 1代替str[sizeof str - 1] == '\\0' 如果fgets()读取空字符'\\0'这将被愚弄。

角落案例:
1.典型的str最多为98个char ,然后为'\\n''\\0' 可以, 最后一个 str是99 char然后是'\\0'吗?
2.如果#1正常,那么典型的str可以有99个char ,然后是'\\0'吗?

当输入太长时,您需要在stdin上读取其余字符,然后再继续循环的下一次迭代。

if (fgets(str, size, stdin) == NULL) {
    if (feof(stdin)) {
        return 0;
    else {
        perror("Could not read from stdin");
        exit(1);
    }
}
else if (strchr(str, '\n') == NULL) {
    int c;
    while((c = getc(stdin)) != '\n' && c != EOF);
    fprintf(stderr, "Input too long\n");
}

如果您使用的是OS X或Linux之类的POSIX系统,则已经有getline函数可以从流中读取任意长度的换行符终止的字符串。 您也可以在线找到该功能的许多免费/开源版本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM