简体   繁体   English

为什么 scanf 可以使用 for 循环读取一行中的多个输入?

[英]Why can scanf read multiple inputs in a line with a for loop?

I wanted to store n values given (n was known) in an array but I didn't know how to do it, so I looked and found this post: C, reading multiple numbers from single input line (scanf?) , and this answer:我想将给定的 n 个值(n 已知)存储在一个数组中,但我不知道该怎么做,所以我查看并找到了这篇文章: C, reading multiple numbers from single input line (scanf?)和这个回答:

int main()
{
    int i, size, *v;
    scanf("%d", &size);
    v = malloc(size * sizeof(int));
    for (i=0; i<size; i++)
        scanf("%d", &v[i]);
    printf("%d %d %d", v[0], v[1], v[2]);
}

I don't understand why scanf can do that, shouldn't the function, in every iteration of the loop, ask for another input?我不明白为什么 scanf 可以做到这一点,函数不应该在循环的每次迭代中要求另一个输入吗? How can it read one int, then another and so on, as long as they are separated by spaces?只要它们用空格分隔,它如何读取一个 int,然后读取另一个等等? How can scanf behave that way? scanf 怎么会这样呢? Because it seems like it shouldn't.因为它似乎不应该。

PS: I only wrote the final print statement with 3 values for simplicity, in "my case" size was 3. PS:为简单起见,我只用 3 个值编写了最终打印语句,在“我的情况”中,大小为 3。

Thank you in advance!先感谢您!

When you type in some numbers on your console and hit ENTER, you are providing an input stream to your code via stdin.当您在控制台上输入一些数字并按 ENTER 时,您将通过标准输入向您的代码提供输入流。 The entire contents of what you type in are kept in that input stream.您输入的全部内容都保存在该输入流中。 So if you type所以如果你输入

2 4 6 8 2 4 6 8

and hit enter, the input stream contains:2 4 6 8然后回车,输入流包含:2 4 6 8

Now, each of your scanfs is only reading (and removing) a single integer from that input stream, so after a single scanf, the stdin input stream now contains: 4 6 8现在,您的每个 scanfs 仅从该输入流中读取(和删除)一个整数,因此在单个 scanf 之后,stdin 输入流现在包含: 4 6 8

The extra input is not discarded, it is still available in the input stream, so your next scanf can come along and grab the next integer from the stream, and the next, and the next.....until the data in the input stream is exhausted.额外的输入不会被丢弃,它仍然在输入流中可用,所以你的下一个 scanf 可以出现并从流中获取下一个整数,下一个,下一个......直到输入中的数据流已用尽。

This is one of the surprising things about scanf .这是scanf令人惊讶的事情之一。

If I write如果我写

scanf("%d %d %d", &a, &b, &c);

it looks like I'm expecting to read a line with three numbers on it.看起来我希望阅读一行包含三个数字的行。 But if what the user actually types is但是如果用户实际输入的是

1
2
3

(that is, on three separate lines), it'll "work" just fine. (也就是说,在三个单独的行上),它会“工作”得很好。 scanf wanted three integers, and it found them, but it had to read three lines in order to do so. scanf想要三个整数,它找到了它们,但它必须读取三行才能这样做。

Contrariwise, if I wrote相反,如果我写

scanf("%d", &a);
scanf("%d", &b);
scanf("%d", &c);

and the user typed和用户输入

4 5 6

on one line, again, this'll "work" just fine, there were three scanf calls asking for a total of three ints, and there were three ints there -- although they happened to be on one line.再一次,在一行上,这会“工作”得很好,有三个scanf调用要求总共三个整数,并且那里有三个整数——尽管它们恰好在一行上。

And in your case, your scanf call in a loop has about the same effect as the several separate scanf calls.在您的情况下,您在循环中的scanf调用与几个单独的scanf调用的效果大致相同。

The bottom line is that scanf is not line-based.底线是scanf不是基于行的。 There is no one-to-one correspondence between calls to scanf and expected lines of input.scanf的调用和预期的输入行之间没有一一对应的关系。 scanf does not treat newline characters specially -- they're just treated as whitespace, separating other input fields. scanf不会特别处理换行符——它们只是被视为空格,分隔其他输入字段。

