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

结构体指针赋值后仍为NULL的技术问题求助

问题分析与解决方案

核心原因:C语言的参数值传递

你遇到的问题本质是C语言中函数参数的传递是值传递——当你把partitioned(一个Tuple*类型的指针)传给get_name_field时,函数内部会创建一个这个指针的副本。你在函数里对这个副本做的赋值(partitioned = split_prefix(...))只会修改副本的值,完全不会影响外部的partitioned变量。这就是为什么调试时split_prefix返回了有效的指针,但外部的partitioned依然是NULL。

解决方案:传递二级指针(最直接的修复方式)

要让函数能修改外部的指针变量,你需要传递指针的指针(也就是Tuple**),这样函数内部可以通过解引用操作修改外部指针的指向。

修改get_name_field函数

// 获取名称字段,成功返回TRUE,失败返回FALSE
int get_name_field(Tuple **partitioned, char name_field[], char *fname, char *cwd, int cwd_len) {
    // fname无法拆分
    if (strlen(fname) > 155) {
        perror(fname);
        return FALSE;
    }
    // 存在路径(前缀)
    else if (cwd) {
        // fname字段长度不足
        if (strlen(cwd) + 1 + strlen(fname) > 100) {
            // ***********修改赋值位置**************
            if ((*partitioned = split_prefix(cwd, strlen(cwd))) == NULL) {
                perror("partition failed");
                return FALSE;
            }
            memcpy(name_field, (*partitioned)->part1, strlen((*partitioned)->part1));
        }
        // ... 剩余代码保持不变
    }
    // ... 剩余代码保持不变
}

修改测试函数的调用

void test_get_name_field3(void) {
    Tuple *partitioned = NULL;
    char name_field[NAME_LEN] = {'\0'};
    char *fname = "hellobutunfortunatelythiswon'tfit.txt";
    char *cwd = "user/bin/arafian/ratherlongdirectorynameandwillnot/fitin"
                "thenamefieldonlysoitwilloverflowtotheprefixfield";
    int cwd_len = strlen(cwd);
    // 传递指针的地址
    get_name_field(&partitioned, name_field, fname, cwd, cwd_len);
    char *result = "user/bin/arafian/ratherlongdirectorynameandwillnot/";
    checkit_string(name_field, result);
    // 现在partitioned指向了分配的内存,可以正确free
    if (partitioned != NULL) {
        free(partitioned);
    }
}

另一种方案:让函数返回指针

如果你觉得二级指针不够直观,也可以调整get_name_field的设计,让它直接返回Tuple*指针,同时用返回值的特殊状态来表示操作是否成功:

// 返回拆分后的Tuple指针,失败返回NULL;name_field会被填充成功的前缀
Tuple* get_name_field(char name_field[], char *fname, char *cwd, int cwd_len) {
    // fname无法拆分
    if (strlen(fname) > 155) {
        perror(fname);
        return NULL;
    }
    // 存在路径(前缀)
    else if (cwd) {
        // fname字段长度不足
        if (strlen(cwd) + 1 + strlen(fname) > 100) {
            Tuple *partitioned = split_prefix(cwd, strlen(cwd));
            if (partitioned == NULL) {
                perror("partition failed");
                return NULL;
            }
            memcpy(name_field, partitioned->part1, strlen(partitioned->part1));
            return partitioned;
        }
        // ... 剩余逻辑:处理不需要拆分的情况,返回NULL或者相应的值
    }
    return NULL;
}

对应的测试函数调用修改为:

void test_get_name_field3(void) {
    char name_field[NAME_LEN] = {'\0'};
    char *fname = "hellobutunfortunatelythiswon'tfit.txt";
    char *cwd = "user/bin/arafian/ratherlongdirectorynameandwillnot/fitin"
                "thenamefieldonlysoitwilloverflowtotheprefixfield";
    int cwd_len = strlen(cwd);
    Tuple *partitioned = get_name_field(name_field, fname, cwd, cwd_len);
    char *result = "user/bin/arafian/ratherlongdirectorynameandwillnot/";
    checkit_string(name_field, result);
    if (partitioned != NULL) {
        free(partitioned);
    }
}

额外注意事项

  • 内存泄漏:原来的代码中,split_prefix分配的内存会因为外部指针没拿到而泄漏,修复后要确保在使用完partitioned后调用free。
  • 边界检查:确保memcpy操作不会越界,比如在split_prefix中,要保证i+1不超过NAME_LEN,cwd_len - i -1不超过PREFIX_LEN,避免缓冲区溢出。

内容的提问来源于stack exchange,提问作者dumbitdownjr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 03:28:24