如何在给定的输入线为整数的情况下创建数组,其中第一个整数是长度?

时间:2019-05-30 23:24:24

标签: c++ arrays

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

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

1 个答案:

答案 0 :(得分:2)

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

有趣的是,实际上并没有很多编程模式可以实现(尽管有很多方法可以实现它们)。问题实际上可以归结为一个简单的问题:我如何知道何时停止取值?

当您收到已经存储的值(例如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