将std :: string拆分为两个const char *,导致第二个const char *覆盖第一个

时间:2012-07-03 17:02:00

标签: c++ string type-conversion cstring

我正在接受一行输入,该行由空格分隔并尝试将数据读入两个整数变量。

例如:“0 1”应该提供child1 == 0child2 == 1

我正在使用的代码如下:

int separator = input.find(' ');
const char* child1_str = input.substr(0, separator).c_str(); // Everything is as expected here.
const char* child2_str = input.substr(
    separator+1,  //Start with the next char after the separator
    input.length()-(separator+1) // And work to the end of the input string.
    ).c_str();     // But now child1_str is showing the same location in memory as child2_str!
int child1 = atoi(child1_str);
int child2 = atoi(child2_str);      // and thus are both of these getting assigned the integer '1'.
// do work

正在发生的事情令我困惑不已。我正在使用Eclipse调试器(gdb)监视序列。函数启动时,child1_strchild2_str显示具有不同的内存位置(正如它们所应)。将字符串拆分为separator并获取第一个值后,child1_str按预期保持“0”。

但是,为child2_str指定值的下一行不仅会将正确的值分配给child2_str,还会覆盖child1_str。我甚至不认为字符值被覆盖,我的意思是调试器显示child1_strchild2_str以共享内存中的相同位置。

什么是什么?

1)是的,我很乐意听取将字符串转换为int的其他建议 - 这就是我很久以前学会这样做的原因,而且我从来没有遇到过这个问题,所以永远不需要改变,但是:

2)即使有更好的方式来执行转换,我仍然想知道这里发生了什么! 这是我的终极问题。因此,即使您提出了更好的算法,所选答案也将帮助我理解我的算法失败的原因。

3)是的,我知道std :: string是C ++,const char *是标准的C. atoi需要一个c字符串。我将其标记为C ++,因为输入绝对将来自我正在使用的框架中的std :: string。

4 个答案:

答案 0 :(得分:4)

首先,优越的解决方案。

在C ++ 11中,您可以使用newfangled std::stoi函数:

int child1 = std::stoi(input.substr(0, separator));

如果失败,您可以使用boost::lexical_cast

int child1 = boost::lexical_cast<int>(input.substr(0, separator));

现在,解释。

input.substr(0, separator)创建临时 std::string对象,该对象在分号处死亡。在该临时对象上调用c_str()会为您提供一个只有临时生命才有效的指针。这意味着,在下一行,指针已经无效。取消引用该指针具有未定义的行为。然后发生了奇怪的事情,就像未定义的行为一样。

答案 1 :(得分:4)

字符串被破坏后,c_str()返回的值无效。所以当你运行这一行时:

const char* child1_str = input.substr(0, separator).c_str();

substr函数返回一个临时字符串。该行运行后,此临时字符串将被销毁,child1_str指针变为无效。访问该指针会导致未定义的行为。

您应该做的是将substr的结果分配给本地std::string变量。然后你可以在那个变量上调用c_str(),结果将一直有效,直到变量被破坏(在块的末尾)。

答案 2 :(得分:3)

其他人已经指出了您当前代码的问题。这是我如何进行转换:

std::istringstream buffer(input);

buffer >> child1 >> child2;

更简单,更直接,更不用说更灵活了(例如,即使输入在数字之间有一个或两个空格,它也会继续工作)。

答案 3 :(得分:1)

input.substr会返回一个临时std::string。由于你没有将它保存在任何地方,它会被破坏。之后发生的任何事情完全取决于你的运气。

我建议使用istringstream