简体   繁体   中英

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:

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? How can it read one int, then another and so on, as long as they are separated by spaces? How can scanf behave that way? 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.

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. The entire contents of what you type in are kept in that input stream. So if you type

2 4 6 8

and hit enter, the input stream contains: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

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.

This is one of the surprising things about 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.

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.

And in your case, your scanf call in a loop has about the same effect as the several separate scanf calls.

The bottom line is that scanf is not line-based. There is no one-to-one correspondence between calls to scanf and expected lines of input. scanf does not treat newline characters specially -- they're just treated as whitespace, separating other input fields.

(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("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.

To quote the man page of 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. This format may contain 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. The conversion specifier %d matches an optionally signed decimal integer. 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 . If this is possible, scanf will store the converted integer in the memory pointed to by the passed argument. 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 SPACE SPACE 4 SPACE TAB 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. At that point it stops and converts the 3 and stores it in &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. scanf stops and and converts the 4 and stores it in &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.

And that's why you can have scanf("%d", &v[i]) in a loop for an input like this "1 2 3 4 5" .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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