使用const转换将std字符串转换为char *

时间:2014-10-07 04:48:33

标签: c++ string const-cast

在尝试创建一个shell几天之后,我会请求一些帮助。我已经开始使用不同的数据结构超过4次,并请求解决以下问题。我有一个字符串,我需要打破单个参数,并有一个指向它的指针。我最终将args传递给了一个exec函数,但由于我似乎无法正确填充args我得到了有趣的结果,这里是发生了什么的简化版本

char* args[100];
int counter=0;
string temp = "some text and stuff here";
stringstream s (temp);
while(s>> temp)
{
    cout << "TOKEN " << counter << " =" << temp <<endl;
    args[counter]=const_cast<char *> (temp.c_str());
    counter++;
}
//print the debug info
      for( int ii=0; args[ii] != NULL; ii++ )
    {
      cout << "Argument OUT " << ii << ": " << args[ii] << endl;
    }

这段代码不起作用,我无法理解为什么。 结果存储&#34; here&#34;在args的每个值中,但计数器都会改变。

TOKEN 0 =some
TOKEN 1 =text
TOKEN 2 =and
TOKEN 3 =stuff
TOKEN 4 =here
Argument OUT 0: here
Argument OUT 1: here
Argument OUT 2: here
Argument OUT 3: here
Argument OUT 4: here

3 个答案:

答案 0 :(得分:2)

执行此操作时:

args[counter]=const_cast<char *> (temp.c_str());

您没有复制字符串,只存储指向其内容的指针。所以当然它们都指向相同的temp字符串,这使得在打印时它们的值完全相同。

如果您只使用std::vector<std::string> args,这会更容易。

答案 1 :(得分:1)

可能是因为temp对象正在重用其内部分配。存储c_str()结果时,只存储内存地址。每次从字符串流中读取std::string类时,c_str()类都不创建全新的分配,而是重用已有的分配(如果可能)。

此外,在对<{1}}对象进行任何之后,使用std::string返回的指针会调用未定义的行为。 1 < / SUP>

如果可能,只需将args更改为std::vector<std::string>即可。如果这不可能,那么您需要strdup() c_str()返回的指针,以便创建一个全新的分配,在那一刻复制字符串的值。当然,当你完成时,你必须记住free()分配。

此外,丢弃const限定符并写入指针会导致未定义的行为。 2 至少您需要将args更改为{{1}但是我强烈建议使用字符串向量。


1 http://en.cppreference.com/w/cpp/string/basic_string/c_str

  

const char * args[100];获得的指针可能会失效:

     
      
  • 将对字符串的非const引用传递给任何标准库函数,或
  •   
  • 在字符串上调用非const成员函数,不包括c_str()operator[]at()front()back()begin()rbegin()end()
  •   

2 http://en.cppreference.com/w/cpp/string/basic_string/c_str

  

写入通过rend()访问的字符数组是未定义的行为。


根据您的评论表明您需要使用c_str(),听起来您确实需要一个指针数组 - exec()。但是,我们仍然可以使用向量来做到这一点。您需要一个向量来保存char个对象,这些对象将拥有std::string分配。然后你可以使用另一个向量来保存实际的指针。像这样:

char*

在这种情况下,const char * binaryPath = "/bin/foo"; std::vector<std::string> argStrings; std::vector<char *> argPointers; std::string temp = "some text and stuff here"; istringstream s(temp); // argv[0] should always contain the binary's path. argPointers.push_back(binaryPath); while (s >> temp) { argStrings.push_back(temp); std::cout << "TOKEN " << argStrings.size() << " =" << argStrings.back() << std::endl; // We cast away the const as required by the exec() family of functions. argPointers.push_back(const_cast<char *>(argStrings.back().c_str())); } // exec() functions expect a NULL pointer to terminate the arguments array. argPointers.push_back(nullptr); // Now we can do our exec safely. execv(binaryPath, &argPointers[0]); 拥有实际的字符串分配,我们只使用argStrings来保存我们将传递给argPointers的指针数组。 execv()是安全的,因为const_cast不会修改字符串。 (对于与旧C代码的兼容性,参数为execv();函数的行为就像参数为char * const []。)

答案 2 :(得分:0)

你需要分别存储每个字符串,存储指向临时对象的指针是不可取的。 E.g。

#include <iostream>
#include <vector>
#include <sstream>

using namespace std;

void exec(char* args[])
{
    for (int i = 0; args[i] != NULL; ++i)
      cout << args[i] << endl;
}

int main() 
{
  string temp = "some text and stuff here";
  stringstream s (temp);    

  vector<string> tokens;
  while(s>> temp)
  {
    tokens.push_back(temp);
  }

  int counter = 0;
  char *args[100];
  for (auto it = tokens.begin(); it != tokens.end(); ++it)
    args[counter++] = const_cast<char*>(it->c_str());
  args[counter] = NULL;

  exec(args);

  return 0;
}

你可以运行它here