I'm getting a segmentation fault on the if (currNode->right) check. Can anyone spot the obvious mistake that I made?
struct node
{
int data;
node* left;
node* right;
};
void Preorder(node *root) {
std::stack<node*> currStack;
currStack.push(root);
while(currStack.top()) {
node *currNode = currStack.top();
currStack.pop();
if (currNode->right) {
currStack.push(currNode->right);
}
if (currNode->left) {
currStack.push(currNode->left);
}
// Print to console
printf("%d ", currNode->data);
}
}
It might be related to my main function, so i'll add it below for reference:
int main() {
node myNode;
myNode.data = 3;
node myNode1;
myNode1.data = 4;
node myNode2;
myNode2.data = 5;
node myNode3;
myNode3.data = 6;
node myNode4;
myNode4.data = 7;
myNode.left = &myNode1;
myNode.right = &myNode2;
myNode1.left = &myNode3;
myNode1.right = &myNode4;
Preorder(&myNode);
return 0;
}
This is due to uninitialized values of left and right pointers in myNode2, myNode3, and myNode4.
Define a constructor for node and you're good:
struct node
{
int data;
node* left;
node* right;
node() : data(0), left(nullptr), right(nullptr) {}
};
currNode seems to be invalid, e.g. NULL. You should check that case before using the pointer in the condition.
This might happen on your top stack node?
Found the Problem: Change the loop condition to while(!currStack.empty()) {}
Actually, I find while(currStack.top()) a pretty strange condition. top() returns a const reference, not a pointer (if you ever expected to get NULL). But if the referenced value is a pointer, and it is NULL, or if we get a reference to, say, int = 0, the loop ends.
Are you sure that's what you wanted? And if there are no elements in the stack, it probably results in an undefined behavior, but it definitely can't return NULL, if you expected that.
Related
I was going through insertion of a node on BST recursively and I found an implementation below (check rinsert() function in the code below). The recursive function returns a pointer of the newly inserted node.
If the node is inserted lets say to the leaf node of height 4 for a tree. Shouldn't all the nodes along the path from height 3 to root be referencing some garbage pointer?
You can also find a test() function which actually returns a garbage pointer when the function doesn't run into an explicit return statement.
When I ran an inorder traversal using rinsert(), I was getting the BST without any garbage values.
Can anybody please help me understand what is going on in the rinsert() function?
struct Node {
Node* left;
Node* right;
int key;
Node(int key) {
this->key = key;
left = NULL;
right = NULL;
}
};
class BST {
Node* root;
public:
BST(int key) {
root = new Node(key);
}
Node* rinsert(Node* cur, int key) {
if (!cur) return new Node(key);
if (key < cur->key)
cur->left = rinsert(cur->left, key);
else
cur->right = rinsert(cur->right, key);
}
void inorder(Node* node) {
if (node == NULL) return;
inorder(node->left);
cout<<node->key<<" ";
inorder(node->right);
}
Node* getRoot() {
return root;
}
};
// function to return garbage pointer
Node* test() {
if (0) return new Node(2);
}
int main() {
BST bst = BST(2);
bst.rinsert(bst.getRoot(), 3);
bst.rinsert(bst.getRoot(), 1);
bst.rinsert(bst.getRoot(), 0);
bst.rinsert(bst.getRoot(), 7);
bst.rinsert(bst.getRoot(), 8);
bst.rinsert(bst.getRoot(), 4);
bst.rinsert(bst.getRoot(), 9);
bst.inorder(bst.getRoot());
// is it really a garbage pointer?
Node* t = test();
cout<<endl;
cout<<t->key;
}
output:
0 1 2 3 4 7 8 9
253425920
Yes the function is bugged because although it promises to return a Node* it doesn't in all cases.
The correct code (untested) is
Node* rinsert(Node* cur, int key) {
if (!cur) return new Node(key);
if (key < cur->key)
cur->left = rinsert(cur->left, key);
else
cur->right = rinsert(cur->right, key);
return cur; // new code
}
The lack of a return statement means the posted code invokes undefined behaviour. Unfortunately undefined behaviour does not mean a program will not work, it does not mean that the function will return a garbage pointer. Just by chance, in this case, the right pointer happens to be in the right register for the return value to be correct. So the code 'works'. On a different compiler (or even a different day) you might not be so lucky.
#include <iostream>
using namespace std;
class Node
{
public:
Node(int N, Node *l, Node *r);
int value; // stored value
Node *left; // left node
Node *right; // right node
};
Node::Node(int N, Node *l, Node *r){
value = N;
left = l;
right = r;
}
void insert(Node *x){
if (x == nullptr) {
Node newNode(5, nullptr, nullptr);
*x = newNode;
}
}
int main(){
Node *root;
root = nullptr;
insert(root);
cout << root->value << endl;
return 0;
}
This is the beginning of a binary search tree. In the insert function, I am trying to change a nullptr to a pointer pointing to a Node object. When I run this c++ code, I get the error: "Segmentation fault: 11". After doing some research, I believe I need to (re)allocate memory. How can I allocate the memory inside of the insert function, if possible?
First up I presume
if (x == nullptr) {
Is a typo? Didn't you mean
if (x != nullptr) {
??
If it is null you shouldn't be going ahead and dereferencing it.
How you fix the crash really depends on how you want the interface to your BST to be.
You are passing in a nullptr and attempting to assign to it. This wont work. You can't assign to nothing.
So you could do something like.
#include <iostream>
using namespace std;
class Node
{
public:
Node(int N, Node *l, Node *r);
int value; // stored value
Node *left; // left node
Node *right; // right node
};
Node::Node(int N, Node *l, Node *r){
value = N;
left = l;
right = r;
}
void insert(Node *x){
if (x != nullptr) {
Node newNode(5, nullptr, nullptr);
*x = newNode;
}
}
int main(){
Node root(2, nullptr, nullptr);
insert(&root);
cout << root.value << endl;
return 0;
}
Here you have an initial object, allocated on the stack, which you can assign to in insert. If you use this method you are wasting some time doing the initial construction of root in function main, when you are always going to go and assign over it.
If you wanted to persist with heap allocation of the Node. Pass a pointer to pointer to insert e.g.
#include <iostream>
using namespace std;
class Node
{
public:
Node(int N, Node *l = nullptr, Node *r = nullptr);
int value; // stored value
Node *left; // left node
Node *right; // right node
};
Node::Node(int N, Node *l, Node *r)
: value(N), left(l), right(r)
{}
void insert(Node **x)
{
if (x != nullptr)
{
Node* n = new Node(5);
*x = n;
}
}
int main()
{
Node *root = nullptr;
insert(&root);
if(root)
{
cout << root->value << endl;
delete root;
}
return 0;
}
This lets insert manage the allocation of the node.
Have you tried to run valgrind? It's a good idea with these kind of errors (and even if you don't see them), it sometime detects error before the symptoms gets visible (the segmentation fault might be just a consequence of an earlier error - if it's not a normal debugger will stop where the segmentation fault occurs).
It points at the fault directly:
void insert(Node *x){
if (x == nullptr) {
Node newNode(5, nullptr, nullptr);
*x = newNode; <<<--- here
}
}
So you basically check if x is null and if it is you tries to dereference and write to the pointed object? That sounds really bad. You're supposed to do the opposite - check and if it's null you do not dereference the pointer.
Hello I have a problem to returned variable from my pop function.
I will be happy if you could help me.
The function receives a pointer to the top of the list and should return the answer but I have a problem with a pointer to the list and intger the answer.
Function Code -
int pop(Node* top)
{
Node* tmp = top;
int ans = tmp->next;
top = top->next;
delete tmp;
return ans;
}
Node -
struct Node
{
int num;
Node* next;
}
Node* top = new Node;
The line int ans = tmp->next; appears to be the source of the problem. This is attempting to take the next pointer in the node, convert it to an int, and return it. What you (almost certainly) want is to retrieve the data from the node and return that, with something like int ans = tmp->num;.
Of course, that's not saying the code is perfect otherwise (e.g., it seems to lack any attempt at checking for, not to mention dealing with, errors), but at least with that change, it stands some chance of working correctly under some (ideal) circumstances.
Usually such a function throws an exception if the stack is empty or it has undefined behaviour. I used return value 0 in case when the stack is empty.
int pop( Node * &top )
{
int value = 0;
if ( top )
{
value = top->num;
Node *tmp = top;
top = top->next;
delete tmp;
}
return value;
}
There is another approach when function poo has type void that is when it returns nothing but simply removes the element on the top.
As mentioned in my comment you should split this up to two separate functions. One to get the value, and another one to pop (remove) the Node
void pop(Node*& top) { // Note the reference. You want to change the current top node.
// ^
if ( top ) {
Node *tmp = top;
top = top->next;
delete tmp;
}
}
int& top(Node* top) {
if ( top ) {
return top->num;
}
// Throw an appropriate exception if the stack is empty
throw std::out_of_range("Stack is empty.");
}
First, you are trying to delete tmp node, but top node still exist and value has to be returned as ans or top->next or in this situation top->num. Why do you initialize node tmp in the function when node tmp is a parameter? Why should node * &top be in the function parameters instead of tmp.
value = top->num doesn't fix the problem, because he wants the pointer from the top of the linked list not the random node inputed through the function parameters. To fix this problem Node * tmp should equal top and then value should be equal to tmp->num. Otherwise all other problems have been fixed.
//EDIT
Ignore everything before //edit because all that is questions about his question that I now already know. I have compiled this code and it completely worked for me.
struct Node
{
int data;
Node *next;
};
int pop(Node *head)
{
while(head->next != NULL)
{
head = head->next;
}
int value;
Node *tmp;
tmp = new Node;
value = head->data;
tmp = head;
delete tmp;
return value;
}
Compiled code link - http://ideone.com/7EgBhf
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.
I'm learning C++ language and I'm trying to write BST, but something goes wrong.
I try to add element to empty tree, root is NULL, but after adding element root is still NULL despite of the fact that addiing was successful (I saw it in debug mode, node is set as tmp). I have no idea why it happens.
struct Node
{
int data;
Node* left;
Node* right;
};
struct Tree
{
Node* root;
};
Tree createTree()
{
Tree tmp;
tmp.root = NULL;
return tmp;
}
void addToNode(Node* node, int value)
{
Node* tmp = new Node;
tmp->data = value;
tmp->left = NULL;
tmp->right = NULL;
if(node == NULL)
node = tmp;
else if(value >= node->data)
addToNode(node->right, value);
else
addToNode(node->left, value);
}
void add(Tree* tree, int value)
{
addToNode(tree->root, value);
}
int _tmain(int argc, _TCHAR* argv[])
{
Tree tree = createTree();
add(&tree, 10);
printf("%d", tree.root->data);
scanf("%*s");
return 0;
}
When you are passing your pointer into the function, you create a local version of the pointer. This local variable (node) does indeed point into the same memory that the outer pointer you were passing. However, any attempt to change this variable (not the memory it points to, but the pointer variable itself) will only change the local variable.
So your node points to the same memory location as your tree, but the node variable itself isn't equal to the tree variable, so your changes are not visible from the outer function.
It sounds complicated, sorry, but it's exacly the same thing as in this:
void foo( int a )
{
a++;
}
int main()
{
int var = 5;
foo( var );
std::cout << var;
}
Of course in this case the var will not change, it's the a that is being changed inside the function.
To fix the issue, pass a reference to the pointer instead of the pointer itself:
void addToNode(Node*& node, int value)
In the function addToNode when you assign to node, that assignment is not visible in the function calling addToNode because node is a local variable.
You should pass it as a reference instead:
void addToNode(Node*& node, int value)
{
...
}
Joachim already beat me to the answer, but I'll add this observation in anyway.
Your code leaks memory.
void addToNode(Node* node, int value)
{
Node* tmp = new Node;
tmp->data = value;
tmp->left = NULL;
tmp->right = NULL;
if(node == NULL)
node = tmp;
else if(value >= node->data)
addToNode(node->right, value);
else
addToNode(node->left, value);
}
Every call to addToNode creates a new Node instance in tmp, but if the parameter Node* node is not NULL, this new Node is not deleted and does not become accessible by the rest of the application.
There are a number of ways to avoid this. The simplest would be to check if node is NULL before creating a new instance.