【问题标题】:scanf() buffer newline consumed with spacesscanf() 缓冲区换行符与空格一起使用
【发布时间】:2021-09-06 07:37:46
【问题描述】:

在 scanf() 之后使用 fgets() 时,我试图解决换行缓冲区问题,我最初的解决方案是使用 scanf("\n"); 使用换行符。它解决了这个问题,但后来我遇到了一个不同的解决方案,用 scanf("%c ",&ch); 消耗缓冲区中的换行符;

注意:%c 后面有个空格确实解决了问题

这是导致换行缓冲区问题的完整代码:

#include "stdio.h"

int main() {
    char ch;
    char s[100];
    char sen[100];

    scanf("%c", &ch);
    scanf("%s", s);
    fgets(sen, sizeof(sen), stdin);

    printf("%c\n", ch);
    printf("%s\n", s);
    puts(sen);
    return 0;
}

但是在 %c 和 %s 之后添加空格时,相同的代码将起作用,如下所示:

#include "stdio.h"

int main() {
    char ch;
    char s[100];
    char sen[100];

    scanf("%c ", &ch);
    scanf("%s ", s);
    fgets(sen, sizeof(sen), stdin);

    printf("%c\n", ch);
    printf("%s\n", s);
    puts(sen);
    return 0;
}

我的问题是 %c 和 %s 之后的两个空格是如何消耗换行符以使 fgets() 能够接受输入的?

【问题讨论】:

  • 这是设计使然:这是scanf 格式字符串中的空格的目的 - 在输入流中消耗 任意数量 的空格,尽管某些说明符会这样做它自动。该字符串中的每个字符都是格式的一部分。请参阅scanf() leaves the newline char in the buffer。但一般来说,将任何空格放在格式字符串的末尾是个坏主意,因为只有在输入流中存在另一个非空格字符时才会满足要求,该字符将保留在那里。
  • “解决”这个问题的最好方法是不要混合scanf和fgets。他们真的不能一起玩。
  • 如果您只是必须将两者混合,通常的解决方案是使用内联代码,或者可能是集中的“gobble”函数,读取字符直到(包括)换行符,然后插入此代码/call 必要时,通常在scanf 调用之后和fgets 调用之前。
  • 有关不使用scanf 的帮助,请参阅this question
  • @WeatherVane 我想说,如果您希望能够输入带空格的字符串,是时候停止使用scanfstart using fgets for everythingscanf 唯一的优点是它对初学者来说简单易用。但是%[] 与 simple'n'easy 正好相反。

标签: c scanf buffer fgets


【解决方案1】:

这是您的前三个scanf 调用,带注释:

scanf("%c", &ch);                // reads one character, as desired (but leaves newline)
scanf("%s", s);                  // skips newline, reads word as desired (but leaves newline)
fgets(sen, sizeof(sen), stdin);  // reads preceding newline, does not read next line

这是您接下来的三个scanf 调用,注释类似:

scanf("%c ", &ch);                // reads one character, then skips whitespace (i.e. newline)
scanf("%s ", s);                  // reads one word, then skips whitespace (i.e. newline)
fgets(sen, sizeof(sen), stdin);   // reads third line, as desired

所以看起来尾随空格已经“起作用”了,因为fgets 调用现在根据需要读取第三行。但是如果你添加一些提示,让程序更真实和方便一些,像这样:

printf("enter character: "); fflush(stdout);
scanf("%c ", &ch);
printf("enter word: "); fflush(stdout);
scanf("%s ", s);
printf("enter string: "); fflush(stdout);
fgets(sen, sizeof(sen), stdin);

当我运行它时,它看起来像这样:

enter character: x
abc
enter word: this is a test
enter string: x
abc
this is a test

在提示我输入之前我必须输入单词abc,同样我必须在提示我输入之前输入字符串this is a test

所以尾随空格确实不是一个很好的解决 gobble-a-newline 问题的方法,因为正如 Weather Vane 在评论中解释的那样,“只有在输入流中有另一个非空白字符时才会满足”。也就是说,它会导致每次调用都阻塞,直到看到下一个输入的开始,这完全打乱了提示的顺序。

【讨论】:

    【解决方案2】:

    如果我理解正确,您正在尝试在收到输入时删除 '\n',如果是这样,请尝试以下操作:

    fgets(input, <size>, stdin);
    input[strcspn(input, "\n")] = 0;
    

    【讨论】:

      猜你喜欢
      • 2021-05-12
      相关资源
      最近更新 更多