将 vector<string> 转换为 char** 会导致分段错误

Posted

技术标签:

【中文标题】将 vector<string> 转换为 char** 会导致分段错误【英文标题】:Converting vector<string> to char** results in segmentation fault 【发布时间】:2016-01-02 21:13:28 【问题描述】:

我绝对是 C++ 的初学者,但我有一个任务。我必须将向量转换为 char** 才能在 execvp 中使用它。所以我写了这个构建好的测试但是当我运行它时我得到分段错误而不是“第一”。我不擅长指针,我需要你的帮助。谢谢

#include <iostream>
#include <vector>
#include <string>
#include <cstring>

using namespace std;

int main()

    vector<string>* list = new vector<string>();
    list->push_back("First");
    list->push_back("Second");
    list->push_back("Third");

    char ** arr;
    arr[0] = strdup(list->at(0).c_str());

    cout << arr[0] << endl;
    return 0;

编辑 1

好的,这是实际的问题。 Command::getCommandArray() 似乎按预期工作,但是当我从 main 调用它并尝试显示 arr[0] 时,它再次导致分段错误。为什么?

// Command.cpp
char** Command::getCommandArray()

    int i=0;
    int len = args->size() + 2;
    char* arr[len];

    arr[0] = strdup(this->commandName->c_str());
    arr[len-1] = NULL;

    for (i=0; i<this->args->size(); i++)
    
        arr[i+1] = strdup(this->args->at(i).c_str());
    

    cout << "in: " << arr[0] << endl; // PRINTS AS EXPECTED

    return arr;


// main.cpp
do 
    char** arr = tmp->getCommandArray();
    cout << arr[0] << endl; // SEGMENTATION FAULT HERE
 while((tmp = tmp->getPipeline()) != NULL);

编辑 2 好的,我解决了。非常感谢!

我不得不换行

char* arr[len];

char** arr = new char*[len];

【问题讨论】:

char** arr 是指向某个内存的指针。它指向什么内存? 你还没有初始化arr。访问它是未定义的行为。不过像const char* arr[3]; 这样的东西会更好。 那么,我应该如何初始化它?如果我不知道向量的长度? 【参考方案1】:

我认为没有理由在这里复制字符串或手动管理内存。您可以只使用另一个向量来存储 char 指针,并获取指向该向量内存的指针。

int main()

    std::vector<std::string> list;
    list.push_back("First");
    list.push_back("Second");
    list.push_back("Third");

    std::vector<char*> ptr_list;
    for (std::size_t i = 0; i != list.size(); ++i) 
        ptr_list.push_back(&list.at(i)[0]);
    

    char** arr = &ptr_list[0];

    std::cout << arr[0] << std::endl;

【讨论】:

【参考方案2】:

应该是这样的:

int main()

    std::vector<std::string> list;
    list.push_back("First");
    list.push_back("Second");
    list.push_back("Third");

    char** arr = new char*[list.size()];
    for (std::size_t i = 0; i != list.size(); ++i) 
        arr[i] = strdup(list.at(i).c_str());
    
    std::cout << arr[0] << std::endl;

    for (std::size_t i = 0; i != list.size(); ++i) 
        free(arr[i]);
    
    delete[] arr;

【讨论】:

【参考方案3】:

请注意,您传递给 execve() 的 argv 和 envp 数组需要以空值结尾(除了这些数组中的字符串):

char ** convert(std::vector<std::string> v)

    char ** t = new char* [v.size() + 1];

    // Need this for execve
    t[v.size()] = nullptr;

    for (int i = 0 ; i < v.size(); ++i)
    
        t[i] = strdup(v[i].c_str());
    

    return t;

【讨论】:

危险的:一个完全内部分配的数据结构作为指针返回。谁以及何时负责删除? 如果 execve(2) 立即使用 convert() 的结果而没有中间的 fork(2),那么就没有必要(甚至没有机会)删除。如果我使用中间的 fork(2) 执行此操作,我会将其包装在可以通过的东西中,并释放 strdup() 在其析构函数中分配的所有内容以及指针数组本身。

以上是关于将 vector<string> 转换为 char** 会导致分段错误的主要内容,如果未能解决你的问题,请参考以下文章

如何将 std::vector<std::string> 转换为 C api 的 char*[] [重复]

c++如何将vector<char>转化成string

将 vector<int> 转换为分隔字符串

将 vector<char> 作为参数,然后转换为字符串

将字符串向量转换为双二维数组向量

std::vector<std::string> 到 char* 数组