我正在为我的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;
}
答案 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));
由于构造函数重载,你甚至不需要调用设定值。
正如其他人所指出的,你还没有完全理解指针是如何工作的,以及新的和删除对它们的作用。
这会让你到达END。但是由于在此之后在同一内存上双重删除,您的程序崩溃了。如果您运行的是linux,则可以使用gdb来调试程序。只需在右侧目录中的终端中调用gdb ./your-program即可。 &#34;开始&#34;将启动该计划,&#34;继续&#34;将告诉程序在停止(称为断点)和&#34;回溯&#34;之后继续运行。有助于向您显示程序停止时调用的函数。大多数IDE都有一个gdb接口或包含自己的调试器。
更进一步,您还会有一些额外的内存泄漏(您创建的对象随后会丢失并永不删除)。您可以使用valgrind --leak-check = full ./your-program
搜索它们