c++ - 如何在给定一行输入的整数中创建一个数组,其中第一个整数是长度?
问题描述
我正在尝试创建一个函数,该函数返回一个数组的地址,该数组是通过从用户那里获取单行输入而创建的,其中第一个整数是长度。例如,如果用户的输入是“5 19 8 26 12 9”,则相应的数组将是 [19, 8, 26, 12, 9](长度为 5)。
我这样做的方式不是在函数运行后从用户那里获取输入,而是将其作为参数 (argc,argv) 例如。“./a.out 5 19 8 26 12 9”。我想知道是否还有其他可能的解决方案可能使用 scanf 或 cin ...
解决方案
这是如何指定具有动态长度的数据项序列的范围的一般问题。
有趣的是,实际上并没有很多编程模式可以解决这个问题(尽管有很多方法可以实现它们)。这个问题实际上归结为一个简单的问题:我怎么知道什么时候停止接受价值观?
当您收到已经存储的值(例如 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_iterator
to 做同样事情的例子:
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
推荐阅读
- python - redis 流式处理消费者组内的有序处理
- python - ImportError:缺少可选依赖项“xlrd”。安装 xlrd >= 1.0.0 以获得 Excel 支持 使用 pip 或 conda 安装 xlrd
- python - 使用 Python、PyQt5 在 GUI 中显示图形
- python - 二进制数组值
- spring - 在 Mockito.when 中使用 Map 中的匹配值
- dbt - 根据 dbt 中的唯一键更新目标表上的记录(数据构建工具)
- api - Azure 应用服务 http 标头 url 编码
- wpf - 如果我们使用禁用 contxtmenu
- reactjs - react-hook-form 错误:transformToNestObject 不是函数
- django - 带有 CSRF 令牌的 Chrome 扩展请求