合并非递减数组的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
相关产品推荐
相关产品推荐

