【问题标题】:constructing char*const* from string从字符串构造 char*const*
【发布时间】:2013-02-04 08:09:10
【问题描述】:

我正在尝试将字符串转换为const*char*,以便能够调用库函数。我的代码如下:

// myVec is simply a vector<string> 

vector<string> myVec;
/* stuff added to myVec
 * it is a vector of words that were seperated by whitespace
 * for example myVec[0]=="Hey"; myVec[1]=="Buck"; myVec[2]=="Rogers"; etc...
 */

char*const* myT = new char*[500]; //I believe my problem stems from here

for(int z=0; z<myVec.size(); z++) {
   string temp=myVec[z]+=" "; 
   myT[z]=temp.c_str();
}
//execv call here

我正在为execv() 的第二个参数构造这个。

编译器总是抛出各种错误,当我修复另一个错误时,会弹出一个(从我使用的解决方案/google-fu 看来相当循环)。

【问题讨论】:

  • 这不是一个好主意,因为 temp 变量就是您命名它的临时变量。也就是说c_str返回的指针也是临时的。
  • temp 很好,因为 exec 调用将在此代码之后;我不知道为什么我把新的留在里面给 myT,我一直在努力让这个工作
  • 并非如此,因为temp 变量的生命周期仅在循环当前迭代内。一旦您继续下一次迭代或离开循环,编译器就可以(并且将)回收该堆栈内存。
  • 哦,你不需要分配 500 个指针,因为你有向量的大小。请记住为数组分配一个额外的条目,因为数组需要由一个空指针终止。

标签: c++ c string char constants


【解决方案1】:

有两个基本问题需要解决。这 首先是编译器错误:数组中的指针指向 myTconst,所以你不能分配给他们。制作myT char const** myT;。第二个问题是你是什么 分配给它们的是一个指向局部变量的指针,它 当它超出范围时将被破坏,因此指针 会悬空。

你调用的函数真的需要额外的白色吗 最后的空间? (你在某处提到了execv,我想。 如果这是功能,额外的空格会造成更大的伤害 比好。)如果没有,你所要做的就是:

std::vector<char const*> myT( myVec.size() + 1 );
std::transform( myVec.begin(), myVec.end(), myT.begin(),
                []( std::string const& arg ) { return arg.c_str(); } );
execv( programPath, &myT[0] );

如果您不能指望 C++11(通常仍然如此), 你可能可以用boost::bind 做类似的事情; 否则,只需自己编写循环即可。

如果您确实需要以某种方式转换 myVec 中的字符串, 最好的解决方案仍然是将它们复制到第二个 std::vector&lt;std::string&gt;,带改造,用 这个。

(BTW: 你真的要修改myVec的内容吗, by 在循环中的每个元素上使用+=?)

【讨论】:

  • 您可以使用非成员函数从string 获取c_str
  • @PeterWood 非成员函数或函数对象,但在这两种情况下,您都需要在当前函数之外编写一些特殊的东西。
【解决方案2】:

execv 的签名要求参数数组指向可修改的 C 样式字符串。因此,与其他答案所暗示的相反,c_str() 并不是一个好主意。

虽然在 C++03 中不能保证,但事实是我所知道的 std::string 的所有实现都将数据存储在连续的 NULL 终止的内存块中(这在 C++11 中得到保证),所以你可以利用这一点:创建一个指向可修改字符数组的指针向量,使用输入向量中字符串的缓冲区初始化值,并将该数据块的地址传递给execv

std::vector<char*> args;
args.reserve(myVec.size()+1);
for (std::vector<std::string>::iterator it=myVec.begin(); it != myVec.end(); ++it) {
   args.push_back(&((*it)[0]);
}
args.push_back(0);   // remember the null termination:

execv("prog", &args[0]);

【讨论】:

  • 哎哟。 execv真的要原地修改数据吗?为什么?或者这只是某人忘记了const 的情况,我们可以安全地使用const_cast 解决它? (从逻辑上讲,execv 不能更改字符串中存在的任何字符,也不能添加字符,因为它不能保证空间存在,所以我看不出它如何修改数据。)跨度>
  • @JamesKanze:我不知道有什么好的理由,但文档声称第二个参数的类型是 char * const *。那里有一个const 的事实表明这不仅仅是一个不知道const 的旧API,所以我不会假设它不会与数据混淆......
  • 我怀疑(但我没有关于 Posix 的内部信息)他们只是复制了传递给 main 的签名。在main 中,您确实 有权更改字符串(但不能更改指针数组),这就解释了有点奇怪的签名。无论如何,安全起见,你是对的;您将需要使用&amp;((*it)[0]) 而不是it-&gt;c_str()。 (但您仍然可以使用 std::transform 来完成。)
  • 还要注意,如果您将args 预先构造为正确的初始大小,则代码会更简单:您不需要reserve(无论如何您确实不需要),并且您不用担心最终的空指针,因为所有的指针都初始化为空指针。
  • @JamesKanze:正确。 Reserve+push_back 只是我习惯的一把锤子......而且你知道,当你有一把锤子时,一切看起来都像钉子:) 关于安全......这个解决方案不是 安全,它取决于标准保证之外的实现细节。您要么假设字符串实现允许我的回答,要么假设execv 不会修改并且您使用您的......在任何一种情况下,您都在祈祷并希望获得最好的结果。这个答案并不比你的好
猜你喜欢
  • 2020-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-10
  • 1970-01-01
  • 2010-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多