【问题标题】:convert vector<string> into char** C++将 vector<string> 转换为 char** C++
【发布时间】:2014-11-19 20:10:07
【问题描述】:

我有一个vector&lt;std::string&gt; 变量。我需要将它传递给一个接受char**作为输入参数的方法。

如何做到这一点?如果可能的话,我需要传递一个可写的。

更新 1: 在用于创建服务方法的工具中,我将参数指定为 std::vector,但它会自动将限定符设置为 &,这意味着该工具生成的我的方法定义将如下所示:

std::string SvcImpl::myMethodname ( const std::string par1, const std::vector<     std::string >& par2, const std::vector< std::string >& par3 )
{

}

此方法会自动调用,并使用传递的参数中的值。 现在从这个方法内部,我将调用 lib 文件夹中的 dll 中的一个方法,如下所示:

int method_to_be_called(char* par1, char ** par2, char ** par3, void* pRetValue);

for par1 --> 我正在传递 (char*)par1.c_str()

我需要知道如何为 par2 和 par3 以及 pRetValue 传递变量。 par2 和 par3 的值在向量中可用,但最后一个参数 pRetValue 是一个输出参数,我需要将其作为 std::string 返回。

对不起,如果我很困惑或提出非常基本的问题。

【问题讨论】:

  • 那么你的操作应该在*writable,假设**writable正在接受你的char **参数。
  • 我认为您需要生成一个新的std::vector&lt;char*&gt; 来存储所有字符串数据的地址。
  • 你传递的这个方法到底是做什么的?
  • 您真的需要将字符串的内容复制到新数组中,还是直接使用指向底层数据的指针?
  • @juanchopanza “基础数据”将是一个字符串对象数组,你不能像他们是一个 c 字符串数组一样遍历它们。

标签: c++ c


【解决方案1】:

只要函数不修改传入的char**,不复制所有std::strings即可解决问题。否则我别无选择,只能将所有内容复制到新的 char**` 结构中(参见第二个示例)

void old_func(char** carray, size_t size)
{
    for(size_t i = 0; i < size; ++i)
        std::cout << carray[i] << '\n';
}

int main()
{
    std::vector<std::string> strings {"one", "two", "three"};
    std::vector<char*> cstrings;
    cstrings.reserve(strings.size());

    for(size_t i = 0; i < strings.size(); ++i)
        cstrings.push_back(const_cast<char*>(strings[i].c_str()));

    // Do not change any of the strings here as that will
    // invalidate the new data structure that relies on
    // the returned values from `c_str()`
    //
    // This is not an issue after C++11 as long as you don't
    // increase the length of a string (as that may cause reallocation)

    if(!cstrings.empty())
        old_func(&cstrings[0], cstrings.size());
}

示例2:如果函数必须修改传入的数据:

void old_func(char** carray, size_t size)
{
    for(size_t i = 0; i < size; ++i)
        std::cout << carray[i] << '\n';
}

int main()
{
    {
        // pre C++11
        std::vector<std::string> strings {"one", "two", "three"};

        // guarantee contiguous, null terminated strings
        std::vector<std::vector<char>> vstrings;

        // pointers to rhose strings
        std::vector<char*> cstrings;

        vstrings.reserve(strings.size());
        cstrings.reserve(strings.size());

        for(size_t i = 0; i < strings.size(); ++i)
        {
            vstrings.emplace_back(strings[i].begin(), strings[i].end());
            vstrings.back().push_back('\0');
            cstrings.push_back(vstrings.back().data());
        }

        old_func(cstrings.data(), cstrings.size());
    }

    {
        // post C++11
        std::vector<std::string> strings {"one", "two", "three"};

        std::vector<char*> cstrings;   
        cstrings.reserve(strings.size());

        for(auto& s: strings)
            cstrings.push_back(&s[0]);

        old_func(cstrings.data(), cstrings.size());
    }
}

注意:经过修改以提供更好的代码。

【讨论】:

  • 很好,尽管在第二个版本中我会使用一个向量或至少一个 unique_ptr 来保存指针数组,并使用某种 scope_exit 工具来删除里面的指针。如果此处任何单个字符串分配失败,则所有先前的字符串以及指针数组都会泄漏。
  • 在您的代码注释中,您写道“这不是 C++11 之后的问题”。你能解释一下为什么吗?
  • @lefenzy 我编辑了评论,因为它并不完全准确。但在C++11 之前,不能保证c_str() 返回的指针指向字符串的实际数据(可能是临时缓冲区)。在C++11 之后,它保证指向字符串实际数据。只有当你增加字符串的长度时它才会失效。
  • 一直在寻找一个好的答案——这就是我需要的,没有人提到过的:c_str() 函数!谢谢!
【解决方案2】:

Galik 的回答存在许多安全问题。这是我在现代 C++ 中的做法:

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

void old_func(char** carray, std::size_t size)
{
    for(std::size_t i(0); i < size; ++i)
        std::cout << carray[i] << '\n';
}

void other_old_func(const char** carray, std::size_t size)
{
    for(std::size_t i(0); i < size; ++i)
        std::cout << carray[i] << '\n';
}

int main()
{
    {
        std::cout << "modifiable version\n";
        std::vector<std::string> strings{"one", "two", "three"};
        std::vector<char*> cstrings{};

        for(auto& string : strings)
            cstrings.push_back(&string.front());

        old_func(cstrings.data(), cstrings.size());

        std::cout << "\n\n";
    }
    {
        std::cout << "non-modifiable version\n";
        std::vector<std::string> strings{"four", "five", "six"};
        std::vector<const char*> cstrings{};

        for(const auto& string : strings)
            cstrings.push_back(string.c_str());

        other_old_func(cstrings.data(), cstrings.size());
        std::cout << std::endl;
    }
}

没有混乱的内存管理或讨厌的const_casts。

Live on Coliru.

输出:

modifiable version
one
two
three


non-modifiable version
four
five
six

【讨论】:

  • 请注意,如果您使用的是&amp;string.front,文档中声明:“不应在空字符串上调用此函数。”我相信在实践中它将与&amp;string[0]datac_str 相同,但它可能会触发调试警告。
【解决方案3】:

此问题的评分最高的答案希望您使用 char** 参数传递一个大小。但是在 method_to_be_call() 中,无法传递 par2 和 par3 的大小,因此这些 c 样式字符串列表可能期望以空值结尾。换句话说,字符串列表 (char **) 中的最后一个字符串 (char*) 必须是空指针。这是许多 c 库中的常见范例。

int method_to_be_called(char* par1, char ** par2, char ** par3, void* pRetValue);

解决这个问题的最方便的方法可能是采用更 c 风格的答案。

//directly create char** par2
std::vector<std::string> par2Vect{"one", "two", "three"};
char ** par2 = (char**) malloc( sizeof(char*)*(par2Vect.size() + 1) );
for(size_t i = 0; i < par2Vect.size(); ++i)
{
    par2[i] = strdup(par2Vect[i].c_str());
}
// set the last entry to null to signify the end of the list
par2[par2Vect.size()] = nullptr;

// call your library
method_to_be_called(..., par2,...);

// delete par2
for(size_t i = 0; i < par2Vect.size(); ++i)
{
    // free memory for each c-style string
    free(par2[i]);
}
// free memory for outer char* array 
free(par2);

【讨论】:

  • 使用strdup分配的内存使用malloc,因此应该使用free而不是delete释放
【解决方案4】:

我相信这相当容易,并且可以在没有太多复杂性的情况下完成。

std::vector<std::string> vector = {"a", "std::vector", "of", "std::string"};
// Result char**.
char** result = new char*[vector.size()];
for (int index = 0; index < vector.size(); index++) {
    result[index] = const_cast<char*>(vector[index].c_str());
}
// Use the result.
delete[] result;
// Deallocate the memory from heap after usage.

【讨论】:

  • 这最终与accepted answer 相同,除了手动内存管理。这并没有增加任何有用的东西。
猜你喜欢
  • 2014-05-16
  • 2012-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多