(By way of comparison, printf isn't line-based, either, although it does at least treat \n characters specially. But there's no different in output between (相比之下, printf也不是基于行的,尽管它至少会特别处理\n字符。但输出之间没有区别

printf("one ");
printf("two ");
printf("three\n");

and

printf("one two three\n");

.) .)

After reading the original question, I think I understand what you are asking.阅读原始问题后,我想我明白你在问什么。

So in the other question the input was:所以在另一个问题中,输入是:

5<ENTER>
1 2 3 4 99<ENTER>

scanf is a function design to read formatted input (the name comes from scan formatted), it is not design to read random user input. scanf是一个读取格式化输入的函数设计(名称来自scan formatted),它不是读取随机用户输入的设计。

To quote the man page of scanf:引用 scanf 的手册页:

man scanf人扫描

#include <stdio.h> int scanf(const char *format, ...);

DESCRIPTION描述

The scanf() family of functions scans input according to format as described below. scanf()系列函数根据如下所述的format扫描输入。 This format may contain conversion specifications ;此格式可能包含conversion specifications the results from such conversions, if any, are stored in the locations pointed to by the pointer arguments that follow format.此类转换的结果(如果有)存储在遵循格式的指针参数所指向的位置。 Each pointer argument must be of a type that is appropriate for the value returned by the corresponding conversion specification.每个指针参数的类型必须适合相应转换规范返回的值。

That means that scanf scans the input according to the provided format.这意味着 scanf 根据提供的格式扫描输入。 The conversion specifier %d matches an optionally signed decimal integer.转换说明符%d匹配可选带符号的十进制整数。 If your format contains only "%d" it will consume any white-space characters and try to convert the next sequence of non-white-space characters into an signed int .如果您的格式仅包含"%d" ,它将消耗任何空白字符并尝试将下一个非空白字符序列转换为带signed int If this is possible, scanf will store the converted integer in the memory pointed to by the passed argument.如果可能, scanf会将转换后的整数存储在传递参数指向的内存中。 If it fails at converting, it stops scanning and any other character in the input buffer will remain in the input buffer.如果转换失败,它将停止扫描,输入缓冲区中的任何其他字符都将保留在输入缓冲区中。

So let's to this: You enter 3 numbers like this:所以让我们这样做:您输入 3 个这样的数字:
3 SPACE SPACE 4 SPACE TAB 5 ENTER 3空格空格4空格选项卡5 ENTER

Your input buffer will look like this:您的输入缓冲区将如下所示:

+---+---+---+---+---+----+---+----+
| 3 | █ | █ | 4 | █ | \t | 5 | \n |
+---+---+---+---+---+----+---+----+

In the first iteration scanf consume any white-space characters, right now there is none, so it will read 3 and continue with the next character which is a space.在第一次迭代中scanf消耗任何空白字符,现在没有,所以它将读取 3 并继续下一个字符,即空格。 At that point it stops and converts the 3 and stores it in &v[i] .此时它停止并转换 3 并将其存储在&v[i]中。 The input buffer will look like this:输入缓冲区将如下所示:

+---+---+---+---+----+---+----+
| █ | █ | 4 | █ | \t | 5 | \n |
+---+---+---+---+----+---+----+

In the second iteration it will consume any white-space characters.在第二次迭代中,它将消耗任何空白字符。 There are two spaces there and those are just consumed.那里有两个空间,它们只是被消耗掉了。 Then it will read 4, and then a white-space character.然后它将读取 4,然后是一个空白字符。 scanf stops and and converts the 4 and stores it in &v[i] . scanf停止并转换 4 并将其存储在&v[i]中。 The input buffer will look like this:输入缓冲区将如下所示:

+---+----+---+----+
| █ | \t | 5 | \n |
+---+----+---+----+

As you can see, in every iteration scanf didn't wait block and wait for the user to enter something, because characters were left in the input buffer from the previous iterations.如您所见,在每次迭代中, scanf都没有等待块并等待用户输入某些内容,因为之前的迭代中字符都留在了输入缓冲区中。

And that's why you can have scanf("%d", &v[i]) in a loop for an input like this "1 2 3 4 5" .这就是为什么您可以在循环中使用scanf("%d", &v[i])以获取像这样的输入"1 2 3 4 5"

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM