【问题标题】:freeing memory causing segmentation fault 11释放内存导致分段错误 11
【发布时间】:2021-08-23 22:43:24
【问题描述】:

我正在尝试创建一个二叉搜索树。这是我的节点初始化函数:

node_t* node_init(int val){
        node_t* n1 = malloc(sizeof(node_t));
        n1->value = val;
        n1->leftNode = NULL;
        n1->rightNode = NULL;

        return n1;
}

由于我正在分配内存,我知道我应该在其他地方释放它。我在我的主要方法中这样做:

int main(){
        tree_t t1;
        tree_init(&t1);
        
        node_t* n1 = node_init(5);

        node_t* n2 = node_init(7);
        

        t1.count += add(n1, &(t1.root));
        t1.count += add(n2, &(t1.root));

        //free(n1);
        //free(n2);
        
        print_tree(t1.root);
}

然而,当我取消注释释放行时,我得到一个分段错误错误。我不确定为什么会这样,因为一旦分配了内存,我就必须释放它。我没有在我的add 函数中进行任何释放,并且代码打印出一个没有free 语句的有效二叉搜索树。

如果有帮助,这是我的添加功能:

int add(node_t* n, node_t** tn){
        if(*tn == NULL){*tn = n; return 1;}
        if(n->value < (*tn)->value){add(n, &((*tn)->leftNode));}
        else if (n->value > (*tn)->value){add(n, &((*tn)->rightNode));}
        else{return 0;}
}

【问题讨论】:

  • 如果可能,请提供minimal reproducible example。
  • 释放节点后,您可能无法再次访问它们。认为print_tree 会尝试访问树中的节点似乎是合理的,因此在调用该函数之前不能释放它们。
  • 通常,通过遍历树来找到它们,而不是通过保留和使用指向它们的单独指针来释放树中的所有节点。任何一种方式都可以,但后者需要维护额外的数据结构。

标签: c segmentation-fault malloc binary-search-tree free


【解决方案1】:

对于初学者来说,函数 add 具有未定义的行为,因为在某些执行路径中它什么也不返回。

你需要写

int add(node_t* n, node_t** tn){
        if(*tn == NULL){*tn = n; return 1;}
        if(n->value < (*tn)->value){ return add(n, &((*tn)->leftNode));}
        else if (n->value > (*tn)->value){ return add(n, &((*tn)->rightNode));}
        else{return 0;}
}

这些带有免费调用的语句

    free(n1);
    free(n2);
    

不要在树中将 n1 和 n2 设置为 NULL。所以这个电话

    print_tree(t1.root);

调用未定义的行为。

【讨论】:

  • 明白!抱歉,您说免费调用“不要在树中将 n1 和 n2 设置为 NULL?”那么它们设置为什么,为什么打印树会调用未定义的行为?
  • @rjc810 函数 free 只是释放用作参数的指针指向的内存。用作参数的原始指针本身没有改变。因此,在函数 print_tree 中,您使用指针 n1 和 n2 来访问已释放的内存。
  • 在你的回答中,你写道:"the function add has undefined behavior because in some paths of execution it returns nothing."——这个说法不太正确。与 C++ 相比,这不会导致 C 中的未定义行为。有关详细信息,请参阅 this question。
  • @AndreasWenzel 这里用到了函数的返回值,比如 t1.count += add(n1, &(t1.root));
  • @VladfromMoscow:是的,访问不存在的返回值是导致C中未定义行为的原因。因此,未定义行为不是由函数add引起的,而是由函数@引起的987654327@.
猜你喜欢
  • 2020-03-14
  • 2021-05-12
  • 2012-06-15
  • 2023-03-04
  • 2013-08-01
  • 2013-05-10
  • 1970-01-01
  • 1970-01-01
  • 2023-03-03
相关资源
最近更新 更多