两段看似相同的字典树代码为何触发SIGSEGV?求错误原因
为什么直接用
*str-'0'作为数组下标会触发段错误,而先存变量就没事? 这是个典型的C++未定义求值顺序导致的坑!我来给你一步步拆解清楚:
两段代码的核心差异
你遇到的问题根源其实在return语句里的表达式,你标记的if判断行只是错误爆发的地方:
原代码的风险点
原代码的return语句是:
return chd[*str-'0']->add(++str);
这里的致命问题是:表达式中的*str(获取当前字符)和++str(移动指针到下一个字符)的求值顺序是未定义的。C++标准并没有规定这两个操作的执行顺序,编译器可以自由选择先执行哪一个。
如果编译器先执行++str,再计算*str-'0':
- 比如处理第一个字符
'9'时,++str会把指针直接移动到'1' - 此时
*str-'0'得到的是1,而不是预期的9 - 因为
chd[1]还没有被初始化(是nullptr),你会调用nullptr->add(...) - 进入
add函数后,this指针是无效的(nullptr),此时访问this->chd(也就是chd[*str-'0'])就会触发段错误(SIGSEGV)
修改后代码的安全点
你修改后先把当前字符的下标存到变量i中:
int i = *str-'0'; // ... return chd[i]->add(++str);
这里i的值在++str执行前就已经确定了,不管编译器什么时候执行++str,chd[i]指向的都是当前字符对应的正确节点,不会出现访问nullptr的情况,自然不会触发段错误。
为什么错误会在if (chd[*str-'0'] == 0)爆发?
当你调用nullptr->add(...)时,成员函数add会被执行(因为成员函数的地址是编译期确定的,不需要this指针来查找),但函数内部访问任何成员变量(比如chd数组)时,需要通过this指针来定位内存,而this是nullptr,所以访问chd就会触发内存访问错误,也就是你看到的段错误。
额外的小建议
- 尽量避免在同一个表达式中同时修改指针/变量和读取它的值,这很容易触发未定义行为
- C++中字符串字面量应该用
const char*接收,而不是char*(虽然很多编译器兼容,但这是不符合标准的写法)
内容的提问来源于stack exchange,提问作者nngm
相关产品推荐
相关产品推荐

