繁体   English   中英

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

[英]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.

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