如何将一个值添加到命令行参数的数组中?

6

我的应用程序有入口点。

int main(int argc, char *argv[])
{

}

我需要扩展*argv数组到n+1并追加一个值。例如,我需要追加"-app_ver"
作为一个C++新手(有Java背景),我知道我不能改变数组大小,因此我需要任何解决方案(复制数组的任何方法等)。

3
为什么你想要这样做? - SingerOfTheFall
你是否考虑过将所有值推入 std::vector<std::string>std::vector<std::string_view> 中,然后在需要时添加新值? - KABoissonneault
只需分配一个大小为 argc + 2char * 数组,从 argv[] 中复制原始的 argc 个字符串,然后将您的额外值和最后一个 NULL 添加到数组的最后两个元素中。 - Paul R
3
听起来像是一个“XY问题”,也就是说,你的解决方案对于任何合理的编程问题都不是正确的解决方案。你实际上想要解决的核心问题是什么? - Lundin
是的,因为一开始在C++中理解数组的概念有点困难。 - Nodirbek Shamsiev
4个回答

17

要复制您的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";
然而,这种方法很危险——如果您决定添加一个以上的元素,它将会崩溃;并且,如果某些代码要求在最后参数之后存在空指针,则可能会导致崩溃。

2
这绝对是解决这个问题最具表现力和符合C++惯用法的方式。最小化分配,自动管理,仍然可以轻松地与C API一起使用。 - willkill07

2

像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>获得。否则,这里描述的方法是一种动态且安全的解决方案。 - cbuchart

0

argv是固定大小的内存块。您必须将整个内容(所有指针)复制到更大的数组中才能扩展它。或者只需使用std::vector<std::string> args;并操纵此变量,它将为您完成。

但说实话,重新设计您的解决方案可能是一个好主意-复制操作可能是不必要的。也许像std::vector<std::string> additional_parameters;这样的东西可以满足您的需求?


这取决于程序参数的使用。使用std::vector<std::string>简化了复制过程,但某些API需要char **(例如Qt中的QCoreApplication),而且不能直接从向量获取。如果原始的char**不是必需的,则您的方法很好。 - cbuchart

0

你必须构建一个新的数组。这里是一个例子:

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<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());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接