字符串拆分为矢量<字符*>覆盖矢量元素

String split into vector<char*> overwrites vector elements

本文关键字:元素 gt 覆盖 lt 拆分 字符串 字符      更新时间:2023-10-16

使用https://stackoverflow.com/a/236803/6361644中提到的以下代码,我编写了以下代码来将字符串解析为向量,其中每个元素由空白分隔。

std::string line = "ls -l -a";
std::string cmd;
std::vector<char*> argv;
std::stringstream ss;
ss.str(line); 
std::string tmp;
getline(ss, cmd, ' ');
argv.push_back( const_cast<char*>(cmd.c_str() ) );
while(getline(ss, tmp, ' '))
    argv.push_back( const_cast<char*>(tmp.c_str() ) );
argv.push_back(NULL);

在这段代码之后打印argv得到

{gdb) print argv                                                                         
$22 = std::vector of length 3, capacity 4 = {0x26014 "ls", 0x2602c "-a", 0x2602c "-a", 0x0} 

我不确定为什么第二个元素被覆盖了。

您正在以一种不正确的方式存储悬空指针!c风格字符串指针的正确存储方式是const char*,而不是char*)。

在这个(const校正)循环中:

std::vector<const char*> argv;
// ...
while(getline(ss, tmp, ' '))
    argv.push_back(tmp.c_str());

之后的每次迭代都将清除tmp,使之前存储的指针失效。你推开的每一个tmp.c_str()都会立即被getline()释放。因此,所有后续访问都是未定义的。

你必须获得所有字符串的所有权,你可以通过存储完整的string来实现:

std::vector<std::string> argv;
// ...
while(getline(ss, tmp, ' '))
    argv.push_back(std::move(tmp));

现在argv实际上拥有自己的所有资源。

c_str()返回的指针指向std::string的内部数据

该指针仅在字符串被销毁或修改之前有效。一旦std::string被销毁或修改,该指针就不再有效。

while(getline(ss, tmp, ' '))
    argv.push_back( const_cast<char*>(tmp.c_str() ) );

先不考虑转换const属性的问题,这已经是一个危险信号:每次while循环迭代时,tmp的内容都会被ss文件中的下一行所替换。

这将自动使在while循环的前一次迭代中获得的c_str()无效。

这里的正确解决方案是首先将所有单个单词解析为std::vector<std::string>

然后,在vector对象初始化之后,遍历vector对象并获得每个字符串的c_str(),以构造包含原始字符指针的vector对象。

甚至更好:使用std::vector<char>代替std::string,在每个向量的末尾添加一个显式的''字符,丑陋的const_cast将不需要。