C++归并排序算法异常行为求助:莫名出现值16
排查归并排序中的奇怪随机值bug
嘿,我一眼就揪出你代码里的问题了——这是数组越界访问导致的栈内存污染,那些莫名其妙的16就是栈里的垃圾数据被错误读出来了!
问题根源分析
你在merge函数里的第二个判断条件完全搞错了维度:
else if (s2 > r)
s2是辅助数组aux的索引,而r是原数组的右边界,两者根本不是一个体系的!aux数组的长度是r-l+1,它的有效索引范围是0到r-l(因为数组从0开始计数)。你初始的s2是(r-l)/2 +1,这是aux右半部分的起始索引,所以判断s2是否越界应该是s2 > (r-l),而不是s2>r。
当你用错误的条件时,这个判断几乎永远不会触发,程序会不断从aux的越界位置读取数据。而aux是栈上的变长数组(VLA),越界访问会直接踩到栈里的其他垃圾值——那些16就是这么来的。
为什么加输出就正常?
这纯属巧合!当你在merge里加cout输出时,栈的内存布局被改变了,越界访问到的位置刚好是合法的数据,或者输出操作触发了栈的清理/对齐,暂时掩盖了问题,但bug本身并没有被修复。
修复后的代码
我把错误的判断条件修正了,还做了一些代码可读性优化:
#include <bits/stdc++.h> using namespace std; int merge(int *ar, int l, int r) { int len = r - l + 1; // 用vector代替VLA,符合C++标准,更安全 vector<int> aux(len); int s1 = 0, s2 = len / 2; for (int i = 0; i < len; i++) aux[i] = ar[l + i]; for (int k = 0; k < len; k++) { // 左半部分已取完:s1到达左半部分的最后一个索引 if (s1 >= len/2) ar[l + k] = aux[s2++]; // 右半部分已取完:s2超出aux的有效范围 else if (s2 >= len) ar[l + k] = aux[s1++]; else if (aux[s1] <= aux[s2]) ar[l + k] = aux[s1++]; else ar[l + k] = aux[s2++]; } return 0; } void mergesort(int *ar, int l, int r) { if (l >= r) return; int mid = (l + r) / 2; mergesort(ar, l, mid); mergesort(ar, mid + 1, r); merge(ar, l, r); } int main() { int ar[] ={ 34, 54, 56, 42, 32, 46, 99, 85, 5, 45, 34, 54, 6, 56, 54, 64, 5 }; int l = 0, r = sizeof(ar) / sizeof(int) - 1; mergesort(ar, l, r); for (int i = 0; i < r + 1; i++) cout << ar[i] << " "; return 0; }
额外优化说明
- 把
r-l+1提取成变量len,避免重复计算,代码更清晰。 - 用
vector<int>代替栈上的变长数组(VLA):C++标准并不支持VLA,这是GCC的扩展特性,用vector更符合标准,还能避免大数组导致的栈溢出问题。 - 调整了左右半部分的结束判断逻辑,直接基于
len计算,更直观不易出错。
运行修复后的代码,就能得到正确的排序结果啦!
内容的提问来源于stack exchange,提问作者Poseidon Broger
相关产品推荐
相关产品推荐

