首页 > 解决方案 > 如何在给定一行输入的整数中创建一个数组,其中第一个整数是长度?

问题描述

我正在尝试创建一个函数,该函数返回一个数组的地址,该数组是通过从用户那里获取单行输入而创建的,其中第一个整数是长度。例如,如果用户的输入是“5 19 8 26 12 9”,则相应的数组将是 [19, 8, 26, 12, 9](长度为 5)。

我这样做的方式不是在函数运行后从用户那里获取输入,而是将其作为参数 (argc,argv) 例如。“./a.out 5 19 8 26 12 9”。我想知道是否还有其他可能的解决方案可能使用 scanf 或 cin ...

标签: c++arrays

解决方案


这是如何指定具有动态长度的数据项序列的范围的一般问题。

有趣的是,实际上并没有很多编程模式可以解决这个问题(尽管有很多方法可以实现它们)。这个问题实际上归结为一个简单的问题:我怎么知道什么时候停止接受价值观?

当您收到已经存储的值(例如 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 风格的字符串以零字节 ie 终止'\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);

事实上,这种用法非常普遍,以至于添加了 STLstd::istream_iterator以使其易于以安全的、类似于库的方式编写。在这种情况下,它并不是真的更好,但取决于你在做什么迭代器可能更方便 - 例如你可以将它们输入std::accumulate()以获得总和。下面是一个使用std::istream_iteratorto 做同样事情的例子:

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

推荐阅读