为何返回字符串时频繁触发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
相关产品推荐
相关产品推荐

