【问题标题】:Why scanf("%c\n") have a delay in stdin为什么 scanf("%c\n") 在标准输入中有延迟
【发布时间】:2013-08-10 23:23:00
【问题描述】:

嗯,我知道有很多关于scanf 的问题,但我还是想问。希望有人能解释一下这个问题的规则或原则:

代码优先:

   #include <stdio.h>

   int main()
   {
           int c = 'W';
           while(c != 'F'){

                   scanf("%c",&c);
                   printf("c is : %c\n",c);
           }
           return 0;
   }

这是输出:

E
c is : E
c is :                  <--newline

G
c is : G
c is :                  <---newline again

W
c is : W
c is :                  <---newline 

F
c is : F

好吧,我现在仍然可以理解,对于我输入的换行符,每次按字母后都会留在缓冲区和赋值 c。所以,我尝试 code2:

  #include <stdio.h>

   int main()
   {
           int c = 'W';
           while(c != 'F'){

                   scanf("%c\n",&c);   //<-- the only modified place.
                   printf("c is : %c\n",c);
          }
          return 0;
  } 

然后我得到这个屏幕:

E
G                        <---why the input and has one step before the output? 
c is : E         
W
c is : G
S
c is : W
C
c is : S
F
c is : C
R                       <---R was left in stdin, turn to a garbage, I didn't hope this. 
c is : F

我也试过刷stdinstdout,还是没用。

注意:我知道如果使用scanf("%c",c);和另一个scanf("%c",&amp;d);后面处理'\n'可以解决这个问题,我只是困惑,我希望明白为什么code2的问题发生了。

我之前已经检查过答案,但我不是一个很细心的人,如果这个答案真的重复,所有的反对意见都可以理解。 :)

提前致谢。

【问题讨论】:

  • 您最好只使用scanf("%c ",&amp;c),它会跳过所有尾随空格。
  • 当在scanf()的格式末尾使用\n时,是时候考虑fgets()scanf()了。

标签: c stdin scanf


【解决方案1】:

将连续空白的任意组合传递给 scanf(包括空格、制表符和换行符,无论如何)意味着“读取直到出现第一个非空白”(包括 EOF)。

在您的 second 示例中,scanf 读取“E”,读取换行符并仍然等待非空白出现。

【讨论】:

  • "在您的第二个示例中,scanf 读取 'E',读取换行符并仍然等待非空白出现。",您应该指定此语句仅适用对于他的第二个示例。
【解决方案2】:

所以stdin(在您的系统上肯定是一般情况下)是行缓冲的,这意味着在您点击“回车”之前没有输入到达程序。这意味着程序本身不必处理“退格”之类的事情。

当您使用"%c\n" 时,scanf 仅在输入后接受换行符。如果不存在,则会被忽略。

正如评论中所建议的,"%c " 将跳过“任何空白”(我相信换行符、制表符、空格和换页符都算作“空白”)。但是您仍然不能保证将“任何输入”作为一个字符读取,而不会将某些内容作为“不需要的输入”。 scanf 绝对不适合阅读人工输入的输入。它有利于读取机器生成的数据,因为它很灵活并且可以处理一堆不同的格式,但是对于输入错误的人来说,它并不是那么好。要么使用fgets()(也许sscanf然后解析输入,但至少你没有得到“用户为这一行输入的一些东西,等待下一轮阅读”类型的惊喜”或使用低级的、系统相关的输入函数,或者像ncurses 这样的库。

【讨论】:

  • "%c " 没有用 , 换行。我试过了。
  • 就像我说的,它可能没有多大帮助。 scanf 根本不适合“人工输入”。
【解决方案3】:

"\n" in scanf 并不意味着需要换行符。你可以在这里找到解释:http://c-faq.com/stdio/scanfhang.html

【讨论】:

    【解决方案4】:

    我相信 yeputons 对您所看到的行为提供了最好的解释,但要解决您的实际问题(令人惊讶的是,我在 StackOverflow 上还没有找到),请参阅这篇文章:http://classes.soe.ucsc.edu/cmps012a/Fall98/faq/scanfQ.html

    它建议使用scanf("%*[ \n\t]%c",&amp;c);,它将跳过字符前的所有空格。通过在字符之前而不是之后跳过空格,您无需等待进一步的输入。

    【讨论】:

    • 更简单的scanf(" %c",&amp;c) 不会实现同样的效果吗?顺便说一句:[ \n\t] 不是 all 空白字符,但肯定是常见的。
    • @chux 我认为这就是重点:也许用户有意发送(比如说)一个垂直标签。根据用途,您甚至可能希望允许制表符和空格。但我将其作为来源的引用发布。如果我写它,我会照你说的做,使用标准空格(除非我有特殊要求)
    【解决方案5】:

    对于第一个示例,这是因为 scanf 一次从 stdin 读取一个字符。既然这样做了,在终端中,您将需要为scanf 输入一个空格字符才能开始从流中提取。所以看起来你正在输入以下序列:

    E, (new line), G, (new line), ...
    

    ...因此输出将与您的示例中一样。

    与您的第二个示例类似,除了您正在读取一个字符后跟一个换行符(scanf( "%c\n" ) 与仅一个字符相反 - 但推理相同。

    备注:

    如果您通过管道传输以下文本文件:

    EGJKF
    

    ...那么它就会有你期望的输出:

    c is : E
    c is : G
    c is : J
    c is : K
    c is : F
    

    【讨论】:

      【解决方案6】:

      如果使用得当,scanf 没有任何问题。

      对于这个问题,请尝试使用"%1s" 的格式并将 c 指向长度为 2 的 char 字段并测试 c[0] 的数据。

      这个想法是%s 更能识别空白。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-08-31
        • 2015-12-02
        • 2015-11-19
        相关资源
        最近更新 更多