You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ unordered_set插入触发Segmentation fault:11栈溢出排查

错误触发根因

崩溃核心原因是手写递归二分查找函数findind存在逻辑缺陷,触发无限递归导致栈溢出,具体问题点:

  • 中点索引计算错误:代码中int mid = (high - low)/2计算的是搜索区间长度的一半,并非区间内的中点索引,正确中点索引应为low + (high - low)/2,从根源上导致索引定位错误。
  • 递归无收敛逻辑:当搜索区间缩小到相邻两个元素时(如high=3、low=1),错误的mid计算会让mid值固定不变,且调整high/low的逻辑没有排除已经比较过的mid位置,递归永远无法触达匹配返回分支,无限压栈最终耗尽栈内存,触发段错误(退出码139),对应LeetCode平台AddressSanitizer报出的栈溢出错误。
  • 其他潜在问题:findind的vector参数为值传递,每次递归都会完整拷贝一份数组,栈内存消耗速度翻倍;初始调用findind时传入的high参数是数组长度N,超过数组最大合法索引N-1,本身存在数组越界访问风险。

对应你观察到的异常现象:哈希集合us只有执行insert语句时才会存入遍历过的元素,把insert替换为打印语句后,us始终为空,永远走不到调用findind的else分支,自然不会触发无限递归导致的崩溃。

以第一个复现用例numbers = {-1,0,1,4,5,7}、target=8为例:遍历到最后一个元素7时,target-7=1已经在之前的循环中被插入us,此时触发findind调用,递归过程中会进入high=3、low=1的状态,此后mid永远计算为1,每次判断目标值1大于s[1]=0,就重复将low设为1,永远无法退出递归,直接触发栈溢出。

修复方案
  1. 修正二分查找函数的所有逻辑缺陷:
    • 将vector参数改为const引用传递,避免递归时无意义的数组拷贝
    • 修正中点索引的计算方式
    • 增加区间无效的终止判断,调整边界收敛逻辑:比较完mid位置元素后,下一轮搜索直接排除mid点,确保区间每次递归都会缩小,从根本上避免死循环
    • 修正初始调用findind时的high参数,传入数组最后一个合法索引N-1

修正后的二分查找代码如下:

int findind(const vector<int>& s, int tar, int high, int low ){
    // 搜索区间为空,终止递归
    if (low > high) {
        return -1;
    }
    // 正确计算区间中点索引
    int mid = low + (high - low) / 2;
    if(s[mid] == tar){
        return mid;
    }
    else if (tar < s[mid]){
        // 目标值更小,搜索左半区间,排除已比较的mid点
        return findind(s, tar, mid - 1, low);
    }
    else{
        // 目标值更大,搜索右半区间,排除已比较的mid点
        return findind(s, tar, high, mid + 1);
    }
}

同时将main函数中调用findind的语句修正为:

id2 = findind(numbers, target - numbers[i], N-1, 0);
  1. 可选优化:本题给定数组为严格升序排列,最优解法是使用左右双指针从两端向中间夹逼,不需要哈希集合也不需要二分查找,时间复杂度O(n)、空间复杂度O(1),代码更简洁不易出错。

内容的提问来源于stack exchange,提问作者A Hasnain Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 10:54:25