1

嗯,我知道有很多关于 的问题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

我也有尝试冲洗stdinand stdout,仍然没有用。

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

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

提前致谢。

4

6 回答 6

6

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

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

于 2013-08-10T23:32:30.877 回答
2

所以stdin(在你的系统上肯定,并且通常)是行缓冲的,这意味着在你点击“输入”之前没有输入到达程序。这意味着程序本身不必处理“退格”之类的事情。

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

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

于 2013-08-10T23:35:34.390 回答
2

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

于 2013-08-10T23:38:16.800 回答
1

对于第一个示例,这是因为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
于 2013-08-10T23:34:48.810 回答
1

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

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

于 2013-08-10T23:35:22.567 回答
0

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

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

这个想法是%s更了解空白。

于 2013-08-11T06:55:53.950 回答