我正在尝试创建一个函数,该函数返回一个数组的地址,该数组是通过从用户获取一行输入而创建的,其中第一个整数是长度。例如,如果来自用户的输入为“ 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 ...
答案 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(文件结尾)可以用作停止机制。它本质上是前缀和/或后缀的特定于系统的组合。例如,正在使用的特定文件系统结构通常将以字节为单位存储文件的长度。本质上,这是前缀方法(尽管在这种情况下,前缀值实际上并不出现在数据序列中)。
此方法之所以受欢迎,是因为只有一个包含相同类型元素序列的文件很常见。它可以与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