[英]Why can scanf read multiple inputs in a line with a for loop?
我想将给定的 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]);
}
我不明白为什么 scanf 可以做到这一点,函数不应该在循环的每次迭代中要求另一个输入吗? 只要它们用空格分隔,它如何读取一个 int,然后读取另一个等等? scanf 怎么会这样呢? 因为它似乎不应该。
PS:为简单起见,我只用 3 个值编写了最终打印语句,在“我的情况”中,大小为 3。
先感谢您!
当您在控制台上输入一些数字并按 ENTER 时,您将通过标准输入向您的代码提供输入流。 您输入的全部内容都保存在该输入流中。 所以如果你输入
2 4 6 8
然后回车,输入流包含:2 4 6 8
现在,您的每个 scanfs 仅从该输入流中读取(和删除)一个整数,因此在单个 scanf 之后,stdin 输入流现在包含: 4 6 8
额外的输入不会被丢弃,它仍然在输入流中可用,所以你的下一个 scanf 可以出现并从流中获取下一个整数,下一个,下一个......直到输入中的数据流已用尽。
这是scanf
令人惊讶的事情之一。
如果我写
scanf("%d %d %d", &a, &b, &c);
看起来我希望阅读一行包含三个数字的行。 但是如果用户实际输入的是
1
2
3
(也就是说,在三个单独的行上),它会“工作”得很好。 scanf
想要三个整数,它找到了它们,但它必须读取三行才能这样做。
相反,如果我写
scanf("%d", &a);
scanf("%d", &b);
scanf("%d", &c);
和用户输入
4 5 6
再一次,在一行上,这会“工作”得很好,有三个scanf
调用要求总共三个整数,并且那里有三个整数——尽管它们恰好在一行上。
在您的情况下,您在循环中的scanf
调用与几个单独的scanf
调用的效果大致相同。
底线是scanf
不是基于行的。 对scanf
的调用和预期的输入行之间没有一一对应的关系。 scanf
不会特别处理换行符——它们只是被视为空格,分隔其他输入字段。
(相比之下, printf
也不是基于行的,尽管它至少会特别处理\n
字符。但输出之间没有区别
printf("one ");
printf("two ");
printf("three\n");
和
printf("one two three\n");
.)
阅读原始问题后,我想我明白你在问什么。
所以在另一个问题中,输入是:
5<ENTER>
1 2 3 4 99<ENTER>
scanf
是一个读取格式化输入的函数设计(名称来自scan formatted),它不是读取随机用户输入的设计。
引用 scanf 的手册页:
#include <stdio.h> int scanf(const char *format, ...);
描述
scanf()
系列函数根据如下所述的format
扫描输入。 此格式可能包含conversion specifications
; 此类转换的结果(如果有)存储在遵循格式的指针参数所指向的位置。 每个指针参数的类型必须适合相应转换规范返回的值。
这意味着 scanf 根据提供的格式扫描输入。 转换说明符%d
匹配可选带符号的十进制整数。 如果您的格式仅包含"%d"
,它将消耗任何空白字符并尝试将下一个非空白字符序列转换为带signed int
。 如果可能, scanf
会将转换后的整数存储在传递参数指向的内存中。 如果转换失败,它将停止扫描,输入缓冲区中的任何其他字符都将保留在输入缓冲区中。
所以让我们这样做:您输入 3 个这样的数字:
3空格空格4空格选项卡5 ENTER
您的输入缓冲区将如下所示:
+---+---+---+---+---+----+---+----+
| 3 | █ | █ | 4 | █ | \t | 5 | \n |
+---+---+---+---+---+----+---+----+
在第一次迭代中scanf
消耗任何空白字符,现在没有,所以它将读取 3 并继续下一个字符,即空格。 此时它停止并转换 3 并将其存储在&v[i]
中。 输入缓冲区将如下所示:
+---+---+---+---+----+---+----+
| █ | █ | 4 | █ | \t | 5 | \n |
+---+---+---+---+----+---+----+
在第二次迭代中,它将消耗任何空白字符。 那里有两个空间,它们只是被消耗掉了。 然后它将读取 4,然后是一个空白字符。 scanf
停止并转换 4 并将其存储在&v[i]
中。 输入缓冲区将如下所示:
+---+----+---+----+
| █ | \t | 5 | \n |
+---+----+---+----+
如您所见,在每次迭代中, scanf
都没有等待块并等待用户输入某些内容,因为之前的迭代中字符都留在了输入缓冲区中。
这就是为什么您可以在循环中使用scanf("%d", &v[i])
以获取像这样的输入"1 2 3 4 5"
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.