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

指针运算致嵌套链表数据丢失,求C++代码问题排查

修复嵌套链表指针操作错误,正确保存子链表数据

我来帮你揪出这段链表代码里的指针问题,你的核心错误集中在子链表的指针维护逻辑和多API节点的处理上,咱们一步步拆解修复:

一、当前代码里的关键错误

1. 完全错误的指针移动方式

你用listGrip->head ++;来试图移动子链表的头指针,但这完全违背了链表的操作逻辑:

  • listGrip->head是指向_ListSub节点的指针,++操作会让它直接跳到内存中下一个_ListSub大小的地址,而不是沿着节点的next指针移动。这会导致原来的节点彻底丢失(内存泄漏),而且新创建的节点和之前的节点没有任何关联。
  • 你根本没设置next指针来把新节点链入子链表——这才是链表节点之间建立连接的核心。

2. 子链表初始化与循环的逻辑漏洞

你一开始就创建了一个空的_ListSub节点作为head,然后每次循环把数据写入当前head,接着创建新节点覆盖head。循环结束后,listGrip->head指向的是一个没有数据的空节点,这就是主函数里看不到子链表数据的直接原因。

3. 未实现多ID的API链表创建逻辑

你的设计目标是每个唯一ID对应一个ListAPI节点,但当前代码每次循环都覆盖listGrip->id,完全没有检查ID是否已存在,也没有创建新的ListAPI节点,彻底偏离了最初的设计。

二、修正后的完整代码实现

我们先完善辅助函数,再修复核心的链表操作逻辑:

1. 补充/完善辅助函数

// 查找是否存在对应ID的ListAPI节点,不存在则返回nullptr
ListAPI* checkListID(const string& id, ListAPI* head) {
    ListAPI* current = head;
    while (current != nullptr) {
        if (current->id == id) {
            return current;
        }
        current = current->next;
    }
    return nullptr;
}

// 将字符串转换为day枚举
int enumerateDay(const string& dayStr) {
    for (int i = 0; i < 7; ++i) {
        if (enumValues[i] == dayStr) {
            return i;
        }
    }
    return -1; // 返回-1表示无效输入
}

// 将day枚举转换为字符串
string getTextFromEnum(short dayVal) {
    if (dayVal >= 0 && dayVal < 7) {
        return enumValues[dayVal];
    }
    return "invalid_day";
}

2. 修正后的createLists函数

ListAPI *createLists(string arg) {
    ifstream f_in;
    ListAPI *apiHead = nullptr; // 保存整个API链表的头节点
    ListAPI *currentAPI = nullptr;

    f_in.open(arg);
    if (!f_in.is_open()) {
        cout << "\"" << arg << "\": file does not exist!" << endl;
        exit(EXIT_FAILURE);
    }

    string h, week, gr, id, sub;
    // 直接用输入流的状态判断循环是否结束,更简洁可靠
    while (f_in >> h >> week >> gr >> id >> sub) {
        // 1. 检查当前ID是否已存在于API链表中
        ListAPI* existingAPI = checkListID(id, apiHead);
        if (existingAPI != nullptr) {
            currentAPI = existingAPI;
        } else {
            // 2. 创建新的ListAPI节点并加入API链表
            ListAPI* newAPI = new ListAPI;
            newAPI->id = id;
            newAPI->next = nullptr;
            newAPI->head = nullptr; // 子链表初始为空

            // 将新节点添加到API链表的尾部
            if (apiHead == nullptr) {
                apiHead = newAPI;
            } else {
                ListAPI* temp = apiHead;
                while (temp->next != nullptr) {
                    temp = temp->next;
                }
                temp->next = newAPI;
            }
            currentAPI = newAPI;
        }

        // 3. 创建新的子链表节点并加入当前API的子链表
        _ListSub* newSub = new _ListSub;
        newSub->h = h;
        int dayIdx = enumerateDay(week);
        newSub->d = (dayIdx != -1) ? static_cast<day>(dayIdx) : mon;
        newSub->gr = gr;
        newSub->sub = sub;
        newSub->next = nullptr;

        // 将子节点添加到子链表的尾部
        if (currentAPI->head == nullptr) {
            currentAPI->head = newSub;
        } else {
            _ListSub* tempSub = currentAPI->head;
            while (tempSub->next != nullptr) {
                tempSub = tempSub->next;
            }
            tempSub->next = newSub;
        }
    }

    f_in.close();
    return apiHead; // 返回整个API链表的头节点
}

3. 修正后的主函数(支持遍历所有节点)

int main( int argc, char **argv ) {
    string ARGUMENT;
    // 补充参数校验逻辑
    if (argc < 2) {
        cout << "Please provide a file path as argument!" << endl;
        return EXIT_FAILURE;
    }
    ARGUMENT = argv[1];

    cout << "File path: " << ARGUMENT << endl;
    ListAPI *apiHead = createLists( ARGUMENT );
    cout << "List has been created." << endl;

    // 遍历所有API节点及其子链表
    ListAPI* currentAPI = apiHead;
    while (currentAPI != nullptr) {
        cout << "\n=== API ID: " << currentAPI->id << " ===" << endl;
        _ListSub* currentSub = currentAPI->head;
        while (currentSub != nullptr) {
            cout << "Subject: " << currentSub->sub << endl;
            cout << "Time: " << currentSub->h << endl;
            cout << "Day: " << getTextFromEnum(static_cast<short>(currentSub->d)) << endl;
            cout << "Group: " << currentSub->gr << endl;
            cout << "-------------------------" << endl;
            currentSub = currentSub->next;
        }
        currentAPI = currentAPI->next;
    }

    // 释放所有内存,避免内存泄漏
    currentAPI = apiHead;
    while (currentAPI != nullptr) {
        // 先释放子链表
        _ListSub* currentSub = currentAPI->head;
        while (currentSub != nullptr) {
            _ListSub* tempSub = currentSub;
            currentSub = currentSub->next;
            delete tempSub;
        }
        // 再释放API节点
        ListAPI* tempAPI = currentAPI;
        currentAPI = currentAPI->next;
        delete tempAPI;
    }

    return EXIT_SUCCESS;
}

三、关键修正点说明

  1. 子链表的正确连接:不再直接移动head指针,而是通过next指针将新节点链入子链表尾部,确保所有节点都能被访问到。
  2. 多API节点的管理:每次读取ID时先检查是否已存在,存在则复用该节点,不存在则创建新节点并加入API链表,完全符合你最初的设计目标。
  3. 避免空节点问题:子链表初始为空,只有当有数据时才创建节点,不会留下无数据的空节点,主函数能正确读取到内容。
  4. 内存泄漏修复:补充了完整的内存释放逻辑,避免程序结束后残留内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:24:55