You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 16:16:13