【问题标题】:EXC_BAD_ACCESS error in a c++ implementation of a binary search tree [closed]二叉搜索树的c ++实现中的EXC_BAD_ACCESS错误[关闭]
【发布时间】:2020-04-18 08:54:43
【问题描述】:

我目前正在学习 c++,为了学习它,我将实现一个简单的二叉搜索树类,以便掌握 c++ 中的概念。在实现 add 函数时,我收到一个有趣的错误,其中似乎程序无法将节点识别为 null,然后立即崩溃,因为节点应该为 null。

//Here is my add/insert function I created.
void BinarySearchTree::insert(double x){
    if(root == NULL){
        root = (struct TreeNode*) malloc(sizeof(struct TreeNode));
        root->val = x;
        return;
    }
    bool inserted = false;
    struct TreeNode* curr = root;
    while(curr != NULL && !inserted){
        if(curr->val == x){
            return;
        }
        if(x > curr->val){
            if(curr->right == NULL){
                curr->right = (struct TreeNode*) malloc(sizeof(struct TreeNode));
                curr->right->val = x;
                inserted = true;
            } else {
                curr = curr->right;
            }
        } else {
            if(curr->left == NULL){
                curr->left = (struct TreeNode*) malloc(sizeof(struct TreeNode));
                curr->left->val = x;
                inserted = true;
            } else {
                curr = curr->left;
            }
        }
    }
}


//This is the TreeNode struct and the BinarSearchTree class in my header file if it helps
struct TreeNode{
    double val;
    struct TreeNode *right;
    struct TreeNode *left;
};

class BinarySearchTree{
private:
    struct TreeNode *root;
public:
    void insert(double x);
};

【问题讨论】:

  • 您需要解决您的问题,以便显示的代码满足minimal reproducible example 的所有要求,如help center 中所述,否则任何人都不太可能为您提供帮助。虽然我确实在显示的代码中看到了一些几乎确定的错误,但除非可以证明,否则不能确定,这只能通过minimal reproducible example 来完成。
  • struct 关键字仅在您实际定义结构时在 C++ 中是必需的。其他时候,这是不必要的。
  • 只是一种预感,可能与leftright 似乎没有被初始化有关。您可能想为TreeNode 创建一个构造函数并将它们设置为nullptr
  • 是的,显示的代码无法初始化leftright。这就是崩溃的原因。出于某种原因,它还使用 C 库的 malloc,而不是 C++ 的 new。最后,insert() 是不必要的复杂和过度设计。 insert() 的经典递归实现要简单得多;它应该是,也许,十行左右的代码。 “你对管道的考虑越多,就越容易堵住排水管”——《星际迷航 III》中的斯科蒂。

标签: c++ xcode class struct binary-search-tree


【解决方案1】:

很高兴您正在学习 C++!

不要害怕:你只需要涉水更深一点,一切都会好起来的。 cmets 一致认为还有很多东西需要学习,但请相信我们:努力是值得的。

正如一些 cmets 所指出的,此示例中的主要问题是您没有正确初始化您在决策过程中使用的变量,这意味着它们包含垃圾——任何旧值——而不是您打算将它们归零。初始化在 C 语言中同样重要。 C++ 只会更多地握住你的手,确保你这样做——如果你愿意的话。

确实,稍后您可能会研究标准库提供的专用指针类型,但起初您可能希望只专注于学习 C++ 方式做事。您可能使用良好的 'ol malloc 进行分配,但是当您这样做时,您实际上只是在为自己做不必要的工作,同时将您的代码暴露给您遇到的那种问题遭遇。 C++ 为您提供operator new,它将为您完成所有繁重的工作,尤其是与适当的constructor 函数结合使用时。

简单的 C++ 语句:

new TreeNode;

... 做的比看起来的要多。首先它分配对象所需的内存——大多数实现在后台使用malloc。然后它调用您为该类定义的constructor 函数,以初始化结构中的数据。

首先,在TreeNode 中,您需要以下内容:

struct TreeNode {
   double val;
   TreeNode *right;
   TreeNode *left;

   // default constructor --'ctor'
   TreeNode():right(null), left(null) {}

   // useful ctor for your particular situation
   TreeNode( double val ):TreeNode(), val(val) {}
};

然后,在您的 ::insert 函数中:

// replace these lines...
if(root == NULL){
   root = (struct TreeNode*) malloc(sizeof(struct TreeNode));
   root->val = x;
   return;
} 

// with something like these...
if( !root ) {
   root = new TreeNode;   // root->val is garbage, for now
   return;
}

// and replace the two branch creation sections...
if(curr->right == NULL){
   curr->right = (struct TreeNode*) malloc(sizeof(struct TreeNode));
   curr->right->val = x;
   inserted = true;
}

// ... with something like this
if( !curr->right ) {
   curr->right = new TreeNode( x );
   break;   // you are only setting 'inserted' here to end your loop
}

构造函数 - 以及作为它们补充的析构函数 - 是强大的工具,您可以发现它们的许多细微差别。

然后,您可以深入了解精简和优化代码的细节。

【讨论】:

    猜你喜欢
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    • 2013-05-03
    • 1970-01-01
    • 2017-06-16
    • 1970-01-01
    • 2011-07-02
    • 1970-01-01
    相关资源
    最近更新 更多