【问题标题】:How to stop enter character getting stuck in buffer? C如何停止输入字符卡在缓冲区中? C
【发布时间】:2016-11-16 14:54:09
【问题描述】:

因此,在下面的代码中,我从用户那里读取一个选项,然后决定是否执行给定的操作:

printf("Do you want to execute %s: ", exe);

char input = getchar();

if (input == 'y') {
    return execute(exe);
} return 0;

我遇到的问题是,在char input = getchar() 行之后,一个字符(我假设是回车键或换行符)卡在stdin 中,并且将来调用fgets()(来自@987654326 @) 来自我的 execute() 函数因此吃掉了这个卡住的字符并且不会提示用户输入所需的输入。

现在我可以定义以下函数,如果在调用 execute() 之前为我“吃掉”任何杂散字符...

void iflush() {
    int c;

    while ((c = getchar()) != EOF && c != '\n') {
        continue;
    }
}

... 这解决了问题。但是我想知道为什么首先会发生这种情况?有没有更“正确”的方式从stdin 获取char 而不会导致这个流浪字符,然后弄乱我的其他方法?我对 C 语言非常陌生,并且很想确保自己正在学习良好的习惯。

我必须添加一个辅助方法(即使很简单)似乎很奇怪,以防止我的程序中的错误只是记录一些用户输入。我也尝试过使用fgetc(),但同样的问题。

【问题讨论】:

  • 您在调用getchar() 的语句之后尝试fflush(stdin); 吗?
  • 是的,什么也没做
  • @VHS 你知道这是一个非常糟糕的建议吗? fflush(stdin); 正在调用未定义的行为。
  • @VHS:请阅读Using fflush(stdin) 了解有关fflush(stdin) 的更细致入微的故事——它是在使用Microsoft C 运行时库时在Windows 上定义的,但在其他方面不可移植。
  • 解析输入(一般数据)绝对不是一件容易的事,因此编写这样的帮助程序(由于丢失了好字符而损坏,输入正确时返回它们)是很常见的。跨度>

标签: c stdin stdio getchar


【解决方案1】:

我想知道为什么会发生这种情况?

这是因为当您可以使用%c(或fgetc())字符时,它不会忽略输入流中的任何空格。 某些格式说明符,例如 %d,会忽略输入流中留下的任何空格。所以,这不是问题。但是%c 并没有忽略它。 因此,您通常会使用那些“吃”功能。

想想如果您正在扫描一个空白字符(例如 space、换行符等),您是如何使用scanf() 扫描它的? 显然,有不同的更好的方法,比如使用fgets()

我是 C 的新手,我很想确定自己正在学习良好的习惯。

我的建议是完全避免scanf()。而是使用fgets() 读取一行,然后您可以使用sscanf() 解析该行。请阅读:Why does everyone say not to use scanf? What should I use instead?

关于fgets() 需要注意的一点是,如果您的输入缓冲区有足够的空间,那么它也会读取换行符, 您希望在大多数用户输入中避免这种情况。因此,您需要检查最后一个字符是否为换行符,然后将其删除。

您可以使用strcspn()函数来实现它,例如:

char line[256];
if (fgets(line, sizeof line, stdin) == NULL) {
    /* handle failure */
}
line[strcspn(line, "\n")] = 0; /* remove the newline char if present */

如果您主要对读取一个字符感兴趣,那么 3 个字符的数组就足够了。仍然使用更大的缓冲区并没有什么坏处:

char line[256];
char ch;
if (fgets(line, sizeof line, stdin) == NULL) {
    /* handle failure */
}
if (sscanf(line, "%c", &ch) != 1) {
    /* handle failure */        
}
/* Now you can use 'ch' to check if it's 'y' */

【讨论】:

  • 非常好,除了“只读取一个字符,然后数组 2 个字符就足够了”。通常要阅读一个char,人们不计入\n。可能至少需要 3 个字符:字符、换行符和空字符。建议缓冲区大小是您认为的最大值的两倍。 256 非常适合用户输入。
  • fgets() 只会在缓冲区没有空间的情况下存储\n。因此,2 就足够了:1 个字符和零字节。因此,当读取一个字符(即使是换行符)时,2 字节的缓冲区大小就足够了。
  • 是的,但'\n' 仍保留在stdin 中以进行下一次输入操作-如果"y\n" 下的用户仅读取“一个”字符,OP 似乎想要避免这种情况。如果代码需要一次读取一个字符,包括'\n',只需使用fgetc() - 这处理读取空字符,这与fgets() 存在问题。
  • 我已经稍微修改了它以处理它。谢谢。
  • 像这样使用 strcspn () 是个坏建议,因为它可以读取没有尾随换行符的行。
猜你喜欢
  • 2017-10-31
  • 2020-04-08
  • 1970-01-01
  • 2015-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-26
相关资源
最近更新 更多