为什么getchar()不等待我在scanf()后按下回车键?

22

我正在学习C语言,使用"getchar()"来停止命令窗口以便能够查看我正在执行的练习,但它不起作用。以下是一个示例:

#include <stdio.h>

int main()
{
    int value;
    printf("1. option 1.\n2. option 2.\n3. option 3.\n4. Exit\n\nMake an option: ");
    scanf("%d", &value);
    switch (value)
    {
        case 1:
            printf("you selected the option 1.");
            break;
        case 2:
            printf("you selected the option 2.");
            break;
        case 3:
            printf("you selected the option 3.");
            break;
        case 4:
            printf("goodbye");
            break;
        default:
            printf("thats not an option");
            break;
    }
    getchar();
    return 0;
}

这是输出结果:

  1. 选项1。
  2. 选项2。
  3. 选项3。
  4. 退出。

请选择一个选项:1

您选择了选项1。

进程返回0(0x0),执行时间为3.453秒

按任意键继续。

为什么它不等待“getchar()”的输入?


请查看https://dev59.com/rEnSa4cB1Zd3GeqPMDlO#1384089。 - Andrew Keeton
10个回答

25

你的scanf只读取了数字而没有读取行尾换行符。在%d后面加上一个换行符或空格会导致另一个问题,读取过多。

这就是为什么人们不喜欢scanf的原因。

我建议读取一整行(使用fgets(3)),然后使用sscanf()扫描字符串。


9
首先,不要使用fflush()来清除输入流;其行为是未定义的:
7.19.5.2.2 如果流指向输出流或最近的操作不是输入的更新流,则fflush函数会导致该流的所有未写数据传递给主机环境以写入文件;否则,行为未定义。
问题在于尾随的换行符没有被"%d"转换说明符消耗,因此它被getchar()立即捕获。解决这个问题的方法有很多种,但一般的方法是将整行作为文本读取(使用fgets()或带大小的%s转换说明符的scanf()),这将消耗换行符,然后使用sscanf()strtol()strtod()将其转换为目标数据类型。

你能否给我们一个例子吗?我无法在我的代码中实现它。 - Raul Chiarella

3

getchar是否能够获取您在1后输入的回车符?


是的,getchar() 获取终止输入的换行符,因此它不需要等待太久,因为数据已经在其缓冲区中了。 - Jonathan Leffler
如果那是错误的话,那就太糟糕了。我喜欢fflush的答案并正在尝试它。 - John Lockwood
2
但这是未定义的行为,可能是不可移植的,并且特别不建议用于类似作业的学习体验。请遵循已发布和标准化的API! :-) - DigitalRoss

2

如前所述,scanf在读取用户输入后会留下换行符“\n”。

解决方案:在scanf后直接添加getchar()。

这样可以弥补scanf的不足。

例如:

int value; 
printf("1. option 1.\n2. option 2.\n3. option 3.\n4. Exit\n\nMake an option: "); 
scanf("%d", &value);
getchar();
switch (value) 

2
getchar()在scanf函数中读取键盘上的\n - 更多信息请参见此处

2
我认为您在输入“1”后输入了回车键。它会被 getchar() 接收。因此,您可以在原有的 getchar() 后添加一个额外的 getchar(),并且放在 return 0; 前面,这样就可以简单地解决问题。

** 我测试过了,它有效。


2
你正在遇到一个回车符的问题,我会通过定义一个字符来解决它,然后只需扫描回车符即可。 char ch; (在你的getch()之前输入以下内容) scanf("%c",&ch); getchar(); 这样应该可以解决问题,虽然不是最有效的方法,但对我来说有效。

0

在阅读其他答案时,我突然想到可以使用scanf("%d\n",&n);而不是scanf("%d",&n);来从缓冲区中删除换行符。虽然我还没有验证过这个方法。

希望它能起作用:D


我认为这对于递归函数不起作用,但对于循环应该可以正常工作。"你不能讨好每个人" - Jayanta Banik
1
这个代码不会按预期工作。由于格式字符串中有\n,所以在输入数字后,scanf函数只有在输入非空白字符之后才会返回。 - dbush

-2
#include <stdio.h> 
#include<conio.h>
void main() 
{ 
    int value; 
    printf("1. option 1.\n2. option 2.\n3. option 3.\n4. Exit\n\nMake an option: "); 
    scanf("%d", &value); 
    switch (value) 
    { 
        case 1: 
            printf("you selected the option 1."); 
            break; 
        case 2: 
            printf("you selected the option 2."); 
            break; 
        case 3: 
            printf("you selected the option 3."); 
            break; 
        case 4: 
            printf("goodbye"); 
            break; 
        default: 
            printf("thats not an option"); 
            break; 
    } 
    getch(); 
} 

1
那么,你的答案是使用 getch 吗?如果确实是这样,你能否更清楚地解释一下? - Felix Frank

-10
为了让您的程序正常运行,在调用getchar()之前,应该使用fflush(stdin)清除输入流。这样做的原因是,当您在键盘上输入一个数字然后按回车键时,输入缓冲区会获取这两个字符,例如“1”和“\n”,而scanf只会获取“1”,所以“\n”仍留在输入缓冲区中。当您调用getchar时,您将获取那个剩余的“\n”。清空输入可以丢弃所有缓冲区。

3
fflush(stdin) 是"未定义行为",不要使用它。请勿这样做。 - Andrew Keeton
那我该怎么做呢?我真的很新手,我的第一门编程语言是Python,所以关于内存管理的一切对我来说都是陌生的。 - user158057
1
哇,我不知道,刚做了一些研究,发现这个解释:http://www.gidnetwork.com/b-57.html - nairdaen
2
请查看我在https://dev59.com/rEnSa4cB1Zd3GeqPMDlO#1384089中的答案或被接受的答案。问题归结为a)使用`fgets`读取整行,然后使用`sscanf`解析它,或者b)再加入第二个`getchar`来“吃掉”换行符。 - Andrew Keeton
3
抱歉对于 fflush(stdin) 的态度比较严厉,但这是其中一件事情,看起来应该是有效的,直到它导致一个你无法追踪的错误。 - Andrew Keeton
我已经删除了我的回答,因为这是一个非常糟糕的想法 :) - warren

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