我可以使用getchar()函数在scanf和fgets之间清除缓冲区吗?

4

我有这个函数并且它工作得很好,但是我想知道使用 getchar 是否正确。我可以做些其他的事情来代替吗?谢谢,大家。

void addRecord (struct record ** start, int account, char name[], char address[ ]);
{

    printf("Enter your account number:\n");
    scanf("%d", &account);

    getchar();
    printf("Enter your name:\n");
    fgets(name, sizeof name, stdin);
    
    printf("Enter your residential address:\n");
    getaddress(address, sizeof address);
     
}

4
是的,你应该这么做。使用int c = getchar(); while (c != '\n' && c != EOF) c = getchar(); 或者将其放在 for (int c = getchar(); c != '\n' && c != EOF; c = getchar();) {} 循环中。这样可以同时保存并检查返回结果是否为 '\n'EOF。需要注意的是 c 必须是 int 而不是 char。你可以将该逻辑放入一个 void empty_stdin() {...} 函数中,然后在需要时调用 empty_stdin(); - David C. Rankin
我应该使用它来代替scanf和getchar()吗? - Fred
2
为什么要使用循环?如果用户输入“123 abc”等内容作为account,那么单次调用getchar()将无法清空stdin - David C. Rankin
1
当然,最好的解决方案是声明 char buf[1024]; printf("输入您的账号:\n"); if (fgets (buf, sizeof buf, stdin) == NULL) { fputs ("(用户取消输入)\n", stdout); return; } if (sscanf (buf, "%d", &account) != 1) { fputs ("错误:无效的整数输入。\n", stderr); return; } 现在您可以完全确信 account 包含有效值,并且 stdin 中不会有任何剩余... :) 您还应该验证 fgets() 的返回值,以确保用户不会使用 Ctrl+d(或 Windows 上的 Ctrl+z)手动生成 EOF - David C. Rankin
我会去做的!非常感谢! - Fred
2个回答

2

getchar()函数仅从stdin中获取一个字符。如果要清除stdin缓冲区,请使用getchar()直到获取EOF(文件结束)或新行。因此,不要只调用一次getchar(),而是像这样循环调用:

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

请注意,EOF的值为-1,因此您必须使用int来处理它,因为char的范围仅限于0到255。感谢David Ranieri,EOF的值可以超出char支持的范围(通常如此),因此您应该使用int(或short)来处理EOF。如果需要多次重复使用此代码,可以将此代码放在像clear_stdin这样的函数中。

2
假设名称不能为空且不允许以空格(或制表符)开头,您可以使用另一个scanf读取名称,同时跳过所有介于空白字符之间的内容。
    printf("Enter your account number:\n");
    int account;
    if(scanf("%d", &account) != 1) { /* error getting account */ }

    printf("Enter your name:\n");
    char name[80];
    if(scanf(" %79[^\n]", name) != 1) { /* error getting name */ }
< p >“%79[^\n]”格式说明符的拆分如下:

  • 前导空格 跳过一个或多个空格、制表符、换行符,它消耗了第一个scanf留下的换行符,任何空行以及下一行的前导空格;

  • 79是一个宽度说明符,限制scanf最多读取79个字符,为80个字符的目标缓冲区留出结束的\0空字符的空间;

  • [^\n]指示scanf读取一个字符串直到(不包括)\n换行符,这样保存了用户在name参数中输入的名称。


1
警告:格式参数过多 [-Wformat-extra-args] 如果(scanf(“%* [^\n]”,sizeof(name)-1,name)!= 1){ - Fred
1
@JoanaF,感谢你发现了这个问题。现在已经进行了编辑和修复(链接:https://godbolt.org/z/8hzfe6)。 - dxiv

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