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

使用strcmp比较字符串触发EXC_BAD_ACCESS的红黑树插入问题

排查红黑树插入函数的EXC_BAD_ACCESS错误

我帮你仔细梳理了代码里的问题,这个EXC_BAD_ACCESS错误主要是由逻辑颠倒、内存使用不当和哨兵节点误用导致的,下面是具体分析和修复方案:


核心错误分析

1. 哨兵节点初始化与使用错误

你的哨兵节点sent在主函数里被初始化为left/right/parent全为NULL,但红黑树的哨兵应该作为所有叶子节点的统一替代(所有真实节点的左右子节点都指向哨兵)。第一次插入后,sent的left/right仍为NULL,后续循环中temp = sent->left会取到空指针,访问temp->id_prod直接触发内存错误。

另外,循环终止时temp == sent,你直接用strcmp比较新节点和哨兵的id_prod,但哨兵的id_prod从未初始化,读取未定义内存必然触发崩溃。

2. 插入路径的比较逻辑完全颠倒

在寻找插入位置的循环中:

if(strcmp(temp->id_prod, new_node->id_prod) < 0) {
    temp = temp->left;
}

strcmp(a,b) < 0表示a的字典序小于b,也就是当前节点temp的ID比新节点小,按照红黑树左小右大的规则,新节点应该放在temp的右子树,但你却让temp移向left,这会导致循环走向错误分支,要么死循环,要么访问空指针。

3. 内存泄漏与指针赋值错误

你在insert_id开头执行了:

node *temp = malloc(sizeof(struct node));
temp = sent->left;

先分配内存给temp,立刻又让它指向sent->left,导致之前的内存地址丢失,造成内存泄漏。如果sent->left是NULL,temp就变成空指针,后续访问temp->id_prod直接崩溃。

4. 红黑树颜色规则错误

红黑树插入新节点时默认应该设为红色(根节点除外),你把所有新节点都设为黑色,会破坏“根到叶子路径黑色节点数相同”的性质,后续平衡修复也无法正常工作。


修复后的完整代码方案

1. 修正哨兵节点初始化

主函数里哨兵节点初始时应自身指向自身,避免空指针访问:

#define STORE "Magazzino.txt"
typedef enum { red, black } color; // 补充color枚举定义

int main() {
    FILE *input;
    node *sent = malloc(sizeof(struct node));
    sent->color_node = black;
    // 哨兵初始:左右子节点指向自身,parent为NULL表示树为空
    sent->left = sent;
    sent->right = sent;
    sent->parent = NULL;

    input = fopen(STORE, "r");
    if (!input) { // 增加文件打开失败判断
        perror("Failed to open file");
        return 1;
    }

    node *new_node;
    while ((new_node = get_node_file(input)) != NULL) {
        insert_id(sent, new_node);
    }

    fclose(input);
    // 后续记得递归释放红黑树内存,避免泄漏
    return 0;
}

2. 修正insert_id函数逻辑

修复比较逻辑、内存泄漏和哨兵使用:

void insert_id(node *sent, node *new_node) {
    if (sent->parent == NULL) { 
        // 树为空,新节点作为根
        sent->parent = new_node;
        new_node->parent = sent;
        new_node->left = sent;
        new_node->right = sent;
        new_node->color_node = black;
    } else {
        // 从根节点开始寻找插入位置(sent->parent是根)
        node *temp = sent->parent;
        while (temp != sent) {
            int cmp = strcmp(temp->id_prod, new_node->id_prod);
            if (cmp < 0) {
                // 当前节点ID更小,往右子树走
                temp = (temp->right != sent) ? temp->right : sent;
            } else {
                // 当前节点ID更大/相等,往左子树走
                temp = (temp->left != sent) ? temp->left : sent;
            }
            if (temp == sent) break;
        }
        // 找到父节点,回溯一步
        node *parent = temp->parent;
        int cmp = strcmp(parent->id_prod, new_node->id_prod);
        if (cmp < 0) {
            parent->right = new_node;
        } else {
            parent->left = new_node;
        }
        new_node->parent = parent;
        new_node->left = sent;
        new_node->right = sent;
        new_node->color_node = red; // 新节点默认红色
        setup_tree(sent, new_node); // 修复红黑树平衡
    }
}

3. 完善get_node_file函数

增加内存分配和读取失败的判断,防止溢出:

#define FORMAT_IN "%4s %19s %4s" // 适配char数组长度,防止溢出

node* get_node_file(FILE *in) {
    node *new_node = malloc(sizeof(node));
    if (!new_node) {
        perror("Failed to allocate node");
        return NULL;
    }
    // 检查fscanf返回值,确保读取3个字段成功
    if (fscanf(in, FORMAT_IN, new_node->id_prod, new_node->name, new_node->id_piece) != 3) {
        free(new_node);
        return NULL;
    }
    new_node->left = NULL;
    new_node->right = NULL;
    new_node->parent = NULL;
    new_node->color_node = black;
    return new_node;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:47:25