C语言实现字符串分割函数时char**缓冲区仅首元素可写入问题
C语言split函数仅返回第一个分割结果的问题修复
问题现象
实现按指定分隔符拆分字符串为字符串数组的函数时,char**类型的结果数组仅第一个索引可正常写入内容。例如将字符串"Hello;;world;;!"按分隔符";;"分割时,预期返回[ "Hello", "world", "!" ],实际仅得到[ "Hello" ]。
原始问题代码
split函数实现
#include <stdlib.h> #include <string.h> #include <stdbool.h> #include "strings.h" int split(char **dest, const char *src, const char *splitStr) { char buffer[16384]; int counter = 0; int len = strlen(splitStr); int flag = 0; int start = 0; for (int i = 0; i < strlen(src); i++) { flag = 0; if (src[i] == splitStr[0]) { for (int j = 1; j < len; j++) { //check if all elements in delimiter are in string if (src[i + j] == splitStr[j] && j != (len - 1)) { continue; } else if(src[i + j] == splitStr[j] && j == (len - 1)) { buffer[i] = '\0'; dest[counter] = malloc(sizeof(char) * (i - start + 1)); strncpy(dest[counter], buffer + start, (i - start)); start = i + (len-1) flag = 1; i += (len - 1); counter++; } //if not break else { break; } } } if (i == (strlen(src) - 1)) { buffer[i] = src[i]; buffer[i + 1] = '\0'; counter++; break; } if (flag == 0) { buffer[i] = src[i]; } } return counter; }
调用代码
auto src = "Hello;;world;;!"; auto buffer = (char **)malloc(32); int count = split(buffer, src, ";;");
错误点汇总
- 语法错误:匹配分隔符后的
start = i + (len-1)语句末尾缺少分号,无法正常编译。 - 结果缓冲区分配错误:
malloc(32)仅分配了32字节连续内存,虽然64位系统下勉强能存4个char*指针,但没有按指针类型计算分配大小,一旦分割结果超过4个就会出现内存越界。 - 缓冲区写入下标逻辑错误:复用原字符串下标
i作为临时buffer的写入下标,匹配到第一个分隔符后i会跳过分隔符位置,后续写入buffer时会出现下标断层,buffer+start指向的内存空间没有有效内容,拷贝自然失败。 - 字符串拷贝缺失终止符:使用
strncpy拷贝固定长度内容时不会自动追加字符串结束符'\0',会导致字符串内存越界。 - 最后一段内容未写入结果数组:循环走到原字符串末尾时,仅操作了临时buffer、累加了计数器,没有给最后一个分割结果分配内存、也没有执行拷贝操作,最后一段内容直接丢失。
- 分隔符匹配逻辑缺陷:内层匹配循环从
j=1开始,当分隔符长度为1时循环永远不会执行,无法匹配单字符分隔符;匹配成功后下一段起始位置计算为i + len -1,会把分隔符的最后一个字符算入下一段内容。 - 循环效率问题:每次循环都调用
strlen(src)计算字符串长度,时间复杂度从O(n)升到O(n²)。
修正后实现
修正后的split函数
#include <stdlib.h> #include <string.h> #include <stdio.h> int split(char **dest, const char *src, const char *splitStr) { int src_len = strlen(src); int split_len = strlen(splitStr); int counter = 0; int buf_pos = 0; // 单独维护临时缓冲区的写入下标,不复用原串下标 char buffer[16384]; // 处理分隔符为空的边界情况 if (split_len == 0) { dest[0] = malloc(src_len + 1); strcpy(dest[0], src); return 1; } for (int i = 0; i < src_len; i++) { bool is_match = true; // 从当前位置检查是否完整匹配分隔符 for (int j = 0; j < split_len; j++) { if (i + j >= src_len || src[i + j] != splitStr[j]) { is_match = false; break; } } if (is_match) { // 匹配到分隔符,将当前缓冲区内容存入结果数组 buffer[buf_pos] = '\0'; dest[counter] = malloc(buf_pos + 1); strcpy(dest[counter], buffer); counter++; buf_pos = 0; // 重置缓冲区写入位置 i += split_len - 1; // 跳过分隔符所占长度 } else { // 未匹配到分隔符,将当前字符写入临时缓冲区 buffer[buf_pos++] = src[i]; } } // 写入最后一段剩余内容 buffer[buf_pos] = '\0'; dest[counter] = malloc(buf_pos + 1); strcpy(dest[counter], buffer); counter++; return counter; }
正确调用示例
int main() { const char *src = "Hello;;world;;!"; // 按指针大小分配结果数组空间,这里预留10个char*位置足够常规场景使用 char **buffer = malloc(sizeof(char*) * 10); int count = split(buffer, src, ";;"); // 打印结果、释放内存 for (int i = 0; i < count; i++) { printf("%s\n", buffer[i]); free(buffer[i]); } free(buffer); return 0; }
运行代码将输出预期结果:
Hello world !
内容的提问来源于stack exchange,提问作者T.Naz
相关产品推荐
相关产品推荐

