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

递归构建文件管理器路径字符串时程序崩溃,求C代码排查修复

问题分析与修复

你的代码存在几个致命问题,直接导致程序卡死或崩溃:

  1. 无限递归:递归调用getPath(root, actual)时没有传入父节点actual->pPA,函数会反复调用自身,永远无法终止,最终导致栈溢出或程序无响应。
  2. 返回局部栈内存:resp是函数内的局部数组,函数执行完毕后栈空间会被回收,返回的指针指向无效内存,后续使用会引发未定义行为(崩溃或乱码)。
  3. 未初始化字符串就使用strcat:resp初始值是随机垃圾数据,strcat依赖目标字符串的'\0'结尾来确定追加位置,这里直接调用会读取非法内存,导致程序异常。
  4. 拼接逻辑颠倒:你需要先获取父节点的路径,再追加当前节点名称,原代码的拼接顺序完全错误。

修复方案(动态内存版)

使用malloc动态分配内存,避免返回局部变量,同时修正递归逻辑和拼接顺序:

#include <stdlib.h>
#include <string.h>

char *getPath(lnodo *root, lnodo *actual) {
    // 递归终止:到达根节点
    if (actual->pPA == NULL) {
        // 为根节点路径分配内存,长度为名称长度+2(加"/"和结束符)
        char *resp = malloc(strlen(actual->Nom) + 2);
        if (resp == NULL) return NULL; // 内存分配失败处理
        strcpy(resp, actual->Nom);
        strcat(resp, "/");
        return resp;
    }

    // 先递归获取父节点的路径
    char *parent_path = getPath(root, actual->pPA);
    if (parent_path == NULL) return NULL;

    // 计算当前路径总长度:父路径长度 + 当前节点名称长度 + 2(加"/"和结束符)
    size_t total_len = strlen(parent_path) + strlen(actual->Nom) + 2;
    char *resp = realloc(parent_path, total_len);
    if (resp == NULL) {
        free(parent_path); // 内存分配失败,释放父节点路径内存
        return NULL;
    }

    // 追加当前节点名称和分隔符
    strcat(resp, actual->Nom);
    strcat(resp, "/");
    return resp;
}

void path(lnodo *root, lnodo *actual) {
    char *current_path = getPath(root, actual);
    if (current_path != NULL) {
        printf("%s\n", current_path);
        free(current_path); // 记得释放动态分配的内存,避免泄漏
    }
}

替代方案(调用者提供缓冲区)

如果不想用动态内存,可以让调用者传入缓冲区和最大长度,更安全且避免内存泄漏:

#include <string.h>

// 返回值:成功返回缓冲区指针,失败返回NULL(比如缓冲区不足)
char *getPath(lnodo *root, lnodo *actual, char *buf, size_t buf_size) {
    // 递归终止:到达根节点
    if (actual->pPA == NULL) {
        if (strlen(actual->Nom) + 2 > buf_size) return NULL;
        strcpy(buf, actual->Nom);
        strcat(buf, "/");
        return buf;
    }

    // 先递归填充父节点路径
    if (!getPath(root, actual->pPA, buf, buf_size)) {
        return NULL;
    }

    // 检查剩余空间是否足够容纳当前节点名称和分隔符
    size_t current_len = strlen(buf);
    if (current_len + strlen(actual->Nom) + 2 > buf_size) {
        return NULL;
    }

    // 追加当前节点信息
    strcat(buf, actual->Nom);
    strcat(buf, "/");
    return buf;
}

void path(lnodo *root, lnodo *actual) {
    char buf[400];
    if (getPath(root, actual, buf, sizeof(buf))) {
        printf("%s\n", buf);
    } else {
        printf("路径过长,缓冲区不足\n");
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 05:01:11