这是如何指定具有动态长度的数据项序列的范围的一般问题。
有趣的是,实际上并没有很多编程模式可以解决这个问题(尽管有很多方法可以实现它们)。这个问题实际上归结为一个简单的问题:我如何知道何时停止接受价值观?
当您收到已存储的值(例如 argc/argv 或传入数组或其他容器)时,您已经拥有这些值并且您知道有多少。这是小事一桩。从文件或终端解析数据是事情开始变得有趣的地方。
这里列出了常用的“停止机制”(据我所知,所有其他机制都是前缀和/或后缀的特定应用)。
前缀序列
这是你描述的方法。在最一般的意义上,它涉及在输入前加上一些东西,告诉你有多少数据。这可能是人类级别的元素数量,也可能是机器级别的,例如从网络连接接收的字节数。
这是一个使用输入序列中的元素数量作为前缀的示例。
std::vector<int> vec;
int count, temp;
std::cin >> count;
for (int i = 0; i < count; ++i)
{
std::cin >> temp;
vec.push_back(temp);
}
请注意,使用此方法您可以立即知道序列中的元素总数,您可以使用它来简化代码并减少动态分配的数量:
std::vector<int> vec;
int count;
std::cin >> count;
vec.resize(count); // performs only one allocation
for (int i = 0; i < count; ++i) std::cin >> vec[i];
用户输入示例(控制台或文件):
4 3 5
4 88 -90
2
结果值(vec):
3, 5, 4, 88
后缀序列
与前缀序列类似,您也可以为该序列添加一些值来表示停止的位置。这通常被称为终止符(例如,C 风格的字符串以零字节终止,即'\0')。
这个例子展示了如何读取一个非负整数序列。我们使用第一个负值作为停止条件:
std::vector<int> vec;
int temp;
while (std::cin >> temp && temp >= 0) vec.push_back(temp);
用户输入示例(控制台或文件):
4 3 5
4 88 -90
2
结果值(vec):
4, 3, 5, 4, 88
到达 EOF
如果您从文件中读取,EOF(文件结尾)可以用作停止机制。它本质上是系统特定的前缀和/或后缀组合。例如,正在使用的特定文件系统结构通常会以字节为单位存储文件的长度。这本质上是前缀方法(尽管在这种情况下前缀值实际上并没有出现在数据序列中)。
这种方法很受欢迎,因为文件只包含一系列相同类型的元素是很常见的。它可以与cin 一起使用,但前提是cin 已经从文件中重定向(否则你永远不会 - 传统上 - 到达终点,因为它只会以交互方式等待更多输入作为控制台会话)。
std::vector<int> vec;
std::ifstream file("nums.txt");
int temp;
while (file >> temp) vec.push_back(temp);
事实上,这种用法非常普遍,以至于 STL 添加了std::istream_iterator,以便以安全的、类似于库的方式轻松编写。在这种情况下,它并不是真的更好,但取决于你在做什么迭代器可以更方便 - 例如您可以将它们输入std::accumulate() 以获得总和。下面是一个使用std::istream_iterator 做同样事情的例子:
std::vector<int> vec;
std::ifstream file("nums.txt");
std::copy(std::istream_iterator<int>(file), std::istream_iterator<int>(),
std::back_inserter(vec));
示例用户输入(文件):
4 3 5
4 88 -90
2
结果值(vec):
4, 3, 5, 4, 88, -90, 2
行尾
使用行尾(即'\n')作为停止条件在技术上是一种后缀序列方法,但它足够不同且足够普遍,我认为应该直接解决它,特别是关于你正在尝试的内容完成。
您可以使用未格式化的输入函数行std::cin.get() 手动搜索您要保留或忽略的字符,但这很繁琐且容易出错。我将要演示的方法比手动方法慢,但如果性能不是问题,它们会非常优越(尤其是对于具有重载流提取运算符的更复杂的类型)。
我们将从cin(以换行符'\n' 终止)读取整行文本,然后解析出它的值。
std::vector<int> vec;
std::string line;
int temp;
std::getline(std::cin, line);
std::istringstream ss(line);
while (ss >> temp) vec.push_back(temp);
如果您想使用标准实用程序(或者如果您需要迭代器):
std::vector<int> vec;
std::string line;
std::getline(std::cin, line);
std::istringstream ss(line);
std::copy(std::istream_itereator<int>(ss), std::istream_iterator<int>(),
std::back_inserter(vec));
用户输入示例(控制台或文件):
4 3 5
4 88 -90
2
结果值(vec):
4, 3, 5