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

为何返回字符串时频繁触发AddressSanitizer堆缓冲区溢出错误?

问题分析与修复方案

报错根源

你遇到的堆缓冲区溢出,核心原因是栈为空时仍非法访问栈顶元素:当str->top == -1(栈空状态),代码执行s[i] == str->items[str->top],也就是访问str->items[-1],这属于越界读取堆内存,直接触发AddressSanitizer的报错。

为什么报错大多在返回字符串时出现?这类非法内存读取不一定会立刻触发错误,可能在后续执行str->items[str->top + 1] = '\0'时,或者返回字符串后进行操作时才被检测到,本质是之前的非法访问留下的隐患被集中暴露。

另外,原代码处理连续重复字符的逻辑存在错误:比如输入"aaaa",原逻辑无法正确删除所有重复项,还会导致循环索引处理混乱。

修复步骤

1. 修复栈空时的越界访问

在比较当前字符和栈顶元素前,先判断栈是否为空,仅当栈非空时才进行比较:

// 替换原代码中的if判断
if (str->top != -1 && s[i] == str->items[str->top]) {
    pop(str);
}

2. 修正连续重复字符的处理逻辑

原代码试图跳过连续相同字符的逻辑错误,正确思路是:遍历每个字符,若当前字符和栈顶相同则弹出栈顶,否则压入栈。连续多个相同字符会被自动处理(比如"aaaa":第一个a压入,第二个a匹配栈顶弹出,第三个a压入,第四个a匹配弹出,最终栈空)。

修改后的完整removeDuplicates函数:

char * removeDuplicates(char * s){
    st *str;
    int l = strlen(s);
    str = malloc(sizeof(st));
    // 分配内存时多留1字节存'\0',避免后续加终止符时越界
    str->items = malloc((l + 1) * sizeof(char));
    int i;
    str->top = -1;
    for(i = 0; i < l; ++i){
        // 栈非空且当前字符等于栈顶,弹出栈顶
        if(str->top != -1 && s[i] == str->items[str->top]){
            pop(str);
        } else {
            // 否则压入当前字符
            push(str, s[i]);
        }
    }
    // 给结果字符串加终止符,此时str->top+1不会超过分配的内存
    str->items[str->top + 1] = '\0';
    // 释放栈结构体,避免内存泄漏
    char *result = str->items;
    free(str);
    return result;
}

3. 简化实现(可选)

可以直接用数组模拟栈,省去结构体的内存分配,代码更简洁:

char * removeDuplicates(char * s){
    int l = strlen(s);
    char *stack = malloc((l + 1) * sizeof(char));
    int top = -1;
    for(int i = 0; i < l; ++i){
        if(top != -1 && s[i] == stack[top]){
            top--;
        } else {
            stack[++top] = s[i];
        }
    }
    stack[top + 1] = '\0';
    return stack;
}

内容的提问来源于stack exchange,提问作者Steve Mathew

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:25:28