I'm trying to implement a binary search tree in C, more specifically looking for the predecessor. However, whenever I try to run the program I get the segmentation vault. Here's the code in question:
#include <stdio.h>
#include <stdlib.h>
struct tree
{
int a;
tree *left;
tree *right;
tree *prev;
}*root=NULL;
tree *searchSpecific (tree *root, int val)
{
tree *x=root;
if (!x)
{
return NULL;
}
else
{
while(x && val!=x->a)
{
if (val>x->a)
x=x->left;
else x=x->right;
}
}
return x;
}
int previous(tree *root, int f)
{
tree *x=searchSpecific(root,f);
if(x->left)
{
x=x->left;
while(x->right) x = x->right;
return x->a;
}
tree *temp;
do
{
temp = x;
x = x->prev;
} while(x && (x->right != temp));
return x->a;
}
The segfault appears at the if statement if(x->left) in the previous() function. I want to check if the node in question exists, but the program crashes every time and I have no idea what is wrong with it..
Since searchSpecific may return NULL, you need to protect your code from it, and check x before accessing one of its members:
tree *x=searchSpecific(root,f);
if (x != NULL && x->left)
The segmentation fault can appear due to several reasons, such as:
x is undefined, which may be caused by your *searchSpecific function
x is NULL, because your function returns a NULL pointer
x->left is NULL, which means trying to access it causes something bad to happen
So, how I'll go about doing this would be trying to check if the returned tree is null using a simple if statement as follows:
if (x == NULL) {
/* throw error or not found message */
}
I would also suggest you dynamically allocate memory for your tree before doing anything with it, by creating a reusable func like create_tree() with the following code:
tree create_tree(int data) {
tree *x;
x = malloc(sizeof(tree));
x->a = data;
x->left = x->right = x->prev = NULL;
return x;
}
Why? Note that in your code snippets, you just declare
tree *some_tree_name;
which is very dangerous every time you try to do something with it, and might lead to your code crashing on you on the do/while loop later.
Related
This question already has answers here:
Warning of "Control may reach end of non-void function"
(3 answers)
Closed 1 year ago.
I was coding a BST Tree, and first i made it with integer key, everything worked fine. Then i copied my code and made some changes, i switched integer key to string key and also added one new pointer (because my goal is to create two trees, one with English words and one with their Polish translation) so i tested it just on single tree with string key first and insert function works fine like in the interger tree, but search function is returning some garbage insted of NULL or pointer to node. I dont really know what is a problem here.
I put the code of Integer tree below:
#include <iostream>
#include <fstream>
#include <string.h>
#include <string>
using namespace std;
typedef struct BST
{
int key;
BST* right;
BST* left;
}BST_node;
BST_node* CreateNewNode(int data) // function that returns new node of my tree
{
BST_node* NewNode = new BST_node;
NewNode->key = data;
NewNode->right = NULL;
NewNode->left = NULL;
return NewNode;
}
BST_node* bstSearch(BST_node* root, int data) // search function
{
if (root == NULL)
return NULL;
else if (root->key == data)
return root;
else if (root->key < data)
bstSearch(root->right, data);
else
bstSearch(root->left, data);
}
void bstInsert(BST_node*& root, int data) // insert function
{
if (root == NULL)
root = CreateNewNode(data);
if (data < root->key)
bstInsert(root->left, data);
else if (data > root->key)
bstInsert(root->right, data);
}
int main()
{
ifstream in1("InTest1.txt"); // InTest1.txt:1 2 4 3 5 52 2 4
BST_node* root = NULL;
int suppVar;
while (!in1.eof())
{
in1 >> suppVar;
bstInsert(rootEng, suppVar);
}
BST_node* tmp = bstSearch(rootEng, 2);
if (tmp == NULL)
cout << "There is no element with given key";
else
cout << "key = " << tmp->key;
}
OUT: key = 2
And also i put the code of string key version of my tree below:
#include <iostream>
#include <fstream>
#include <string.h>
#include <string>
using namespace std;
typedef struct BST_str
{
string key;
BST_str* right;
BST_str* left;
BST_str* engWordPtr; // pointer to node in translation tree (not used yet)
}BST_strNode;
BST_strNode* CreateNewStrNode(string data) // function that returns new node of my tree
{
BST_strNode* NewNode = new BST_strNode;
NewNode->key = data;
NewNode->right = NULL;
NewNode->left = NULL;
NewNode->engWordPtr = NULL;
return NewNode;
}
BST_strNode* bstStrSearch(BST_strNode* root, string data) // search function
{
if (root == NULL)
return NULL;
else if (strcmp(root->key.data(), data.data()) == 0)
return root;
else if (strcmp(root->key.data(), data.data()) < 0)
bstStrSearch(root->right, data);
else if (strcmp(root->key.data(), data.data()) > 0)
bstStrSearch(root->left, data);
}
void bstStrInsert(BST_strNode*& root, string data) // insert function
{
if (root == NULL)
root = CreateNewStrNode(data);
else if (strcmp(root->key.data(), data.data()) > 0)
bstStrInsert(root->left, data);
else if (strcmp(root->key.data(), data.data()) < 0)
bstStrInsert(root->right, data);
}
int main()
{
ifstream in1("InTest2.txt"); // InTest2.txt:O G X E OH D F I OA H OB OX
BST_strNode* rootEng = NULL;
string suppVar;
while (!in1.eof())
{
in1 >> suppVar;
bstStrInsert(rootEng, suppVar);
}
BST_strNode* tmp = bstStrSearch(rootEng, "OXcasdf");
if (tmp == NULL)
cout << "There is no element with given key";
else
cout << "key = " << tmp->key;
}
OUT: key =
And program crashes, it doesnt matter if i want to search for string that is already there or not, always the same result, probably its returning some garbage instead of node or NULL but i don't really know why it's working on integer tree, but on string tree doesn't. It also generates 3 warnings:
Warning C26495 Variable 'BST_str::engWordPtr' is uninitialized. Always initialize a member variable (type.6).
Warning C26495 Variable 'BST_str::left' is uninitialized. Always initialize a member variable (type.6).
Warning C26495 Variable 'BST_str::right' is uninitialized. Always initialize a member variable (type.6).
And also an exception while debugging:
Exception thrown: read access violation. this was 0x45.
Thanks for the help in advance.
The recursive function bstSearch is incorrect because it does not return a node in each its path of execution
BST_node* bstSearch(BST_node* root, int data) // search function
{
if (root == NULL)
return NULL;
else if (root->key == data)
return root;
else if (root->key < data)
bstSearch(root->right, data);
else
bstSearch(root->left, data);
}
The last if else statements should look like
else if (root->key < data)
return bstSearch(root->right, data);
else
return bstSearch(root->left, data);
Also for the function designed for strings there is no need to use the C function strcmp. The function could be defined the following way
BST_strNode* bstStrSearch( BST_strNode* root, const string &data) // search function
{
if (root == NULL)
return NULL;
else if ( root->key == data )
return root;
else if ( root->key < data )
return bstStrSearch(root->right, data);
else
return bstStrSearch(root->left, data);
}
Pay attention to that the condition of the while loop
while (!in1.eof())
{
in1 >> suppVar;
bstStrInsert(rootEng, suppVar);
}
is incorrect. The eof state can occur after this statement
in1 >> suppVar;
Instead you should write
while ( in1 >> suppVar)
{
bstStrInsert(rootEng, suppVar);
}
Note when compiled, the compiler should print a warning along the lines of:
warning: control may reach end of non-void function
in reference to bstStrInsert. Indeed, looking at the function definition, the two recursive branches don't return a value.
To prevent the warning (and this sort of error in general), you can use a local variable to hold the result, and have a single return.
Additionally, the functions should be rewritten as member function of the BST node class. You can also use templates (and template specializations) rather than creating separate, unrelated BST classes for each key type. With scohe001's protip, the template functions will work with any key type that implements standard comparison operators (so you don't have to write a specialization for std::string).
template<typename K> BST_Node<K>* BST_Node<K>::search(BST_Node<K>* node, const K& data) {
BST_Node<K>* result = NULL;
if (node) {
if (node->key == data)
result = node;
else if (node->key < data)
result = search(node->right, data);
else // if (node->key > data)
result = search(node->left, data);
}
return result;
}
Since the last branch covers all remaining cases, the if (node->key > data) test is unnecessary.
The above BST_Node<K>::search has an extra BST_Node<K>* argument that isn't strictly necessary. An alternative is to call search on each node, which means moving the pointer test to immediately before each recursive call (and operating on this, rather than the extra node argument).
template<typename K> BST_Node<K>* BST_Node<K>::search(const K& data) {
BST_Node<K>* result = NULL;
if (key == data)
result = this;
else if (key < data) {
if (right) {
result = right->search(data);
}
} else if (left) // (key > data)
result = left->search(data);
return result;
}
In general, an interactive debugger is your most powerful tool for troubleshooting crashes and unexpected behavior. Find and learn to use whatever debugger your development suite provides.
Additional
As noted in C++ references, passing string::data to C string functions can result in undefined behavior, as it's not guaranteed to be null terminated. string::c_str should be used for that purpose, but (in general) C string functions should only be used when interacting with C code (such as libraries).
When printing a message, be sure to include a newline. This can be done with a newline in the string, but better is to output std::endl, which will also flush the output buffer (if output is buffered, which it probably is).
Importing all of std into the current namespace is fine for one-offs, sample and practice code, but shouldn't be done in production. Importing specific symbols (such as std::cin, std::cout and std::endl) is fine and unlikely to cause collisions.
I am working on question to check if Binary structure tree is balanced or not and when I run the code, I get EXC_BAD_ACCESS and I'm not sure how fix problem and what is causing it to break.
The code is suppose to hit NULL and return (true,-1) at some point and go deep into left subtree. Then return and go to right subtree. We can check whether the subtrees of left and right are balanced by different if it is <= 1. and get its height by max(left,right) +1 for each node.
if <= 1 means not balance returns (false , height) and it bubbles up to recursion.
Thanks
#include <iostream>
using namespace std;
struct TreeNode {
TreeNode * left;
TreeNode * right;
};
class balanceStatusAndHeight{
public:
bool isBalanced;
int height;
balanceStatusAndHeight(bool isBalanced, int height);
};
balanceStatusAndHeight::balanceStatusAndHeight(bool isBalanced, int height) {
this->isBalanced = isBalanced;
this->height = height;
}
balanceStatusAndHeight checkBalance(TreeNode * root) {
if (root == NULL ) {
return balanceStatusAndHeight(true, -1);
}
balanceStatusAndHeight leftResult = checkBalance(root->left);
if ( !leftResult.isBalanced ) {
return leftResult;
}
balanceStatusAndHeight rightResult = checkBalance(root->right);
if ( !rightResult.isBalanced) {
return rightResult;
}
bool subTreesAreBalanced = abs(leftResult.height - rightResult.height) <= 1;
int height = max(leftResult.height, rightResult.height) + 1;
return balanceStatusAndHeight(subTreesAreBalanced, height);
};
int main(int argc, const char * argv[]) {
TreeNode *a = new TreeNode;
a->left = new TreeNode;
a->left->left = new TreeNode;
balanceStatusAndHeight c = checkBalance(a);
cout << c.isBalanced << endl;
return 0;
}
In checkBalance
if (root == NULL )
expects tree branches to be NULL terminated. Unfortunately nothing in the code ensures that the trees are NULL terminated, so this test fails when it hits an uninitialized left or right pointer and then the program tries to access the invalid TreeNode at the uninitialized pointer.
With a modern compiler
struct TreeNode {
TreeNode * left = NULL; // but prefer nullptr to NULL as it has better type safety
TreeNode * right = NULL;
};
solves that problem. Since NULL is being used instead of nullptr the compiler may be old or deliberately set to an older C++ Standard revision and a constructor will be needed instead.
struct TreeNode {
TreeNode * left;
TreeNode * right;
TreeNode():left(NULL), right(NULL)
{
}
};
A smarter constructor or crafty use of aggregate initialization can make your life easier.
Does the program work after this change? No idea. Didn't test for that. It exits without a crash, though.
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node *left, *right;
Node()
{
data = NULL;
left = right = NULL;
}
};
Node* insertBST(Node* root, int value)
{
if (root == NULL) {
root->data = value;
root->left = root->right = NULL;
}
if ((root->data) > value)
insertBST(root->left, value);
if ((root->data) < value)
insertBST(root->right, value);
}
Node* printBST(Node* root)
{
if (root != NULL) {
printBST(root->left);
cout << "\n" << root->data;
printBST(root->right);
}
}
int main()
{
Node* root = new Node;
insertBST(root, 30);
insertBST(root, 20);
insertBST(root, 40);
insertBST(root, 70);
insertBST(root, 60);
insertBST(root, 80);
printBST(root);
}
Above is the code which I wrote to implement Binary Search Tree. When I execute it, the program stops responding and closes. I tried getting help from pythontutor.com but I am not able to tackle it.What should I do to make it run without error?
here is where it stops : Click to see
Any help is appreciated,I am new to writing program.
In insertBST in the case of root == NULL you do not create a new node and attempt to modify the contents of root, as this is null it should result in an access violation or segmentation fault.
I think the reason your program is hanging instead of crashing is that you are using an online compiler that ignores invalid writes and instead allows the program to continue. This then possibly ends up with infinite recursion through the insertBST function.
To fix this you need to allocate a new node, one way would be as follows:
void insertBST(Node*& root, int value)
{
if (root == NULL) {
root = new Node();
root->data = value;
root->left = root->right = NULL;
}
if ((root->data) > value)
insertBST(root->left, value);
if ((root->data) < value)
insertBST(root->right, value);
}
Note that your program leaks all the nodes that it allocates. You should write a destructor in Node which deletes all child nodes and call delete root at the end of your program. Alternatively don't use raw pointers at all and use std::shared_ptr or std::unique_ptr instead.
I am trying to insert into a Binary Search Tree everything compiles but when I try to run the program I get Segmentation fault (core dumped) everything looks good to me and I can't find the issue. Please Help.
int main()
{
struct node
{
int item;
node *left;
node *right;
};
node * root = NULL;
int x = 9;
void BinarySearchTree::insert(x)
{
insert(x, root);
}
void insert(x, node *t)
{
if(t == NULL)
{
t-> item = x;
t->left = NULL;
t->right = NULL;
}
else if(x < t-> item)
{
insert(x, t->left);
}
else if(t->item < x)
{
insert(x, t->right);
}
else
{
;//do nothing
}
}
}
If the pointer is null, then you try to indirect through it to set the values of the non-existent node. That will cause your segfault.
You probably want to take the argument by reference, so you can update it to point to a new node if necessary:
void insert(x, node *&t)
{ // ^
if (t == nullptr) {
t = new node {x, nullptr, nullptr};
}
// the rest of the function should work as it is
}
The question is incomplete, and without context it becomes difficult to answer accurately. That being said, there is something in the code that seems unhealthy.
the
void insert(x, node *t){}
function takes a value, and a pointer to an allocated structure.
if you hand it a null value, instead of a pointer to an allocated structure, your code will attempt to assign a value to null->item which is still null. So this will give you a segmentation fault.
if(t == NULL)
{
t-> item = x;
t->left = NULL;
t->right = NULL;
}
You must decide what to do, when not handed a a pointer to a previously allocated structure.
either, throw exception, or automatically create a new object (allocate the structure), and then assign the value.
notice if you do the latter, that you will need to return the address, of the pointer, or change the parameter to become a reference to a pointer...
This is my first time working with trees. I wrote a c++ code, but it says Segmentation fault (core dumped) , As far as I searched, this error comes from accessing a memory location that may be NULL. I tried 'new' keyword as malloc() should be avoided in c++, But still I didn't get how to resolve this in my code.
# include<iostream>
using namespace std;
struct node
{
int data;
node *left;
node *right;
}*next;
int k=0;
void tree(int i,/*struct*/ node *next = new node)
{
++k; --i;
if (i==0)
return;
//next = new node;
next->data = k*k;
next->left = NULL;
next->right = NULL;
tree(i, next->left);
tree(i, next->right);
return ;
}
void display (node* next)
{
cout<<next->data<<" ";
if (next->left!=NULL)
{
display(next->left);
display(next->right);
}
}
int main()
{
int h;
cout<<"Enter the expected height of tree : ";
cin>>h;
node *root;
root = new node;
root->data=0;
root->left=NULL;
root->right=NULL;
tree(h, (root->left));
tree(h, (root->right));
cout<<root->data<<" ";
display(root->left);
display(root->right);
return 0;
}
There are serious problems with this code. In particular, here:
void display (node* next)
{
cout<<next->data<<" ";
if (next->left!=NULL)
{
...
}
}
You dereference next without ever checking to see whether it's null. And it will be null. That's enough to explain the error you see.
I say that it will be null because of this:
void tree(int i,/*struct*/ node *next = new node)
{
...
return ;
}
...
root->left=NULL;
...
tree(h, (root->left));
...
display(root->left);
The tree function takes its second argument by value-- that means that it does not change the value of root->left. You then call display with a null argument. I suspect that you think void tree(int i,/*struct*/ node *next = new node) means something other than what it actually means.
More fundamentally, you must review the two ways to pass an argument, by reference and by value.
More fundamentally still, you must start with a small, simple program and build up in small steps, rather than trying to write a big complex program all at once.
#include <iostream>
using namespace std;
struct node
{
int data;
struct node *left;
struct node *right;
};
void tree(int i, struct node **root, int k)
{
if (i < 1)
return;
*root = new struct node;
(*root)->data = k*k;
(*root)->left = NULL;
(*root)->right = NULL;
tree(i - 1, &((*root)->left), k + 1);
tree(i - 1, &((*root)->right), k + 1);
}
void display(struct node *root)
{
if (root == NULL)
return;
cout << root->data << " ";
if (root->left != NULL)
display(root->left);
if (root->right != NULL)
display(root->right);
}
int main()
{
struct node *root;
int h;
cout<<"Enter the expected height of tree : ";
cin>>h;
tree(h, &root, 0);
display(root);
return 0;
}
I think you should do some more read up on how pointers works: http://www.tutorialspoint.com/cprogramming/c_pointers.htm
When you where calling tree(h, root->left) you actually just send the pointers value "NULL" == 0x0. As you want to allocate memory for it you should send a reference to the pointer. Hence &root and &((*root)->left). In the display function you have to check for NULL values both for left and right.
The code above is only improved and doesn't handle any freeing of memory, to be able to do that, traverse the tree and use delete on all leafs and work you back to the root.