尝试在二进制树中赋值时出现分段错误

Getting Segmentation Fault when trying to assign value in Binary Tree

本文关键字:分段 错误 赋值 二进制      更新时间:2023-10-16

我正在为我的C++类做一个BinaryTree项目,但我一直遇到分段错误。在TreeNode类的setValue()函数中,它不断打断我试图将x赋值给值的地方。有人知道为什么会发生这种事吗?

这是我的树节点类:

#ifndef TREENODE_H
#define TREENODE_H
#include <iostream>
template<typename T>
class TreeNode{
private:
    T value;
    TreeNode* left;
    TreeNode* right;
public:
    TreeNode();
    TreeNode(const T&);
    ~TreeNode();
    T& getValue();
    TreeNode* getLeft() const;
    TreeNode* getRight() const;
    void setValue(const T&);
    void setLeft(TreeNode*);
    void setRight(TreeNode*);
};
template<typename T>
TreeNode<T>::TreeNode()
{
    value = 0;
    left = NULL;
    right = NULL;
}
template<typename T>
TreeNode<T>::TreeNode(const T& x)
{
    value = x;
    left = NULL;
    right = NULL;
}
template<typename T>
TreeNode<T>::~TreeNode()
{
    if(left!=NULL)
        delete left;
    if(right!=NULL)
        delete right;
}
template<typename T>
void TreeNode<T>::setValue(const T& x)
{
    value=x;
}
template<typename T>
T& TreeNode<T>::getValue()
{
    return value;
}
template<typename T>
TreeNode<T>* TreeNode<T>::getLeft() const
{
    return left;
}
template<typename T>
TreeNode<T>* TreeNode<T>::getRight() const
{
    return right;
}
template<typename T>
void TreeNode<T>::setLeft(TreeNode* x)
{
    if(left!=NULL)
        delete left;
    left=new TreeNode;
    left=x;
}
template<typename T>
void TreeNode<T>::setRight(TreeNode* x)
{
    if(right!=NULL)
        delete right;
    right=new TreeNode;
    right=x;
}
#endif

这是我的BinaryTree类:

#ifndef BINARYTREE_H
#define BINARYTREE_H
#include "TreeNode.h"
#include <iostream>
template<typename T>
class BinaryTree:public TreeNode<T>{
public:
    BinaryTree();
    BinaryTree(const T&);
    ~BinaryTree();
    BinaryTree(const BinaryTree&);
    void insert(const T&);
    void inorder_traversal();
private:
    TreeNode<T>* root;
    TreeNode<T>* getRoot();
    void setRoot(const T&);
    void destroyTree(TreeNode<T>*);
};
template<typename T>
BinaryTree<T>::BinaryTree()
{
    root = new TreeNode <T>;
    root = NULL;
}
template<typename T>
BinaryTree<T>::BinaryTree(const T& x)
{
    root = new TreeNode <T>(x);
}
template<typename T>
BinaryTree<T>::BinaryTree(const BinaryTree<T>& A)
{
    root=A.getRoot();
}
template<typename T>
void BinaryTree<T>::destroyTree(TreeNode<T>* leaf)
{
    if(leaf!=NULL)
    {
        destroyTree(leaf->getLeft());
        destroyTree(leaf->getRight());
        delete leaf;
    }
}
template<typename T>
BinaryTree<T>::~BinaryTree()
{
    if(root!=NULL)
        destroyTree(root);
}
template<typename T>
TreeNode<T>* BinaryTree<T>::getRoot()
{
    return root;
}
template<typename T>
void BinaryTree<T>::setRoot(const T& x)
{
    if(root!=NULL)
    {
        delete root;
        root=new TreeNode<T>;
    }
    root->setValue(x);
}
template<typename T>
void BinaryTree<T>::insert(const T& x)
{
    if (root == NULL)
        setRoot(x);
    else
    {
        TreeNode<T>* rootTemp = new TreeNode < T > ;
        rootTemp = root;
        bool insertionComplete = false;
        while (!insertionComplete)
        {
            if (x < rootTemp->getValue())
            {
                if ((rootTemp->getLeft()) == NULL)
                {
                    (rootTemp->getLeft())->setValue(x);
                    insertionComplete = true;
                }
                else
                    rootTemp = rootTemp->getLeft();
            }
            else
            {
                if ((rootTemp->getRight()) == NULL)
                {
                    (rootTemp->getRight())->setValue(x);
                    insertionComplete = true;
                }
                else
                    rootTemp = rootTemp->getRight();
            }
        }
        root = rootTemp;
        delete rootTemp;
    }
}
#endif

