为什么strtok修改stl容器

时间:2014-06-17 13:37:24

标签: c++ stl

在下面的代码中,我希望输出为abc#def。但我得到输出为abcdef。似乎strtok正在修改向量,即使我没有直接将向量传递给strtok函数。我可以知道它是如何发生的吗?

std::vector<std::pair<const std::string, int>> x;

std::vector<std::string> z;

int main()
{

    char* pch;
    x.push_back(std::make_pair("abc#def", 1));

    std::string m = x[0].first;

    pch = strtok ((char*)(m.c_str()),"#");

    while (pch != NULL)
    {
        z.push_back(pch);
        pch =strtok (NULL, "#");
    }

    cout<<x[0].first<<endl;

    return 0;
}

3 个答案:

答案 0 :(得分:0)

std::string的复制实例可能使用相同的后备缓冲区。即x [0],m实际上可能使用相同的后备缓冲区。

这就是c_str()成员返回const char *的原因 - 您不能修改它。

您正在使用C样式转换(char *)来抛弃const。

通常,更好地使用C ++强制转换:static_cast&lt;&gt; / reinterpret_cast&lt;&gt; / dynamic_cast&lt;&gt;和const_cast&lt;&gt;如果你真的需要剥离const。后者仅用于在没有const限定符的情况下连接旧的C代码。您不需要在普通的C ++代码中使用它。

答案 1 :(得分:0)

在您的实现中,c_str()必须返回对字符串的内部char缓冲区的引用,而不进行任何复制。来自glibc strtok

的联机帮助页
  

BUGS

     

使用这些功能时要小心。如果您确实使用它们,请注意:

     
      
  • 这些函数修改了他们的第一个参数。
  •   

所以,是的,strtok应用于从c_str()返回的指针将修改字符串缓冲区。

您应该使用std::getline代替strtok将字符串拆分为#

std::vector<std::pair<const std::string, int>> x;

int main() {
    x.push_back(std::make_pair("abc#def", 1));

    std::string m = x[0].first;
    std::string token;

    while(std::getline(m, token, '#')) {
        std::cout << token << std::endl;
    }

    cout<< x[0].first <<endl;

    return 0;
}

或者,如果确实需要使用strtok,至少要复制c_str()strdup返回的缓冲区(并记住free() }它)。

答案 2 :(得分:0)

而是使用strtok使用find_first_of&amp; find_first_not_of

string方法 像这样:

using namespace std;
int main () {
    string s="abc#def";
    string temp = s,res;
    while(temp.size()){
        size_t st,en;
        st = temp.find_first_not_of("#");
        en = temp.find_first_of("#",st);

        res= temp.substr(st,en);
        cout<<res.c_str()<<endl;
        temp=(en == string::npos) ? "" : temp.substr(en);
    }
  return 0;
}