指针错误

Errors with Pointers

本文关键字:错误 指针      更新时间:2023-10-16

我一直在为一个更大的项目开发一个简单的二进制搜索树。我理解二进制搜索树的概念,只是在C++中实现的语法上有问题。我故意不使用boost的树容器。我对树的代码如下。

  struct Tree{
int nodeValue;
Tree *nodeChild1;
Tree *nodeChild2;
Tree(int userProvidedValue){
    nodeValue = userProvidedValue;
    nodeChild1 = NULL;
    nodeChild2 = NULL;
}
static void placeValue(Tree &parent, int value);
static Tree findValue(Tree parent, int value);
static void crawl(Tree parent);
~Tree(){
    delete nodeChild1;
    delete nodeChild2;
}
};
 void Tree::placeValue(Tree &parent, int value){
Tree node = Tree(value);
cout<<"made node"<<endl;
if(value>parent.nodeValue){
    cout<<"eval node child 2"<<endl;
    if(parent.nodeChild2 ==NULL){
        cout<<"reaching this";
        parent.nodeChild2 = &node;
    }
    else{
        placeValue(*parent.nodeChild2, value);
    }
}
if(value<=parent.nodeValue){
    cout<<"eval node child 1"<<endl;
    if(!parent.nodeChild1){
                cout<<"assigning"<<endl;
                parent.nodeChild1 = &node;
    }
            else{
                        placeValue(*parent.nodeChild1, value);
            }
        }
}

然而,每当我用Tree parent = Tree(5)构建一个树,然后用Tree::placeValue(parent, 4)向其添加另一个节点时,它编译得很好,但会弹出一条消息,告诉我exe已经崩溃。

有人能帮我了解这次撞击是从哪里来的吗?提前谢谢。

在树中爬行的代码如下所示:

void Tree::crawl(Tree parent){
cout<<parent.nodeValue<<endl;
if(NULL!=parent.nodeChild1){
    crawl(*parent.nodeChild1);
}
if(NULL!=parent.nodeChild2){
    crawl(*parent.nodeChild2);
}
}

附加问题:当Tree::crawl接受Tree&parent而不是Tree parent,它运行良好。然而,如果没有&然而它失败了。有人能解释一下为什么会这样吗?

您必须在堆上分配树。

Tree node = Tree(value);

在这里,您正在堆栈上分配一个树。此变量的地址将在超出范围后进行处理。为了在堆上分配它,只需使用新的运算符:

Tree *node = new Tree(value);

然后将其分配为父级的子级:

parent.nodeChild2 = node;

关于Tree::爬网错误,它是基于相同的错误。您一直在堆栈上分配Tree,因此一旦它超出范围,就会调用其析构函数,删除nodeChild1和nodeChild2。您应该通过使用指针或始终使用引用来管理这些类型的结构,这样当函数结束时,树的析构函数就不会被调用。因此:

void Tree::crawl(const Tree &parent){
  cout<<parent.nodeValue<<endl;
  if(NULL!=parent.nodeChild1){
      crawl(*parent.nodeChild1);
  }
  if(NULL!=parent.nodeChild2){
      crawl(*parent.nodeChild2);
  }
}

这应该做到。记住在Tree::findValue上也要这样做,你应该为这个函数使用这个签名:

static Tree findValue(const Tree &parent, int value);

分配包含堆栈上新值的Tree()实例,即Tree node = Tree(value);。当函数调用返回时,该实例将被销毁,因此当您稍后尝试访问它时,程序将崩溃。

此外,您的析构函数在其两个子级上都调用delete,因此您应该在堆上分配Tree实例来解决您的问题:Tree* node = new Tree(value);

Tree node = Tree(value);

node具有它在其中声明的程序块的作用域。退出Tree::placeValue后,它将自动删除。当您在它上面获得指针(parent.nodeChild2 = &node;)时,它将在退出后不指向任何内容,并尝试取消引用它将导致未定义的行为。动态创建如下:

Tree * node = new Tree(value);