C++字符串拆分分段错误

Posted

技术标签:

【中文标题】C++字符串拆分分段错误【英文标题】:C++ string splitting segmentation error 【发布时间】:2012-05-28 19:32:07 【问题描述】:

我将一个字符串拆分成一个字符串向量

    vector<string> tokens;

    stringstream strstm(str);
    string item;
    while (getline(strstm, item, ' ')) 
        tokens.push_back(item);
    

    token_idx = 0;

    cout << "size = " << tokens.size() << endl;

    for (unsigned int i = 0; i < tokens.size(); i++)
    
        cout << tokens[i] << "[" << i << "]" << endl;
     

拆分成功,size() 及其元素就是我喜欢的样子。但是,当我尝试获取它的值时,最后一个令牌的行为似乎很奇怪。

string Lexer::consume() 
    if (hasValue()) 
        token_idx++;
        cout << "consumed " << tokens[token_idx-1] << " tokens = " << token_idx -1 << endl;
        return tokens[token_idx-1];
    
    cout << "didn't consume, token_idx = " << token_idx << endl;
    return "null";

hasVal 是这样的

bool Lexer::hasValue() 
    if ( token_idx < tokens.size()) 
        return true;
     else 
        return false;
    

如果我有一个像1 + 2 * 3 这样的输入字符串,我的程序的预期输出应该是(+1(*23)),但是我遇到了分段错误。

size = 5
1[0]
+[1]
2[2]
*[3]
3[4]
consumed 1 tokens = 0
consumed + tokens = 1
consumed 2 tokens = 2
consumed * tokens = 3
consumed 3 tokens = 4
Segmentation fault (core dumped)

但是如果我将有值检查更改为( token_idx &lt; tokens.size() -1 ),程序将返回(+1 (*2 null))

size = 5
1[0]
+[1]
2[2]
*[3]
3[4]
consumed 1 tokens = 0
consumed + tokens = 1
consumed 2 tokens = 2
consumed * tokens = 3
didn't consume, token_idx = 4
(+1 (*2 null))

所以我想知道在拆分我所做的方式时,在 3 之后是否有行尾,或者是否有其他一些因素导致了这种行为?我很确定我不会超出向量的范围。

【问题讨论】:

我在核心转储文件上使用了 gdb,但是它给我的信息非常模糊,并没有告诉我它在我的代码中的哪一行崩溃了。使用命令gdb prefixer core.3211 我得到Core was generated by ./prefixer'。程序以信号 11 终止,分段错误。 #0 0x0000003b1229c0d3 in std::basic_string, std::allocator >::size() const () from /usr/lib64/libstdc++.so.6 缺少单独的调试信息,使用:debuginfo-install glibc-2.12-1.47.el6_2.12.x86_64 libgcc-4.4.6-3.el6.x86_64 libstdc++-4.4.6-3.el6.x86_64` 你是用g++编译的吗?使用 -g 选项? 如果你在崩溃后使用where,你肯定会得到一些信息。 @puller 你能详细说明如何包含where。我不太熟悉使用核心转储文件:( @JasonHu 只需在 gdb 终止程序运行后键入where&lt;enter&gt; 【参考方案1】:

我认为生成错误的真正有罪的代码没有显示给她,但因为我能感觉到你操纵索引的方式......没有什么神秘的,你在访问令牌列表的末尾时出错了,在除了容易出错的设计,仅此而已。

if (hasValue())  // has value is useless to me
    token_idx++;  // why incrementing this here ?

    cout << "consumed " << tokens[token_idx-1] << " tokens = " << token_idx -1 << endl;

    return tokens[token_idx-1];

改成这样:

if ( token_idx < tokens.size() )  
    cout << "consumed " << tokens[token_idx] << " tokens = " << token_idx << endl;

    return tokens [ token_idx++ ];

另请阅读recursive descent parsing,它非常简单,您将在解析方面更加了解,避免常见的陷阱。

【讨论】:

以上是关于C++字符串拆分分段错误的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C++ 中拆分字符串而不将其他库安装到标准 Ubuntu 版本? [复制]

拆分字符串的最佳方法是啥? (c++) [重复]

使用 C++ 拆分字符串 [重复]

在 C++ 中在左侧拆分字符串

在 C++ 中拆分字符串

你如何在 C++ 中拆分数组?