如何将值附加到命令行参数数组?

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 + 2char * 数组,从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; 

请注意,为了优化,我只分配了新参数。要创建完整副本,您必须为先前存在的参数分配内存。

请注意手动分配内存:完成后将其删除。您只需删除您创建的那些。

另一方面,由于argvargc 通常在main 函数中使用,这并不是什么大问题(内存泄漏)。

备注

由于我不知道这些新的命令行参数的未来用途,因此该解决方案试图保持main 函数的原始数据类型。如果将其传递给 Boost 或 Qt,则无法从更直接的选项(例如使用 std::vector&lt;std::string&gt; 时)获得 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&lt;std::string&gt; 获得。否则,这里描述的是一种动态且安全的解决方案。【参考方案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 一起使用。

以上是关于如何将值附加到命令行参数数组?的主要内容,如果未能解决你的问题,请参考以下文章

讲解命令行参数

将 GUI 附加到命令行工具

C++ 如何将命令行参数转换为数组?

在 psql 命令行上传递数组参数

从命令行参数指定数组

将命令行参数转换为 Bash 中的数组