我不知道为什么只有一个代码在两个代码之间有SIGSEGV(看起来一样)

时间:2019-02-27 14:09:50

标签: c++

第一次,我这样编码(我正在做一个特里),当我调用add(“ 911”);当* str =='1'

时,我出现了分段错误
struct Node {
    int check, check2;
    Node* chd[10];
    Node() : check(0), check2(0), chd{0, } {}
    ~Node() {
        for (int i = 0; i < 10; i++)
            if (chd[i])
                delete chd[i];
    }
    int add(char* str) {
        if (!str[0])
            return 0;
        if (chd[*str-'0'] == 0)          // here I got SIGSEGV
            chd[*str-'0'] = new Node();
        ...
        return chd[*str-'0']->add(++str);
    }
}

然后我像这样固定那部分

        int i = *str-'0';
        if (chd[i] == 0)
            chd[i] = new Node();

没有错误。

有什么区别?是什么使第一个代码产生错误?

(我正在解决ACM-ICPC>地区>欧洲>西北欧区域竞赛>北欧大学编程竞赛> NCPC 2007 A)

2 个答案:

答案 0 :(得分:2)

return chd[*str-'0']->add(++str);

在您修改和使用str无序列时包含不确定的行为。

您的“修复程序”具有经典的行为,可以将某些内容四处移动以隐藏未定义的行为。请记住,未定义的行为是未定义的。它不必崩溃。它甚至没有任何意义。而且最可怕的是它至少可以暂时满足您的期望。

一个简单的更改是:

return chd[*str-'0']->add(str+1);

答案 1 :(得分:0)

此行具有未定义的行为

return chd[*str-'0']->add(++str);

因为str的修改和使用没有顺序。

快速解决方法是(当您指++时不要说+ 1):

return chd[*str-'0']->add(str + 1);

但是您也可以通过只计算一次相关索引来避免该问题(听起来这是您解决问题的方式,并且是更好的解决方案):

int add(char* str) {
    if (!str[0])
        return 0;
    char c = str[0] - '0';
    if (chd[c] == 0)
        chd[c] = new Node();
    ...
    return chd[c]->add(str + 1); // And ++str would also work...