尝试在二叉树中分配值时获取分段错误

时间:2016-04-18 09:31:16

标签: c++

我正在为我的C ++类做一个BinaryTree项目,并且我一直遇到分段错误。它在我的TreeNode类中的setValue()函数中尝试将x分配给值的地方不断破坏。有谁知道为什么会这样?

这是我的TreeNode类:

#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 << "first\n";
    x.insert(1);
    std::cout<<"END\n";
    return 0;
}

4 个答案:

答案 0 :(得分:2)

在你的课堂上,你有这段代码

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();
            }

当对象为setValue()时,您基本上在调用NULL。在使用之前,您必须先从left对象初始化right和/或TreeNode

答案 1 :(得分:2)

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

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

看起来像是在创建一个对象(rootTemp),然后通过将其重新分配给root对象立即抛弃它。进一步研究这里实施的逻辑。

答案 2 :(得分:0)

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

您正在检查getLeft是否为NULL,然后您将其解除引用。

答案 3 :(得分:0)

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

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

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

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

root = rootTemp;
delete rootTemp;

当您找到一个指向节点的空指针(指针为NULL)时,您可以在其上调用setValue。 NULL表示后面没有可以执行您的操作的对象=&gt;分段错误(简单地说你访问一个不存在的对象)

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

你的TreeNode虽然提供了合适的函数setLeft()。这里也是创建新TreeNode的理想场所:

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

由于构造函数重载,你甚至不需要调用设定值。

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

  • new =&gt;在内存中创建并调用构造函数成员函数,返回内存地址
  • delete =&gt;调用析构函数成员函数并删除内存(告诉内存管理,内存现在可以被其他人使用)
  • 指针=&gt;只是一个地址告诉你的CPU在哪里寻找对象的内存

这会让你到达END。但是由于在此之后在同一内存上双重删除,您的程序崩溃了。如果您运行的是linux,则可以使用gdb来调试程序。只需在右侧目录中的终端中调用gdb ./your-program即可。 &#34;开始&#34;将启动该计划,&#34;继续&#34;将告诉程序在停止(称为断点)和&#34;回溯&#34;之后继续运行。有助于向您显示程序停止时调用的函数。大多数IDE都有一个gdb接口或包含自己的调试器。

更进一步,您还会有一些额外的内存泄漏(您创建的对象随后会丢失并永不删除)。您可以使用valgrind --leak-check = full ./your-program

搜索它们