简体   繁体   English

C - 为什么 puts 行为异常,而 printf 在使用 scanf 时却没有?

[英]C - Why does puts behave unexpectedly, but printf does not when using scanf?

I was testing some code earlier that looked like this:我之前正在测试一些看起来像这样的代码:

char input;
int data;

while(scanf("%c %d", &input, &data) != EOF) {
    puts("foo");
}

And when I read it with the following input:当我使用以下输入阅读它时:

c 8
c 10
c 15
c 18
^D

This was my output:这是我的输出:

foo
foo
foo
foo
foo
foo
foo
foo

Although I was only really expecting to have foo printed once;虽然我只是真的希望foo打印一次; that is, once the EOF signal was sent.也就是说,一旦发送了 EOF 信号。 I also tried running it outside my IDE and manually in the terminal (because CLion has issues with EOF), and when I ran it manually through the terminal, foo would print once after the first input, and then double print each time after.我还尝试在我的 IDE 之外并在终端中手动运行它(因为 CLion 有 EOF 问题),当我通过终端手动运行它时,foo 会在第一次输入后打印一次,然后每次都打印两次。

However, when I use printf instead of puts inside the loop, my code runs as expected.但是,当我在循环中使用printf而不是puts ,我的代码会按预期运行。 I want to know why puts was causing an issue here?我想知道为什么puts 在这里引起了问题? I imagine it has something to do with the IO stream, but I am not exactly sure why this is happening.我想它与 IO 流有关,但我不确定为什么会发生这种情况。

Is this undefined behavior?这是未定义的行为吗? If so, why is that happening?如果是这样,为什么会这样?

EDIT : Someone in the comments said that they were not getting the same issue.编辑:评论中有人说他们没有遇到同样的问题。 I've attached a screenshot of my code + terminal.我附上了我的代码+终端的屏幕截图。 I am also running gcc-9.4 if that makes any difference.如果这有什么不同,我也在运行 gcc-9.4。

enter image description here在此处输入图片说明

The root of the problem is that %c does not skip over leading whitespace.问题的根源在于%c不会跳过前导空格。

Here's what's happening - your input stream contains the following sequence:这是发生的事情 - 您的输入流包含以下序列:

{ 'c', ' ', 8, '\n', 'c', ' ', 10, '\n', 'c', ' ', 15, '\n', 'c', ' ', 18, '\n' }

The first call to scanf reads 'c' into input and 8 into data and returns 2 (for two successful conversions and assignments).scanf的第一次调用将'c'读入input ,将 8 读入data并返回2 (对于两次成功的转换和赋值)。 The next call to scanf reads '\\n' into input and tries to read 'c' into data - that's a matching failure, so data isn't assigned.scanf下一次调用将'\\n'读入input尝试'c'读入data - 这是匹配失败,因此未分配data However, since '\\n' was successfully read into input , scanf returns 1 (which is not EOF ).但是,由于'\\n'已成功读入input ,因此scanf返回1 (这不是EOF )。 The next call to scanf reads ' ' into input and 10 into data .scanf的下一次调用将' '读入input ,将10读入data

Lather, rinse, repeat.起泡,冲洗,重复。 Depending on where you are in the sequence, scanf will return 2 , 1 , or 0 , none of which are the same as EOF .根据您在序列中的位置, scanf将返回210 ,其中没有一个与EOF相同。 This is why you get multiple foo outputs per line, because you're not reading what you think you're reading.这就是为什么每行会得到多个foo输出的原因,因为您没有在阅读您认为正在阅读的内容。

There are two things you need to do to fix this:您需要做两件事来解决这个问题:

  1. Put a blank in front of the %c specifier - this will tell scanf to skip over leading whitespace;%c说明符前面放一个空格 - 这将告诉scanf跳过前导空格;

  2. Instead of testing against EOF , test against 2 - you are expecting 2 successful conversions and assignments per input line:不是针对EOF进行测试,而是针对2测试 - 您期望每个输入行有 2 个成功的转换和分配:

while ( scanf( " %c %d", &input, &data ) == 2 )
  puts( "foo" );

Don't compare to EOF, count the number of valid conversions.不要与 EOF 进行比较,计算有效转换的数量。 In particular, on the input you show:特别是,在您显示的输入上:

scanf("%c %d", &input, &data) 

will read the first c into input , assign the value 8 to data , and return 2. The next character in the input stream is \\n , so the second scanf stores that in input and is unable to get an integer value out of c , so it does not write anything to data and returns 1. The next call to scanf writes c to input and sets data to 10. Rinse and repeat.将第一个c读入input ,将值 8 赋给data ,然后返回 2。输入流中的下一个字符是\\n ,因此第二个scanf将其存储在input ,并且无法从c获取整数值,所以它不会向data写入任何内容并返回 1。对scanf的下一次调用将c写入input并将data设置为 10。冲洗并重复。

You probably meant to write:你可能想写:

while(scanf(" %c %d", &input, &data) == 2) {

(note the space before the %c ). (注意%c之前的空格)。

After the first line, "%c %d" is consuming the prior line's '\\n' and then chokes on 'c' as an int , necessitating another loop to process the line .在第一行之后, "%c %d"正在消耗前一行的'\\n'然后将'c'作为int阻塞,需要另一个循环来处理该

  • Use a leading space to consume whitespace.使用前导空格来消耗空格。

  • Check results.检查结果。


// while(scanf("%c %d", &input, &data) != EOF) {
int count;
while((count = scanf(" %c %d", &input, &data)) != EOF) {
  printf("count:%d input:%c data:%d\n", 
      count, count >= 1 ? input : '?', count >= 2 ? data : -1);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么在使用struct时printf会表现出这种方式? - Why does printf behave this way when using struct? 为什么补码通过printf表现不同? - Why does the complement behave differently through printf? 为什么即使scanf中的输入值不等于1,printf函数也会打印输入的值 - Why does the printf function print the value input even when the input value in scanf is not equal to 1 "为什么 scanf() 需要 "%lf" 作为双打,而 printf() 只需要 "%f"?" - Why does scanf() need "%lf" for doubles, when printf() is okay with just "%f"? 为什么scanf(“%d”,[...])不消耗'\ n'?而scanf(“%c”)呢? - Why scanf(“%d”, […]) does not consume '\n'? while scanf(“%c”) does? printf和scanf如何循环工作? 为什么我在scanf中不需要\\ n? - How does printf and scanf work in a loop? Why I dont need \n in scanf? 为什么 C printf 在十进制为 16.125 时不四舍五入,但在 16.135 时会四舍五入 - Why does C printf not round up when decimal is 16.125 but will with 16.135 为什么在使用printf时在地址上使用表达式会显得很奇怪 - Why does using an expression on an address act weird when using printf 为什么在使用指针时printf()绕过分段失败? - why does printf() circumvents segmentation fail when using pointers? C-使用\\ b的puts()与printf() - C - puts() vs. printf() using \b
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM