std::vector<std::string> 到 char* 数组
Posted
技术标签:
【中文标题】std::vector<std::string> 到 char* 数组【英文标题】:std::vector<std::string> to char* array 【发布时间】:2011-10-26 07:22:17 【问题描述】:我有一个std::vector<std::string>
,我需要将它用于C
函数的参数,该参数为char* foo
。我有seen how 将std::string
转换为char*
。作为C++
的新手,我正在尝试拼凑如何对向量的每个元素执行此转换并生成char*
数组。
我见过几个密切相关的 SO 问题,但大多数似乎都说明了走向另一个方向并创建 std::vector<std::string>
的方法。
【问题讨论】:
什么是确切的 C 接口。根据 const 的位置以及函数在使用期间如何处理内存,我们可以做几件不同的事情(C 函数可以做一些讨厌的事情,比如调用 realloc)。 模型* ModelInitialize (char *fnames, int nterms) 该函数接受char*
,而不是您的问题中的char**
。是哪个?
字符*。对困惑感到抱歉。我无意中看到了一个将 char** fnames 作为参数并随后调用 ModelInitialize 的函数。
在函数签名中显然没有足够的信息来确定正确的行动方案。 fnames
的所有权是否转移到 ModelInitialize
? (如果是这样:它必须如何分配?)调用代码是否意味着delete
、free
或以其他方式释放从ModelInitialize
返回的Model
? (如果是这样:它必须如何被释放?)fnames
必须是一个以 null 结尾的字符串吗?可以通过哪些方式修改fnames
?
【参考方案1】:
您可以将std::transform
用作:
std::transform(vs.begin(), vs.end(), std::back_inserter(vc), convert);
这需要您将convert()
实现为:
char *convert(const std::string & s)
char *pc = new char[s.size()+1];
std::strcpy(pc, s.c_str());
return pc;
测试代码:
int main()
std::vector<std::string> vs;
vs.push_back("std::string");
vs.push_back("std::vector<std::string>");
vs.push_back("char*");
vs.push_back("std::vector<char*>");
std::vector<char*> vc;
std::transform(vs.begin(), vs.end(), std::back_inserter(vc), convert);
for ( size_t i = 0 ; i < vc.size() ; i++ )
std::cout << vc[i] << std::endl;
for ( size_t i = 0 ; i < vc.size() ; i++ )
delete [] vc[i];
输出:
std::string
std::vector<std::string>
char*
std::vector<char*>
在线演示:http://ideone.com/U6QZ5
您可以在需要char**
的任何地方使用&vc[0]
。
请注意,由于我们使用new
为每个std::string
分配内存(在convert
函数中),我们必须在最后释放内存。这使您可以灵活地更改矢量vs
;你可以给它push_back
更多的字符串,从vs
中删除现有的字符串,然后vc
(即vector<char*>
仍然有效!
但是如果你不想要这种灵活性,那么你可以使用这个convert
函数:
const char *convert(const std::string & s)
return s.c_str();
您必须将std::vector<char*>
更改为std::vector<const char*>
。
现在转换后,如果您通过插入新字符串或从中删除旧字符串来更改vs
,那么vc
中的所有char*
可能会失效。这是重要的一点。另一个重要的一点是,您不再需要在代码中使用delete vc[i]
。
【讨论】:
快速提问:如果我们使用 std::vector,为什么需要 delete [] vc 部分? @Christopher:因为我们使用new
为char*
分配内存,所以我们使用delete vc[i]
。但是我们没有为char**
分配内存,因此我们没有为delete vc
分配内存。
如果convert
中的新代码抛出,此代码将泄漏。最好使用std::vector<char>
。
@Christopher:看我的回答。现在有了更多的解释。
@Mankarse:std::vector<char>
在哪里?在转换功能?局部变量?【参考方案2】:
你能做的最好的就是分配一个std::vector
的const char*
与你的向量大小相同。然后,遍历向量的每个元素,调用c_str()
获取字符串数组并将其存储为数组的对应元素。然后,您可以将指向该向量的第一个元素的指针传递给相关函数。
代码如下所示:
std::vector<const char *> cStrArray;
cStrArray.reserve(origVector.size());
for(int index = 0; index < origVector.size(); ++index)
cStrArray.push_back(origVector[index].c_str());
//NO RESIZING OF origVector!!!!
SomeCFunction(&cStrArray[0], cStrArray.size());
请注意,您不能允许在从 std::strings
获取 const char*
s 到调用 C 函数之间调整原始字符串向量的大小。
【讨论】:
c_str() 不返回 const char 吗?如果我只需要一个 char*,那会是个问题吗? (我已经在 cmets 中包含了确切的接口。) 你也可以做 std::vector这应该可行:
char ** arr = new char*[vec.size()];
for(size_t i = 0; i < vec.size(); i++)
arr[i] = new char[vec[i].size() + 1];
strcpy(arr[i], vec[i].c_str());
编辑:
如果你的 C 函数以某种方式修改了这个数组,你可能需要以另一种方式获取大小,假设 vec 仍然具有正确数量的元素,那么你将如何释放这些数据结构。
for(size_t i = 0; i < vec.size(); i++)
delete [] arr[i];
delete [] arr;
再次编辑:
如果您的 C 函数不修改字符串,则可能不需要复制字符串。如果您能详细说明您的界面是什么样的,我相信我们可以为您提供更好的帮助。
【讨论】:
您需要展示如何删除该数组,特别是因为它非常复杂。不要忘记使用delete[]
。
如果for
中的new
抛出,则会泄漏。最好使用std::vector
。【参考方案4】:
一个 C++0x 解决方案,其中std::string
的元素保证连续存储:
std::vector<std::string> strings = /* from somewhere */;
int nterms = /* from somewhere */;
// using std::transform is a possibility depending on what you want
// to do with the result of the call
std::for_each(strings.begin(), string.end(), [nterms](std::string& s)
ModelInitialize(&s[0], nterms);
如果函数 null 终止了它的参数,那么在调用 (s.begin(), s.end())
之后可能没有意义。您可以后处理来解决这个问题:
s = std::string(s.begin(), std::find(s.begin(), s.end(), '\0'));
更精细的版本,将每个字符串分别复制到char[]
:
typedef std::unique_ptr<char[]> pointer;
std::vector<pointer> args;
std::transform(strings.begin(), strings.end()
, std::back_inserter(args)
, [](std::string const& s) -> pointer
pointer p(new char[s.size()]);
std::copy(s.begin(), s.end(), &p[0]);
return p;
);
std::for_each(args.begin(), args.end(), [nterms](pointer& p)
ModelInitialize(p.get(), nterms); );
【讨论】:
【参考方案5】:const char* 也和 char* 一样,只是 const_ness 不同,你的接口方法接受 const 和 non-const 字符串。
c_str() 不返回 const char 吗?如果我只是 需要一个 char* 吗?
是的,它返回一个常量字符串,不应该没有问题
const char*a="something";
////whatever it is here
const char* retfunc(const char*a)
char*temp=a;
//process then return temp
很多人不接受返回本地对象,这个小例子是按原样提供的。
【讨论】:
这段代码不会编译。将指向 const 的指针分配给指向非 const 的指针既不合法也不安全。 "返回本地对象不被很多人接受" // 不,这是垃圾。语言或编译器不接受将 reference 或 pointer 返回到本地对象。但这不一样。 不仅这段代码无效,而且即使你实际上抛弃了const
ness,这也是一件非常愚蠢的事情。
感谢Tomalak的指正和cmet,请不要太苛刻,这是另一个想法,如何使其更安全仍然取决于OP的实际编码经验......
“const char* 也与 char* 相同,只是 const_ness 不同”,这与说明“苹果与橙子相同,只是不同”一样有用【参考方案6】:
向量的元素是stored contiguously,所以最好最简单的方法是:
std::vector<char> v;
char* c = &v[0];
【讨论】:
以上是关于std::vector<std::string> 到 char* 数组的主要内容,如果未能解决你的问题,请参考以下文章
从 std::vector<std::vector<float>> 转换为 float**
如何将 std::vector<std::vector<double>> 转换为 torch::Tensor?
C++随机选择std::vector的非空元素<std::vector>>
如何将 std::vector<std::vector<double>> 转换为 Rcpp::Dataframe 或 Rcpp::NumericMatrix
std::vector<std::array<T, N>> 或 std::array<std::vector<T>,N> 类型的数组如何存储在内存中?