来自stdin的fgets具有不可预测的输入大小

时间:2017-12-08 16:52:27

标签: c stdin fgets

我试图从stdin读取一行但我不知道在输入大小至少等于限制时正确处理这些情况。示例代码:

void myfun() {
    char buf[5];
    char somethingElse;

    printf("\nInsert string (max 4 characters): ");
    fgets (buf, 5, stdin);

    ...

    printf("\nInsert char: ");
    somethingElse = getchar();
}

现在,用户可以做三件事:

  1. 输入少于4个字符(加上换行符):在这种情况下,stdin中没有任何内容,后续getchar()正确等待用户输入;
  2. 输入正好4个字符(加上换行符):在这种情况下,stdin中有一个换行符,后续的getchar()会读取它;
  3. 输入超过4个字符(加上换行符):在这种情况下,至少还有另一个字符留在stdin中,随后的getchar()读取它,至少留下一个换行。
  4. 案例 2 3 需要使用stdin之类的内容清空while(getchar() != '\n'),而案例 1 不会&# 39; t需要任何额外的行动。正如我从阅读类似问题和c-faq的答案中所理解的那样,没有标准/可移植的方式来了解实际情况是否是 1 中描述的情况。

    我说得好吗?或者实际上 是一种可移植的方式吗?或者可能采用完全不同的方法?

2 个答案:

答案 0 :(得分:4)

如果有空间,fgets函数会将换行符存储在缓冲区中。因此,如果字符串中的最后一个字符不是换行符,则表示您需要刷新缓冲区。

fgets (buf, 5, stdin);
if (strrchr(buf, '\n') == NULL) {
    // flush buffer
    int c;
    while ((c = getchar()) != '\n') && (c != EOF));
}

答案 1 :(得分:2)

如果假设从未读过 null字符 '\0',那么@dbush答案就可以了。

如果读取空字符,则strrchr(buf, '\n')找不到可能已被阅读的'\n'

代码可以预先设置缓冲区,以查看最后是否读取了'\n'

buf[sizeof buf - 2] = '\n';
if (fgets (buf, sizeof buf, stdin)) {
  if (strrchr(buf, '\n') == NULL) {
    // incomplete line read.  (the usual detection)
  } else if (buf[sizeof buf - 2] != '\n') {
    // incomplete line read with prior null character  (see below note).
  }
}

然而,C标准并未指定过去buf[]中读取的数据未更改,使用某种模式预先填充缓冲区不足以检测 null字符 { {1}}已被阅读。

  

是一种可移植的方式吗?

最便携的方法是使用'\0'之类的重复来电,而不是fgetc()

  

可能是一种完全不同的方法?

我建议使用fgets()或普通但不是C标准fgetc()

另一种选择:使用getline()非常繁琐,但可以采用便携式方式。它会跟踪scanf("%4[^\n]%n", buf, &n)之前读取的字符数,即使某些空字符也是如此。

'\n'