【问题标题】:getchar does not stop when using scanf使用 scanf 时 getchar 不会停止
【发布时间】:2012-09-29 15:11:31
【问题描述】:

我很难理解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")

【问题讨论】:

    标签: c getchar


    【解决方案1】:

    输入仅在您输入换行符后发送到程序,但是

    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)) 个字符到 command,为 0 终止符留出空间。

    【讨论】:

      【解决方案2】:

      Whitespace 是 5y3 %s 格式说明符的分隔符,而 newline 被视为空格,因此它保持缓冲状态。控制台输入通常是面向行的,因此对 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 - 您通常希望避免在各处重复这些检查和错误处理)。

      【讨论】:

        【解决方案3】:

        我宁愿先使用fgets,然后使用sscanf 来解析输入。我已经这样做了很长时间了,而且这种行为比使用普通的scanf 更容易预测。

        【讨论】:

          【解决方案4】:

          好吧,我有更简单的事情:添加另一个getchar() ...问题解决了!!

          【讨论】:

          • 那不一定能解决问题,缓冲区中可能还有一个字节以上,getchar() 会立即返回。
          【解决方案5】:

          在输入命令后刷新标准输入。

          fflush(stdin);
          

          但刷新输入流会导致未定义的行为(尽管 Microsoft 的 C 库将该行为定义为扩展)。

          【讨论】:

          • fflush() 未定义输入流。
          • -1: 将fflush() 应用于输入流(或输入最后一个操作的输入/输出流)是C Standard 指定的未定义行为的少数具体示例之一.
          • 请注意,虽然这适用于 Microsoft 的 C 库,但它肯定不适用于 GNU C 库。避免。
          • 我已经提到了未定义的行为。
          • IMO 仍然是个坏建议——“未定义”包括实际上根本不做任何事情。它可能不应该投反对票,但肯定不应该投赞成票。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-23
          相关资源
          最近更新 更多