为什么基于指针实现的递归fold函数首次运行正确,重跑后输出异常大值?
问题根因
你的代码存在两处逻辑错误,最终触发了未定义行为,直接表现就是首次运行碰巧结果正确,重跑就出现无意义的异常大数。
具体错误拆解
递归逻辑顺序颠倒,触发数组越界访问
你当前的代码把数组元素计算的语句放在了终止判断语句的前面:只要进入函数,不管传入的size是多少,第一行就会执行double result = func(func(init, *tab), *tab); 直接解引用指针读数组元素。
顺着递归流程推演:
- 最初调用时size=5,tab指向数组首地址,这时候解引用是合法的
- 每次递归调用时tab向后移动1位、size减1
- 当size最终降到0时,tab已经连续向后移动了5次,指向数组末尾之外的无归属内存
- 这时候进入size=0的函数分支,代码依然会强行读取这块越界内存的值参与计算,属于典型的非法内存访问
第一次运行时,栈上这块越界位置刚好残留着你原本要处理的最后一个元素5.0,碰巧算出来的结果符合预期;重跑程序时栈内存的残留值发生变化,读到的可能是任意随机大数值,最终输出就成了异常值。
终止条件形同虚设
你原本写的if (size > 0)递归分支,完全没有拦住size=0场景下的非法解引用——因为解引用的代码在if判断的外面,哪怕size是0,也会先执行解引用再判断,根本起不到“无元素时直接返回累计值”的作用。
修正后的实现
把终止判断移到最前面,先处理边界场景再做计算,保留你“每个元素连续应用两次func”的业务逻辑:
double fold(double* tab, int size, double init, double func(double, double)){ // 终止条件:没有剩余元素需要处理,直接返回累计值,不触碰指针 if (size <= 0) { return init; } // 按需求对当前元素连续应用两次func,生成新的累计值 double current_result = func(func(init, *tab), *tab); // 递归处理剩余元素:指针后移、数组长度减1、把当前结果作为下一层的初始值 return fold(tab + 1, size - 1, current_result, func); }
修正后的稳定性说明
调整后的代码全程不会触碰数组边界之外的内存,所有计算都在合法地址范围内完成,不管程序重跑多少次、栈内存布局如何变化,结果都是稳定的。拿你的测试用例验证,最终会稳定输出40.0,和预期完全一致。
内容的提问来源于stack exchange,提问作者Tobilowe
相关产品推荐
相关产品推荐

