在C语言中使用fgets()函数后清除输入缓冲区

11
#include <stdio.h>
int main()
{
  char name[10];
  for(int i=0;i<=10;i++)
  {
    printf("Who are you? ");
    if(fgets(name,10,stdin)!=NULL)
    printf("Glad to meet you, %s.\n",name);
  }
  return(0);
}

当我输入超过10个字符时,循环会跳过。

Who are you? aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Glad to meet you, aaaaaaaaa.
Who are you? Glad to meet you, aaaaaaaaa.
Who are you? Glad to meet you, aaaaaaaaa.
Who are you? Glad to meet you, aaaaaaaaa.
Who are you? Glad to meet you, aaaaaaaaa.
Who are you? Glad to meet you, aaaaaaaaa.
Who are you? Glad to meet you, aaaaaaa

我想清除输入缓冲区中剩余的字符,最好的方法是什么...?

5个回答

11

检查name中是否存在换行符。

#include <stdio.h>
#include <string.h>

int main(void){
    char name[10];

    for(int i=0;i<=10;i++){
        printf("Who are you? ");
        if(fgets(name,10,stdin)){
            char *p;
            if(p=strchr(name, '\n')){//check exist newline
                *p = 0;
            } else {
                scanf("%*[^\n]");scanf("%*c");//clear upto newline
            }
            printf("Glad to meet you, %s.\n", name);
        }
    }
    return(0);//Parentheses is not necessary
}

1
良好的使用 scanf("%*[^\n]");scanf("%*c"); 而不是错误的 scanf("%*[^\n]%*c"); - chux - Reinstate Monica

4

检查 fgets() 是否获取了 '\n'。如果没有 '\n',则当前行中的一些字符尚未被读取。您可以简单地忽略它们。

    printf("Who are you? ");
    if (fgets(name, 10, stdin) != NULL) {
        if (!strchr(name, '\n')) {
            // consume rest of chars up to '\n'
            int ch;
            while (((ch = getchar()) != EOF) && (ch != '\n')) /* void */;
            if (ch == EOF) /* input error */;
            printf("Glad to meet you, %s.\n", name);
        } else {
            printf("Glad to meet you, %s.", name); // name includes ENTER
        }
    }

不清楚为什么 if (ch == EOF) 被认为是一个错误,因为它可能只是 stdin 被关闭了。(例如:重定向输入:program_foo < input.txt。) - chux - Reinstate Monica
1
@chux:你可以检查ferror()和/或feof()来确保。对我而言,一行包括ENTER。如果文件中的最后一个字符不是'\n',那么该文件以其他内容终止而不是行。 - pmg

1

根据fgets的文档(重点在于我):

从流中读取字符并将其作为C字符串存储到str中,直到已读取(num-1)个字符或达到换行符或文件结束符,以先发生者为准

因此,您输入的内容(超过缓冲区)将以9个字符的块(+1个空字符)读入。

您需要反复调用fgets,直到最后读取的字符是换行符(\n)。


问题就像是当输入长度在限制范围内的字符时,会使得gets函数等待。 - 3lokh

1
你需要使用类似以下的方式查找 \n

/* flush unread input buffer */
while( ! strchr( name, '\n' ) )
    if( ! fgets(name,(sizeof name),stdin) )
        break;

注意:不确定您是否认为这是一个错误或一个功能,但短名称将包括最后的\n。这会导致类似于以下内容的结果:
Glad to meet you SSS
.

这是一个好主意,除了额外调用 fgets() 最好使用不同于 name[] 的缓冲区(在我看来)。另一方面,@Nikhil George 在这种情况下对 name[] 的内容不太清楚。 - chux - Reinstate Monica

0

使用 strchr() 函数来判断 stdin 中是否有垃圾数据,如果是的话,可以使用常用的 getchar()、while 循环和 continue 的组合来清理垃圾数据:

#include <stdio.h>
#include <string.h>
int main()
{
  char name[10];
  for(int i=0;i<=10;i++)
  {
    printf("Who are you? ");
    if(fgets(name,10,stdin)!=NULL){
        printf("Glad to meet you, %s.\n",name);
        /* If there is no '\n' in name, then there are garbage left in the stdin
            with a trailing '\n' */
        if ( strchr(name, '\n') == NULL )
            while (getchar() != '\n')
                continue;
    }
  }
  return(0);
}

输出结果为:

Who are you? AAAAAAAAAA
Glad to meet you, AAAAAAAAA.
Who are you? bbbbbbbbbbbbbbbbbbbbbbb
Glad to meet you, bbbbbbbbb.
Who are you? ccccccccccccccccccccccccccc
Glad to meet you, ccccccccc.
Who are you? dddddddddddddddddddddddddddddd
Glad to meet you, ddddddddd.
Who are you? eeeeeeeeeeeeeeeeee
Glad to meet you, eeeeeeeee.
Who are you? fffffffffffffffffffff
Glad to meet you, fffffffff.
Who are you? ggggggggggggggggggggggggggg
Glad to meet you, ggggggggg.
Who are you? hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
Glad to meet you, hhhhhhhhh.
Who are you? iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii
Glad to meet you, iiiiiiiii.
Who are you? jjjjjjjjjjjjjjjjjjjjjjjjjj
Glad to meet you, jjjjjjjjj.
Who are you? kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
Glad to meet you, kkkkkkkkk.

这确实是预期的行为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接