0

I have an implementation of a binary tree using pointers. I am trying to print its nodes using preorder depth first traversal using recursion. When the program gets to right nodes it says segmentation fault. The problem is that I cannot find the error/mistake in the binary tree implementation. Program works when i use different btree implementation, so I assume the problem is in this btree implementation using pointers.

Below is my binary tree implementation

#include "../data-structures/trees/binary-tree-pointers/tree.h"
using namespace std;


void PrintTree(BinaryTree<int> tree, BinaryTree<int>::node node) {
   cout << tree.Label(node) << endl;
   if (tree.LeftChild(node) != tree.lambda) PrintTree(tree, tree.LeftChild(node));
   if (tree.RightChild(node) != tree.lambda) PrintTree(tree, tree.RightChild(node));
}

int main() {
   BinaryTree<int> tree;
   BinaryTree<int>::node node;

   tree.CreateRoot(1);
   tree.CreateLeftChild(tree.Root(), 2);
   tree.CreateRightChild(tree.Root(), 3);
   node = tree.Root();
   node = tree.LeftChild(node);
   tree.CreateLeftChild(node, 4);
   tree.CreateRightChild(node, 5);
   node = tree.LeftChild(node);
   tree.CreateLeftChild(node, 7);
   node = tree.Root();
   node = tree.RightChild(node);
   tree.CreateRightChild(node, 8);

   PrintTree(tree, tree.Root());

   return 0;
}

Here is my binary tree implementation:

#include <iostream>
#include <cstdlib>

template <typename nodeType>
class BinaryTree {
   private:
   struct Tnode {
      Tnode *parent, *left, *right;
      nodeType label;
   };

   Tnode *B;

   public:
   typedef Tnode* node;
   const node lambda = NULL;

   void Del(node n) {
      if (n->left != NULL) Del(n->left);
      if (n->right != NULL) Del(n->right);
      delete n;
   }

   void Prnt(node n) {
      std::cout << n->label << " ";
      if (n->left != NULL) Prnt(n->left);
      if (n->right != NULL) Prnt(n->right);
   }

   BinaryTree() {
      B = NULL;
   }

   BinaryTree(nodeType x) {
      B = new Tnode;
      B->parent = B->left = B->right = NULL;
      B->label = x;
   }

   bool IsEmpty() {
      return B == lambda;
   }

   nodeType Label(node n) {
      if (n == lambda) {
         std::cout << "That node doesn't exist!" << std::endl;
         exit(EXIT_FAILURE);
      }
      return n->label;
   }
   
   node Root() {
      return B;
   }

   node Parent(node n) {
      if (n == lambda) {
         std::cout << "That node doesn't exist!" << std::endl;
         exit(EXIT_FAILURE);
      }
      return n->parent;
   }

   node LeftChild(node n) {
      if (n == lambda) {
         std::cout << "That node doesn't exist!" << std::endl;
         exit(EXIT_FAILURE);
      }
      return n->left;
   }

   node RightChild(node n) {
      if (n == lambda) {
         std::cout << "That node doesn't exist!" << std::endl;
         exit(EXIT_FAILURE);
      }
      return n->right;
   }

   void ChangeLabel(node n, nodeType x) {
      if (n == lambda) {
         std::cout << "That node doesn't exist!" << std::endl;
         exit(EXIT_FAILURE);
      }
      n->label = x;
   }

   void CreateRoot(nodeType x) {
      if (!this->IsEmpty()) {
         std::cout << "Can't create root! Tree is not empty!" << std::endl;
         exit(EXIT_FAILURE);
      }
      B = new Tnode;
      B->parent = B->left = B->right = NULL;
      B->label = x;
   }

   void CreateLeftChild(node n, nodeType x) {
      if (n == lambda) {
         std::cout << "That node doesn't exist!" << std::endl;
         exit(EXIT_FAILURE);
      }
      if (n->left != lambda) {
         std::cout << "Can't create left node! It already exists" << std::endl;
         exit(EXIT_FAILURE);
      }
      Tnode *newNode = new Tnode;
      newNode->left = newNode->right = NULL;
      newNode->parent = n;
      newNode->label = x;
      n->left = newNode;
   }

   void CreateRightChild(node n, nodeType x) {
      if (n == lambda) {
         std::cout << "That node doesn't exist!" << std::endl;
         exit(EXIT_FAILURE);
      }
      if (n->right != lambda) {
         std::cout << "Can't create right node! It already exists" << std::endl;
         exit(EXIT_FAILURE);
      }
      Tnode *newNode = new Tnode;
      newNode->label = x;
      newNode->left = newNode->right = NULL;
      newNode->parent = n;
      n->right = newNode;
   }

   void Delete(node n) {
      if (n == lambda) {
         std::cout << "That node doesn't exist!" << std::endl;
         exit(EXIT_FAILURE);
      }
      if (n->parent != NULL) {
         if (n->parent->left == n) n->parent->left = NULL;
         else n->parent->right = NULL;
         Del(n);
      }
      else {
         Del(n);
         B = NULL;
      }
   }

   void Print() {
      Prnt(B);
      std::cout << std::endl;
   }

   ~BinaryTree() {
      if (B != lambda) Del(B);
   }
};
Timjuice
  • 1
  • 2
  • 2
    Did you use a debugger? See [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) and [What is a segmentation fault?](https://stackoverflow.com/questions/2346806/what-is-a-segmentation-fault). – Jason Aug 07 '22 at 08:59
  • 1
    `BinaryTree` is copy constructible, but not copy assignable. This not only breaks the rule of 3, but also results in a double free, since the parameter seen inside the `PrintTree` function is a copy of the object in the calling function that owns the same root node... It's also the reason you get into trouble accessing the tree after returning from one of the recursive `PrintTree` calls for the first time. – fabian Aug 07 '22 at 09:10
  • 1
    You should make the class non-copyable/moveable until you manually implement copy semantics to have the compiler complain about unexpected copies. Add the following members to `BinaryTree`: `BinaryTree(BinaryTree&&) = delete; BinaryTree& operator=(BinaryTree&&) = delete;` This will result in the move semantics to be user defined as deleted and therefore resulting in the implicitly defined copy semantics to be deleted too. – fabian Aug 07 '22 at 09:14
  • Fixed the problem. I just had to replace `BinaryTree tree` with `BinaryTree &tree` so its passed by reference. – Timjuice Aug 07 '22 at 10:50

0 Answers0