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

合并非递减数组的C代码触发AddressSanitizer堆溢出错误,求排查

合并有序数组时的堆溢出问题分析

你遇到的AddressSanitizer: heap-buffer-overflow错误确实是数组索引访问越界导致的。以下是具体分析和修正方案:

原实现代码

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    int index = 0;
    int index1 = 0;
    int index2 = 0;
    int count1 = 0;
    int count2 = 0;
    int result[m + n];
    while(index < m + n) {

        if(nums1[index1] <= nums2[index2] && count1 < m && index1 < nums1Size) {
            count1++;
            result[index++] = nums1[index1++];
        }
        else if(count2 < n && index2 < nums2Size) {
            count2++;
            result[index++] = nums2[index2++];
        }
    }

    for(int i = 0; i < m + n; i++) {
        nums1[i] = result[i];
    }
}

测试代码

int main() {
    int num1[6] = {1,2,3,0,0,0};
    int num2[3] = {2,5,6};
    merge(num1, 6, 3, num2, 3, 3);
    for(int i = 0; i < 6; i++) {
        printf("%d ", num1[i]);
    }
}

错误原因分析

  • 越界访问触发点:当其中一个数组的有效元素取完后,循环仍会尝试访问该数组的越界索引。比如count1 == m时,if条件里的nums1[index1] <= nums2[index2]仍会访问nums1的index1位置,此时index1已等于m,超出了有效元素的索引范围(0~m-1)。
  • 冗余变量干扰逻辑:count1和index1完全同步(每次同时自增),count1 < m等价于index1 < m,额外维护count1反而增加出错概率;且index1 < nums1Size判断多余——nums1的有效元素仅前m个,无需关注数组整体大小。

修正后的代码

方案1:保留额外数组的正确实现

去掉冗余变量,分阶段处理剩余元素:

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    int index = 0;
    int index1 = 0;
    int index2 = 0;
    int result[m + n];
    
    // 合并两个数组的有效元素
    while(index1 < m && index2 < n) {
        if(nums1[index1] <= nums2[index2]) {
            result[index++] = nums1[index1++];
        } else {
            result[index++] = nums2[index2++];
        }
    }
    
    // 处理nums1剩余的有效元素
    while(index1 < m) {
        result[index++] = nums1[index1++];
    }
    
    // 处理nums2剩余的有效元素
    while(index2 < n) {
        result[index++] = nums2[index2++];
    }
    
    // 将结果复制回nums1
    for(int i = 0; i < m + n; i++) {
        nums1[i] = result[i];
    }
}

方案2:原地合并(无需额外数组,更高效)

利用nums1末尾的空闲空间,从后往前双指针合并,避免元素移动:

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    int p1 = m - 1; // nums1有效元素的最后一个索引
    int p2 = n - 1; // nums2有效元素的最后一个索引
    int p = m + n - 1; // 合并后数组的最后一个索引
    
    // 从后往前合并较大的元素
    while(p1 >= 0 && p2 >= 0) {
        if(nums1[p1] > nums2[p2]) {
            nums1[p--] = nums1[p1--];
        } else {
            nums1[p--] = nums2[p2--];
        }
    }
    
    // 若nums2还有剩余元素,复制到nums1前端
    while(p2 >= 0) {
        nums1[p--] = nums2[p2--];
    }
}

验证结果

用你的测试代码运行任意修正版本,都会输出正确结果:1 2 2 3 5 6

内容的提问来源于stack exchange,提问作者Zhe Lin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 08:07:50