LeetCode最长回文子串代码触发AddressSanitizer堆缓冲区溢出求助
排查LeetCode最长回文子串代码的heap-buffer-overflow错误
错误原因分析
从报错信息和代码逻辑来看,触发heap-buffer-overflow的核心问题有三个:
- 未预留字符串终止符空间:C语言中字符串必须以
'\0'结尾,你通过malloc(sizeof(char)*(max))分配的内存仅能存储max个字符,没有给终止符留额外字节。调用者读取返回的字符串时,会越界访问到内存分配区域之外的地址,直接触发溢出错误。 - 回文长度计算逻辑错误:你的
t变量统计的是双向匹配的步数,并非回文的实际长度。比如对于回文"aba",t会被计算为2,但实际长度是3,这导致max值偏小,后续复制字符时会遗漏部分内容,同时加剧了内存越界风险。 - 边界场景未处理:当输入字符串为空或所有字符互不重复时,
max会保持0,此时malloc(0)属于未定义行为,同样会引发错误。
解决思路与代码修正
核心修正点
- 内存分配时多预留1字节,用于存储字符串终止符
'\0'。 - 调整回文长度的计算逻辑,确保
max_len是回文的真实长度。 - 处理空字符串、单字符等边界场景。
- 复制完字符后必须手动添加
'\0'。
基于中心扩展法的优化代码
中心扩展法是解决最长回文子串问题的高效方案,逻辑更清晰,也能避免原代码中的匹配逻辑漏洞:
char * longestPalindrome(char * s){ int le = strlen(s); if (le == 0) { char *ans = malloc(1); ans[0] = '\0'; return ans; } int start = 0, end = 0; // 遍历每个可能的中心,分别处理奇数/偶数长度回文 for (int i = 0; i < le; i++) { int len_odd = expandAroundCenter(s, i, i); int len_even = expandAroundCenter(s, i, i + 1); int max_current = len_odd > len_even ? len_odd : len_even; // 更新最长回文的边界 if (max_current > end - start) { start = i - (max_current - 1) / 2; end = i + max_current / 2; } } int max_len = end - start + 1; char *ans = malloc(sizeof(char) * (max_len + 1)); // +1 预留终止符空间 for (int i = 0; i < max_len; i++) { ans[i] = s[start + i]; } ans[max_len] = '\0'; // 添加字符串终止符 return ans; } // 辅助函数:从中心向两侧扩展,计算回文长度 int expandAroundCenter(char *s, int left, int right) { int le = strlen(s); while (left >= 0 && right < le && s[left] == s[right]) { left--; right++; } return right - left - 1; }
原代码的最小修改版本
如果想保留原代码的双层循环逻辑,只需修正长度计算和内存分配:
char * longestPalindrome(char * s){ int le = strlen(s); if (le == 0) { char *ans = malloc(1); ans[0] = '\0'; return ans; } int start = 0, end = 0; int max_len = 1; // 至少存在单字符回文 for (int i = 0; i < le; i++){ for (int j = le-1; j > i; j--){ int temp_i = i; int temp_j = j; // 检查当前i到j的子串是否为回文 while (temp_i <= temp_j && s[temp_i] == s[temp_j]){ temp_i++; temp_j--; } // 确认是回文后,更新最长回文信息 if (temp_i > temp_j) { int current_len = j - i + 1; if (current_len > max_len) { max_len = current_len; start = i; end = j; } break; // 找到以i为起点的最长回文,无需继续遍历更短的j } } } char *ans = malloc(sizeof(char)*(max_len + 1)); for(int i = 0; i < max_len; i++){ ans[i] = s[start+i]; } ans[max_len] = '\0'; return ans; }
内容的提问来源于stack exchange,提问作者Wen Sun
相关产品推荐
相关产品推荐

