调用C语言自定义解析函数触发段错误,求排查原因
字符串分割函数段错误的原因及修复方案
我一直在调试一个自定义的字符串分割函数,用于解析命令行参数,但它总是触发段错误。用valgrind检测发现错误出在strtok调用时,但我已经把输入的字符串字面量复制到了本地堆内存中,还是没能解决问题。这个函数接收字符串和分隔符字符串(非单个字符),我实在搞不懂内存相关的问题出在哪里。
原代码如下:
char **splitstring(char *str, const char *delim) { int i, wn; char **array; char *token; char *copy; copy = malloc(strlen(str) + 1); if (copy == NULL) { perror("hsh"); return (NULL); } i = 0; while (str[i]) { copy[i] = str[i]; i++; } copy[i] = '\0'; token = strtok(copy, delim); array = malloc((sizeof(char *) * 2)); array[0] = strdup(token); i = 1; wn = 3; while (token) { token = strtok(NULL, delim); array = realloc(array, (sizeof(char *) * (wn - 1)), (sizeof(char *) * wn)); array[i] = strdup(token); i++; wn++; } free(copy); return (array); }
错误原因分析
strdup(NULL)触发段错误:循环条件是while(token),但每次循环先调用token = strtok(NULL, delim),当strtok遍历完所有token后会返回NULL,此时仍然执行strdup(token),而strdup无法处理NULL指针,直接导致非法内存访问。realloc参数错误:realloc只需要两个参数(原指针、新内存大小),你传入了三个参数,这属于未定义行为,会导致内存分配异常。- 边界情况未处理:如果输入字符串为空、全是分隔符,或者第一个
strtok就返回NULL,此时array[0] = strdup(token)同样会因为token是NULL而触发段错误。 - 内存分配逻辑混乱:初始分配和循环中的
wn变量逻辑不合理,没有预留数组末尾的NULL指针位置,不符合C风格字符串数组的规范。
修复后的代码
char **splitstring(char *str, const char *delim) { int i, wn; char **array; char *token; char *copy; // 处理空输入或空字符串的情况 if (str == NULL || strlen(str) == 0) { array = malloc(sizeof(char *)); if (array != NULL) array[0] = NULL; return array; } // 复制原字符串到堆内存 copy = malloc(strlen(str) + 1); if (copy == NULL) { perror("hsh"); return NULL; } strcpy(copy, str); // 获取第一个token token = strtok(copy, delim); if (token == NULL) { free(copy); // 返回仅含NULL的数组 array = malloc(sizeof(char *)); if (array != NULL) array[0] = NULL; return array; } // 初始化数组,预留末尾NULL的位置 wn = 2; array = malloc(sizeof(char *) * wn); if (array == NULL) { perror("hsh"); free(copy); return NULL; } array[0] = strdup(token); i = 1; // 遍历剩余token while (1) { token = strtok(NULL, delim); if (token == NULL) break; // 重新分配内存,增加一个指针位置(含末尾NULL) wn++; char **temp = realloc(array, sizeof(char *) * wn); if (temp == NULL) { perror("hsh"); // 内存分配失败,释放已分配的所有资源 for (int j = 0; j < i; j++) free(array[j]); free(array); free(copy); return NULL; } array = temp; array[i] = strdup(token); i++; } // 添加数组结束标记NULL array[i] = NULL; free(copy); return array; }
关键修复点
- 新增空输入、无有效token的边界处理,避免操作NULL指针
- 修正
realloc参数错误,仅传递原指针和新内存大小 - 调整循环逻辑,当
strtok返回NULL时立即退出,不再执行strdup(NULL) - 使用
strcpy替代手动循环复制字符串,代码更简洁可靠 - 内存分配失败时添加资源清理逻辑,防止内存泄漏
- 在返回的数组末尾添加NULL指针,符合C语言字符串数组的惯例(方便后续遍历)
内容的提问来源于stack exchange,提问作者BSO_1
相关产品推荐
相关产品推荐

