CodeWars找唯一数递归函数出现意外无效内存访问问题
问题:找出数组中唯一不同的元素(C语言递归实现错误排查)
我正在学习C语言,尝试解决CodeWars上的题目:给定数组,除一个元素外其余均相同,找出该唯一元素。我编写了带wrapper函数的递归实现以处理const指针遍历数组,通用测试通过,但随机测试触发SIGSEGV(11)无效内存访问错误,同时存在返回值警告。现咨询:
- 递归函数中无效内存访问的原因是什么?
- 如何提升该方案的健壮性,是否应转为迭代实现?
题目示例
finduniq((const float[]){1, 1, 1, 2, 1, 1}, 5); /* --> 2 */ finduniq((const float[]){0, 0, 0.55, 0, 0}, 5); /* --> 0.55 */
实现代码
#include <stddef.h> float wrapper_finduniq(float *nums, size_t n) { // Middle one is unique if ((*(nums - 1) != *nums) && (*nums != *(nums + 1))) return *nums; // Left one is unique if ((*(nums - 1) != *nums) && !(*nums != *(nums + 1))) return *(nums - 1); // Right one is unique if ((!(*nums - 1 != *nums) && (*nums != *(nums + 1)))) return *(nums + 1); if (n > 2) return wrapper_finduniq(nums + 1, n - 1); } float finduniq(const float *nums, size_t n) { return wrapper_finduniq((float *)(nums + 1), n - 1); }
错误信息
Test Results:
Generic_Test
Completed in 0.5986msRandom_Test
should_return_the_uncheated_unique_number
Test Crashed
Caught unexpected signal: SIGSEGV (11). Invalid memory access.
Completed in 0.0000msSTDERR
solution.c:14:1: warning: control may reach end of non-void function [-Wreturn-type]
}
^
1 warning generated.
解答
1. 无效内存访问的原因
- 指针越界访问:递归过程中,当
n递减到1时,nums已经指向数组边界附近,此时访问*(nums-1)或*(nums+1)会直接触碰数组外的无效内存,触发SIGSEGV。比如当递归到数组最后一个元素时,nums+1完全在数组内存范围之外。 - 逻辑表达式语法错误:第三个if条件中的
!(*nums - 1 != *nums)是错误写法,正确应该是!(*(nums - 1) != *nums)——少了括号导致表达式逻辑混乱,可能让函数错误进入递归分支,提前触发越界。 - 无明确返回值的边界情况:当
n <= 2时,函数没有定义返回值,会触发返回值警告,同时程序执行到函数末尾时会产生未定义行为,这也可能间接引发内存访问错误。
2. 提升健壮性的方案,是否转迭代
递归方案的修复(可选)
如果坚持用递归,需要做以下调整:
- 增加指针边界检查:在访问
nums-1、nums+1前,确保当前指针处于数组的有效范围内,避免越界。 - 修正逻辑表达式的语法错误:把第三个条件的括号补全,保证判断逻辑正确。
- 处理所有终止分支:比如当
n == 2时,直接比较两个元素返回不同的那个,确保函数任何路径都有返回值。
更推荐迭代实现
递归本身存在栈溢出风险(数组极大时),且指针越界问题更难排查。迭代实现更健壮、逻辑更直观:
- 直接处理const指针,无需额外wrapper函数和类型转换。
- 先检查数组头部和尾部的边界情况,再遍历中间元素,避免越界。
- 无栈溢出风险,性能更稳定。
示例迭代实现:
#include <stddef.h> float finduniq(const float *nums, size_t n) { // 处理数组长度为1的特殊情况 if (n == 1) return nums[0]; // 检查第一个元素是否唯一 if (nums[0] != nums[1]) return nums[0]; // 检查最后一个元素是否唯一 if (nums[n-1] != nums[n-2]) return nums[n-1]; // 遍历中间元素找唯一值 for (size_t i = 1; i < n-1; i++) { if (nums[i] != nums[i-1] && nums[i] != nums[i+1]) { return nums[i]; } } // 题目保证存在唯一元素,此处不会执行到 return 0.0f; }
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

