如何将值附加到命令行参数数组?
Posted
技术标签:
【中文标题】如何将值附加到命令行参数数组?【英文标题】:How to append a value to the array of command line arguments? 【发布时间】:2017-09-08 09:29:30 【问题描述】:我的应用程序有入口点
int main(int argc, char *argv[])
我需要将 *argv
数组扩展为 n+1
并附加一个值。比如我需要追加"-app_ver"
。
我是 C++ 的新手(具有 Java 背景)。我知道我无法更改数组大小,所以我需要任何解决方案(任何方法复制数组等)
【问题讨论】:
你为什么要这样做? 您是否考虑过将所有值推入std::vector<std::string>
或std::vector<std::string_view>
,然后将新值附加到您想要的位置?
只需分配一个大小为argc + 2
的char *
数组,从argv[]
复制原始argc
字符串,然后在最后两个中添加您的额外值和最终NULL
元素。
听起来像一个“XY 问题”,因为您的解决方案对于任何明智的编程问题都不是正确的解决方案。你真正想要解决的核心问题是什么?
是的,因为起初在 c++ 中弄清楚数组的概念有点困难
【参考方案1】:
argv 是固定大小的内存块。您必须将整个内容(所有指针)复制到更大的数组才能扩展它。或者只是使用 std::vector<std::string> args;
并操纵这个变量,因为它会为你做这件事。
但老实说 - 重新设计您的解决方案可能是个好主意 - 可能不需要复制操作。也许像std::vector<std::string> additional_parameters;
这样的东西会满足您的需求?
【讨论】:
取决于使用的程序参数。使用std::vector<std::string>
简化了复制,但有些API 需要char**
(如Qt 中的QCoreApplication
),不能直接从向量中获取。如果不需要原始的char**
,您的方法是一个不错的方法。【参考方案2】:
您必须构造一个新数组。举个例子:
int new_argc = argc + 2;
char** new_argv = new char*[new_argc];
new_argv[argc + 1] = nullptr;
for (int ii = 0; ii < argc; ++ii)
new_argv[ii] = argv[ii];
new_argv[argc] = new char[strlen("-app_ver") + 1]; // extra char for null-terminated string
strcpy(new_argv[argc], "-app_ver");
// use new_argc and new_argv
delete[] new_argv[argc];
delete[] new_argv;
请注意,为了优化,我只分配了新参数。要创建完整副本,您必须为先前存在的参数分配内存。
请注意手动分配内存:完成后将其删除。您只需删除您创建的那些。
另一方面,由于argv
和argc
通常在main
函数中使用,这并不是什么大问题(内存泄漏)。
备注
由于我不知道这些新的命令行参数的未来用途,因此该解决方案试图保持main
函数的原始数据类型。如果将其传递给 Boost 或 Qt,则无法从更直接的选项(例如使用 std::vector<std::string>
时)获得 char**
。首先,std::string::c_str()
返回一个const char*
,这些指针在内存中不是连续的。
更安全的选择(无需手动删除)可以是:
int new_argc = argc + 1;
std::vector<std::unique_ptr<char>> new_argv_aux(new_argc); // automatically destroyed
for (int ii = 0; ii < argc; ++ii)
new_argv_aux[ii].reset(new char[strlen(argv[ii]) + 1]);
strcpy(new_argv_aux[ii].get(), argv[ii]);
new_argv_aux[argc].reset(new char[strlen("-app_ver") + 1]);
strcpy(new_argv_aux[argc].get(), "-app_ver");
// Now the actual double pointer is extracted from here
std::vector<char*> new_argv(new_argv_aux.size());
for (size_t ii = 0; ii < new_argv_aux.size(); ++ii)
new_argv[ii] = new_argv_aux[ii].get(); // soft-reference
// last element is null from std::unique_ptr constructor
use_here(new_argc, new_argv.data());
【讨论】:
【参考方案3】:就像 cbuchart 说的,你必须创建一个新数组或者一个向量。 使用向量和字符串对象可以比 char* 和数组更简单。
示例:
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
vector<string> list;
for ( int i = 1 ; i < argc ; i++)
string tmp (argv[i]);
list.push_back(tmp); // add all arguments to the vector
cout << "number of given arguments : " << list.size() << endl;
list.push_back("-app_ver"); // add one string to the vector
for ( int i = 0 ; i < list.size() ; i++)
cout << list[i] << endl; // acces data of the vector
【讨论】:
对,我尝试保留原始数据类型,因为我们不知道其用途。正如我在另一条评论中提到的,某些 API,例如 Qt 和QCoreApplication
需要 char**
,而无法直接从 std::vector<std::string>
获得。否则,这里描述的是一种动态且安全的解决方案。【参考方案4】:
要复制您的argv
,您可以使用指向char
的指针的std::vector
。
std::vector<const char*> new_argv(argv, argv + argc);
然后将新元素添加到其中:
new_argv.push_back("-app_ver");
new_argv.push_back(nullptr); // or NULL if you are using an old compiler
然后用新数组替换argv
:
argv = new_argv.data(); // or &new_argv[0] if you are using an old compiler
argc = argc + 1;
注意:在普通参数的末尾,应该有一个空指针。它很少使用(尽管标准要求它);如果您确定您的其他代码不使用它,并且您只想将一个元素添加到您的argv
数组,您可以只覆盖空指针,而不使用任何替换 argv
。也就是说,忽略上面的所有代码,直接这样做:
argv[argc++] = "-app_ver";
但是,这很危险 - 如果您决定再添加一个元素,它会崩溃,如果某些代码需要在最后一个参数之后存在空指针,它可能会崩溃。
【讨论】:
这是迄今为止解决此问题的最具表现力和 C++ 惯用的方法。自动管理的最小分配,并且仍然可以轻松地与 C API 一起使用。以上是关于如何将值附加到命令行参数数组?的主要内容,如果未能解决你的问题,请参考以下文章