【问题标题】:Is this the best way to clear input buff in c?这是在c中清除输入缓冲区的最佳方法吗?
【发布时间】:2015-03-19 07:50:56
【问题描述】:

我正在尝试编写一个读取各种用户输入的程序。这些字符串输入可以包含或不包含空格。我制作了一个运行良好的版本,但需要一个 while 循环(在 clearStdin 函数内),如下所示:

#include <stdio.h> 
#include <stdlib.h> 

void clearStdin(void);

int main(void)
{
    char name1[8], name2[5];

    printf("Write a name: ");
    fgets(name1, sizeof name1, stdin);
    clearStdin();

    printf("Write another name: ");
    fgets(name2, sizeof name2, stdin);
    clearStdin();

    printf("First name is: %s\n", name1);  
    printf("Second name is: %s\n", name2);

    return 0;
}

void clearStdin(void){  

    int c;

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

我尝试使用

scanf("%7[^\n]", name1);
scanf("%*[^\n]");
scanf("%*c");

还有其他方式。我的问题是:程序还有其他方法可以在不使用 while(或其他)循环的情况下工作吗?只有任何 scanf 或 fgets 方式?

示例输入:

 Write a name: RafaelBluhm
 Write another name: Tainah Julião

需要的输出:

First name is: RafaelB
Second name is: Tain

输出失败(其他方式):

First name is:Tain
Second name is:@�

【问题讨论】:

  • 有没有可能你没有使用 \0 来关闭你的字符串?
  • 顺便说一句 char c; clearStdin() :应该是 int c;
  • 总是检查每次调用 'fgets; 的返回值;和/或“scanf”以确保操作成功。始终在 scanf() 的格式字符串中放置一个前导 ' ' (空格),这样它将跳过任何前导空格。在 scanf() 中使用 %s 时,请始终设置限制/最大长度,因此不会发生缓冲区溢出。建议使用 fscanf() 而不是 scanf() 最后,我建议使用 fgets() 输入整行,使用 sscanf() 来提取名字/姓氏。并始终在使用 sscanf() 之前将每个名字/姓氏缓冲区清除为 '\0',因此当没有姓氏时,不会打印任何内容。
  • scanf("%8[^\n]", name1); 应该是scanf("%7[^\n]", name1);
  • OT:使用stderr 作为提示更常见(并且会减少缓冲问题):fputs("Write a name: ", stderr)fprintf(stderr, "Write a name: ");

标签: c


【解决方案1】:

对于一般实现:不,没有其他方法可以清除输入缓冲区。

对于给定的特定环境,可能有一种特定于环境的方式。例如,在 Linux/Unix 上,有一种方法可以通过 ioctl() 查看有多少终端缓冲区字符处于待处理状态,还有另一种方法可以清除它们。

【讨论】:

  • 这是正确的。 stackoverflow.com/questions/22901901/… 的更多详细信息 - 但是,在 Linux(显然还有 DOS)上,fflush(stdin) 确实 确实有效 - 请参阅手册页。
  • 即使可靠,也还是很糟糕。想象一下,如果标准输入来自管道或重定向文件(这是一件好事;每个人都讨厌为了测试而输入重复的东西)!
【解决方案2】:

如果你想使用scanf,你可以使用

scanf("%*[^\n]%*1[\n]");

这相当于你的clearStdin 函数。

我建议您通过返回值指示 EOF(scanf 在文件结尾或此处错误时返回 EOF),并检查这一点——程序不应尝试读取进一步的输入在第一个文件结尾之后。

【讨论】:

  • 效果很好。但仅清除fgets 输入。我尝试与scanf 一起使用,但它不起作用。听说这两个功能混用不好。
  • @RafaelBluhm,混合它们不一定不好(实际上,使用它们中的任何一个都不好(一些scanf 调用是可以的),但这是另一个讨论),你必须记住他们的工作方式不同。这个scanf 调用应该与clearStdin 函数完全相同。用什么scanf 调用不起作用?顺便说一句,您可能想检查 fgets 是否已读取换行符 (strchr)(如果没有,则仅清除 stdin)。
  • @mafso scanf("%*[^\n]%*c"); 也很好用。 Ty 表示建议。
【解决方案3】:

我认为您可以使用fflush(stdin); 我以前使用过它,但我不确定它是否标准 C ,测试它并告诉我。

【讨论】:

  • fflush(stdin); donts 有效。它不在标准 C 中。存储在第一个字符串中的其余缓冲区放在第二个中
  • 拜托,让我们从地球表面废除[这个可憎的[(stackoverflow.com/questions/2979209/using-fflushstdin)!
  • 虽然它不符合 POSIX,但它确实在 Linux 下工作(并且据称是 DoS) - 请参阅其他帖子上的链接。回答者确实说他不确定这是标准 C,所以我们不要太苛刻。
  • 即使是标准的,它仍然会很糟糕。 OP 的循环将消耗最多并包括下一个换行符;如果fflush(stdin) 在哪里可靠地工作,它只会丢弃缓冲区的其余部分。现在想象一下,如果标准输入不是来自人类在终端中输入,而是来自管道或重定向文件。
  • 这个解决方案是为了解决这个问题......在这种情况下,这就是你获得输入的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-08
  • 2011-12-15
相关资源
最近更新 更多