[英]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。
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
将返回2
、 1
或0
,其中没有一个与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:您需要做两件事来解决这个问题:
Put a blank in front of the %c
specifier - this will tell scanf
to skip over leading whitespace;在%c
说明符前面放一个空格 - 这将告诉scanf
跳过前导空格;
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.