这是我正在尝试运行的简单main.cpp:

#include "TreeNode.h"
#include "BinaryTree.h"
#include <iostream>
int main()
{
    BinaryTree<int> x(2);
    std::cout << "firstn";
    x.insert(1);
    std::cout<<"ENDn";
    return 0;
}

在您的类中,您有以下代码

if (x < rootTemp->getValue())
            {
                if ((rootTemp->getLeft()) == NULL)
                {
                    (rootTemp->getLeft())->setValue(x);
                    insertionComplete = true;
                }
                else
                    rootTemp = rootTemp->getLeft();
            }
            else
            {
                if ((rootTemp->getRight()) == NULL)
                {
                    (rootTemp->getRight())->setValue(x);
                    insertionComplete = true;
                }
                else
                    rootTemp = rootTemp->getRight();
            }

当对象是NULL时,您基本上是在调用setValue()。您必须从TreeNode对象初始化left和/或right,然后才能使用它们

没有过多的调试(我把它作为家庭作业留给你),这段代码:

    TreeNode<T>* rootTemp = new TreeNode < T > ;
    rootTemp = root;

看起来像是创建了一个对象(rootTemp),然后通过将其重新分配给root对象立即将其丢弃。进一步研究此处实现的逻辑。

if((rootTemp->getLeft())==NULL){(rootTemp->getLeft())->setValue(x)

您正在检查getLeft是否为NULL,然后取消对它的引用。

您的void BinaryTree::insert(const T&x)有一些缺陷:

您创建了一个新的TreeNode对象,并立即覆盖指向它的指针。这个新对象现在丢失了。进入太空。只需放下第一行

TreeNode<T>* rootTemp = new TreeNode < T >;
rootTemp = root;

最后覆盖根节点,旧的根节点现在就会丢失。进入太空。然后删除新的根节点(rootTemp)。任何对根节点的下一次访问现在都将崩溃。把两行都放下。

root = rootTemp;
delete rootTemp;

当您发现一个指向节点的空指针(指针为NULL)时,您将调用该指针的setValue。NULL表示后面没有对象可以执行您的操作=>分段错误(只是说您访问了一个不存在的对象)

 (rootTemp->getLeft())->setValue(x);

不过,TreeNode提供了适当的函数setLeft()。这里也是创建新树节点的理想场所:

rootTemp->setLeft(new TreeNode<T>(x));

由于构造函数重载,您甚至不需要调用集合值。

正如其他人所指出的,你还没有完全理解指针是如何工作的,以及新指针和删除指针的作用。

  • new=>在内存中创建并调用构造函数成员函数,返回内存地址
  • delete=>调用析构函数成员函数并删除内存(告诉内存管理,内存现在可以被其他人使用)
  • pointer=>只是一个地址,告诉CPU在内存中查找对象的位置

这会让你结束。但是您的程序在那之后由于对同一内存的双重删除而崩溃。如果你正在运行linux,你可以使用gdb来调试你的程序。只要打电话给gdb/您的程序位于正确目录下的终端中。"start"将启动程序,"continue"将告诉程序在停止(称为断点)后继续运行,"backtrace"有助于显示程序停止时调用了哪个函数。大多数IDE都有一个到gdb的接口,或者包含自己的调试器。

更进一步,您还会有一些额外的内存泄漏(您创建的对象会丢失,而且永远不会删除)。你可以用valgrind来搜索它们——leak-check=full/您的程序