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

CodeWars找唯一数递归函数出现意外无效内存访问问题

问题:找出数组中唯一不同的元素(C语言递归实现错误排查)

我正在学习C语言,尝试解决CodeWars上的题目:给定数组,除一个元素外其余均相同,找出该唯一元素。我编写了带wrapper函数的递归实现以处理const指针遍历数组,通用测试通过,但随机测试触发SIGSEGV(11)无效内存访问错误,同时存在返回值警告。现咨询:

  1. 递归函数中无效内存访问的原因是什么?
  2. 如何提升该方案的健壮性,是否应转为迭代实现?

题目示例

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.5986ms

Random_Test
should_return_the_uncheated_unique_number
Test Crashed
Caught unexpected signal: SIGSEGV (11). Invalid memory access.
Completed in 0.0000ms

STDERR
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 14:07:17