getchar在使用scanf时不会停止

9
我很难理解getchar()。在下面的程序中,getchar按预期工作:
#include <stdio.h>


int main()
{
    printf("Type Enter to continue...");
    getchar();
    return 0; 
} 

然而,在下面的程序中,getchar 不会创建延迟,程序会立即结束:

#include <stdio.h>

int main()
{
    char command[100];
    scanf("%s", command );
    printf("Type Enter to continue...");
    getchar();
    return 0; 
} 

我有以下奇怪的解决方法,它可以运行,但我不明白为什么:
#include <stdio.h>

int main()
{
    char command[100];
    int i;
    scanf("%s", command );
    printf("Type Enter to continue...");
    while ( getchar() != '\n') {
      i=0; 
    }
    getchar();
    return 0;    
}

所以我的问题是:
1. scanf 是做什么的?为什么 scanf 要这样做?
2. 为什么我的解决方法有效?
3. 模拟以下 Python 代码的好方法是什么:

raw_input("Type Enter to continue")
5个回答

14

只有在您输入换行符后,输入才会发送到程序中。

scanf("%s", command );

由于%s(1)格式在遇到非空白字符后的第一个空白字符时停止,因此留下了输入缓冲区中的换行符。getchar()会立即返回该换行符,而不需要等待进一步的输入。

您的解决方法有效是因为在再次调用getchar()之前清除了输入缓冲区中的换行符。

为了模拟这种行为,请在打印消息之前清除输入缓冲区。

scanf("%s", command);
int c;
do {
    c = getchar();
}while(c != '\n' && c != EOF);
if (c == EOF) {
    // input stream ended, do something about it, exit perhaps
} else {
    printf("Type Enter to continue\n");
    getchar();
}

(1)注意,在scanf中使用%s非常不安全,你应该通过设置字段宽度来限制输入内容的大小。例如scanf("%99s", command)将最多读取99个字符(即sizeof(command) - 1),留出空间放置0结束符。


3

空格是5y3 %s格式说明符的分隔符,换行符被视为空格,因此它保留在缓冲区中。控制台输入通常是按行定向的,因此对getchar()的后续调用将立即返回,因为“行”仍然缓冲。

scanf("%s", command );
while( getchar() != '\n' ){ /* flush to end of input line */ }

同样地,如果你使用getchar()或%c获取单个字符,通常需要清空缓冲区,但在这种情况下,输入的字符本身可能是一个换行符,因此需要稍微不同的解决方案:

scanf("%c", ch );
while( ch != '\n' && getchar() != '\n' ){ /* flush to end of input line */ }

同样对于getchar()函数:
ch = getchar();
while( ch != '\n' && getchar() != '\n' ){ /* flush to end of input line */ }

当然,明智的做法是将这些解决方案封装到独立的专用输入函数中,您可以重复使用它们,并将其用作放置常见输入验证和错误检查代码的位置(如Daniel Fischer的答案中明智地检查EOF - 您通常希望避免在每个地方都重复进行这些检查和错误处理)。


2

我更喜欢先使用fgets然后再用sscanf来解析输入。我长期以来一直都是这样做的,行为比使用普通的scanf更加可预测。


-2

嗯,我有一个更简单的方法:添加另一个 getchar() ... 问题解决了!


这并不一定解决问题,你仍然可能在缓冲区中有多个字节,而 getchar() 将立即返回。 - Pablo

-4

在接收命令输入后清空标准输入流。

fflush(stdin);

但是清空输入流会导致未定义的行为(尽管Microsoft的C库将其定义为扩展功能)。


2
输入流未定义fflush()。 - Clifford
1
-1:对于输入流(或最后一次操作为输入的输入/输出流),应用 fflush()C标准指定的少数未定义行为的具体示例之一。 - pmg
我已经提到了未定义行为。 - Debobroto Das
是我给你的回答点了踩。在回答中还没有提到“未定义行为”的信息时,我就已经这样做了。当我注意到你已经修改了回答后,我无法取消点踩,但我在编辑你的回答后立即撤销了它。对于造成的困惑请道歉。 - pmg
1
在我看来,这仍然是一个糟糕的建议 - “未定义”包括实际上根本不做任何事情。它可能值得一个负分,但绝对不值得一个正分。 - Clifford
显示剩余3条评论

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