C语言实现LeetCode目标解析器时单行代码触发堆缓冲区溢出
C语言实现字符串解析触发堆缓冲区溢出问题排查
核心错误点
你的代码存在4个会触发未定义行为/内存越界的问题,本地运行正常只是内存环境巧合,在线判题沙箱开启了严格的内存越界检测就会直接崩溃:
sizeof无法计算传入函数的字符串长度command是函数形参,类型为字符指针,sizeof(command)得到的是指针本身的占用空间(64位系统固定为8字节,32位系统固定为4字节),和传入字符串的实际长度完全无关。当测试用例长度超过这个值时,循环要么提前终止,要么越界读取非法内存。正确获取C字符串长度的方式是调用strlen(command),需要引入头文件<string.h>。- 循环步进逻辑缺失,未跳过已匹配的子串
当前循环每次固定让i自增1,匹配到组合子串后没有跳过后续已识别的字符:匹配()时,i在(位置处理完后,下一轮会落到)字符上,这个字符既不是G也不是(,会导致逻辑混乱;匹配(al)时同理,后续的a/l/)都会被当成新的判断起点,写入ret数组时很容易越界。 - 内存重分配时未预留字符串结束符空间
最后调用realloc时传入的大小是counter * sizeof(char),但C语言字符串需要额外1字节存储末尾的\0结束符,分配空间不足会直接触发堆溢出。 (al)分支注释状态下属于典型未定义行为
注释掉ret[counter] = 'a'时,分支仅给ret[counter+1]赋值了'l',ret[counter]位置是malloc申请到的内存里的随机垃圾值,本地运行能出正确结果只是内存残留值刚好符合预期,不代表代码逻辑正确。
修正后可运行代码
#include <stdlib.h> #include <string.h> char * interpret(char * command){ // 输入最长100字符,输出最长不超过100,多留1字节存结束符 char * ret = malloc(sizeof(char) * 101); int counter = 0; int cmd_len = strlen(command); for(int i = 0; i < cmd_len; i++) { if(command[i] == 'G') { ret[counter++] = 'G'; } else if(command[i] == '(') { if (command[i + 1] == ')') { ret[counter++] = 'o'; i++; // 跳过已匹配的右括号 } else { ret[counter++] = 'a'; ret[counter++] = 'l'; i += 3; // 跳过'al)'三个已匹配字符 } } ret[counter] = '\0'; } // 分配空间包含结束符位置 return realloc(ret, (counter + 1) * sizeof(char)); }
内容的提问来源于stack exchange,提问作者vito
相关产品推荐
相关产品推荐

