C语言实现split函数时使用strcat、memset引发程序崩溃的原因
split函数调用memset、strcat崩溃的错误排查
你的代码存在5个核心问题,直接导致内存访问违规崩溃:
- 只分配了指针数组内存,未给子串分配实际存储内存
你用calloc(size+1, sizeof(char*))只给二级指针分配了size+1个char*类型指针的存储空间,calloc会把这段内存初始化为0,也就是说split[word]全是空指针。你后续直接对空指针执行memset、strcat操作,会直接触发段错误,这是崩溃的首要原因。 - strcat用法完全不符合预期
strcat的第二个参数必须是'\0'结尾的完整字符串,你传入&str[i]会把原字符串从i位置到末尾的所有字符全部拼接到目标地址,根本不是“逐字符添加”的效果,哪怕内存分配正确,也会造成写入越界、结果完全错误。 - memset逻辑无效
你每次新单词开头只给目标地址写1个字节的'\0',但没有给子串预留足够的存储空间,也没有维护写入位置,后续写入必然越界。 - 循环效率极低、逻辑缺失
循环条件中每次迭代都调用strlen(str)遍历整个原字符串算长度,时间复杂度从O(n)劣化到O(n²);且循环只遍历到字符串最后一个有效字符就停止,没有处理末尾无分隔符的最后一个子串的收尾逻辑。 - 返回结果无结束标识
你返回的指针数组末尾没有放置NULL哨兵值,调用方无法判断数组边界,后续遍历很容易读越界。
修正参考代码
// 假设你已经实现了num_items,功能是返回分割后的子串数量 char** split(const char* str, char delimiter) { int str_len = strlen(str); unsigned int size = num_items(str, delimiter); // 多分配1个位置存NULL哨兵 char** split_res = calloc(size + 1, sizeof(char*)); int word_idx = 0; int cur_word_len = 0; // 给第一个子串分配初始内存,用于存结束符 split_res[word_idx] = malloc(1); split_res[word_idx][0] = '\0'; for(int i = 0; i <= str_len; i++) // 遍历到'\0'时收尾最后一个子串 { if(str[i] == delimiter || str[i] == '\0') { // 给当前子串补结束符 split_res[word_idx][cur_word_len] = '\0'; if(str[i] == '\0') break; // 初始化下一个子串的存储空间 word_idx++; cur_word_len = 0; split_res[word_idx] = malloc(1); split_res[word_idx][0] = '\0'; } else { // 逐字符追加,扩容2字节:存当前字符+结束符 cur_word_len++; split_res[word_idx] = realloc(split_res[word_idx], cur_word_len + 1); split_res[word_idx][cur_word_len - 1] = str[i]; split_res[word_idx][cur_word_len] = '\0'; } } // 数组末尾放NULL作为遍历结束标识 split_res[size] = NULL; return split_res; }
注意:实际生产使用时所有malloc/calloc/realloc的返回值都要做判空处理,避免内存分配失败触发崩溃;使用完分割后的数组要记得逐个子串free,最后free外层的指针数组,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Saar Weinberg
相关产品推荐
相关产品推荐

