Unexpected Pointer behavior - c++

I am confused with what exactly goes wrong in the following demo code. I expected that the next would keep pointing to the next element in the chain until reached end. However, I get EXE_BAD_ADDESS error. I guess I am missing something in the recursive pointer assignment.
template <class T>
struct Node {
Node *left, *right, *parent;
int height;
T value;
// constructor
Node(T val)
: value(val){
height = 0;
left = right = NULL;
}
};
template <class T>
void assignToNext(Node<T> *n, Node<T> *next){
// base case
if (n == NULL)
return;
// else assign to this node and check for next
next = n;
assignToNext(n->left, next);
}
And then in the main:
Node<int> a(1);
a.left = new Node<int>(2);
a.left->left = new Node<int>(3);
a.left->left->left = new Node<int>(4);
a.left->left->left->left = new Node<int>(5);
Node<int> *last = NULL;
assignToNext(&a, last);
std::cout << last->value << std::endl; // I get EXE_BAD_ADDRESS error
Thanks in advance,
Nikhil

void assignToNext(Node<T> *n, Node<T> *next){
-->
void assignToNext(Node<T> *n, Node<T> *&next){ // note the &
Otherwise the original pointer isn't updated and stays NULL.

assignToNext(&a, last);
This code can't modify local variable Node<int> *last's value. You just passed NULL to parameter Node<T> *next. So last's value is still NULL and you got error. If you want modify pointer's value, use double pointer.
Like,
void assignToNext(Node<T> *n, Node<T> **next);
assignToNext(&a, &last);

Related

Why is my class node overwriting itself instead of making a new node object

can someone run this code and tell me why the node in insert keeps overwriting?
#ifndef LinkedList_hpp
#define LinkedList_hpp
#include <stdio.h>
#include <utility>
template<class T>class LinkedList{
public:
LinkedList(){
head = nullptr;
tail = nullptr;
size = 0;
}
//void insert(T val);
class Node{
public:
Node* next;
T* value;
Node* prev;
Node(T* value){
this->value = value;
}
Node(){
}
Node(T* value,Node* prev, Node* next){
this->value = value;
this->next = next;
this->prev = prev;
}
Node* operator=(const Node& node){
this->value = node.value;
this->prev = node.prev;
this->next = node.next;
return *this;
}
};
public:
Node* head;
Node* tail;
int size;
void insert(T val){
at this line, if the previous head was 10, the current val, 40, overwrites the old head value and inserts a new node with val 40
Node* temp = new Node(&val);
if(head==nullptr){
head = temp;
tail = temp;
}else{
temp->next = head;
head->prev = temp;
head = temp;
}
size++;
}
#endif
#include <iostream>
#include "LinkedList.hpp"
int main(int argc, const char * argv[]) {
// LinkedList<int> t;
int h = 7;
int j = 10;
int k = 40;
LinkedList<int>* list1 = new LinkedList<int>();
list1->insert(h);
list1->insert(j);
list1->insert(k);
return 0;
}
every time insert is called and a new node is constructed, it overwrites the old value and everything becomes the current Val
void insert(T val){
val is a parameter to this function. This object, this val, only exists until this function returns. At which point it gets destroyed, like everything else declared in non-static scope inside the function. That's how C++ works. Once insert() returns, this val no more. It ceases to exist. It goes to meet its maker. It becomes an ex-object, that no longer exist and is completely in the past.
Your insert() function does the following:
Node* temp = new Node(&val);
You're passing a pointer to this val parameter to Node's constructor, and Node then saves the pointer to a parameter to insert(), as its own class member.
That's great, but as soon as insert() returns, the saved pointer in the new-ed Node becomes a pointer to a destroyed object, and dereferencing this pointer becomes undefined behavior.
You are then, later, attempting to dereference the original pointer, which is no longer pointing to a valid object.
This explains the observed undefined behavior in your code.
The bottom line is that your classes and templates's design is fundamentally flawed. There is no apparent purpose for Node to use a pointer. Node should simply store T as its own class member, as the value, instead of value being a pointer to some other T which exists somewhere, and can get destroyed at any time, which is not under Node's control.
Another problem in the shown code is that two ofNode's constructor fail to initialize the next and prev pointers to NULL. This will also lead to undefined behavior.
void insert(T val)
takes its arguments by value, so val is a local copy rather than the original.
Node* temp = new Node(&val);
stores a pointer to this local copy. The copy goes out of scope, so what you're looking at after insert exits is a ghost existing in memory that is no longer valid. In this case the ghost appears to always hold the last value set.
Solution:
Smart way: Store Node::value directly instead of as a pointer that you need to keep alive along with the node. Much less memory management this way.
T* value;
becomes
T value;
and
Node(T* value){
this->value = value;
}
becomes
Node(T value){
this->value = value;
}
The other uses of value must be updated accordingly. In general, new is such a headache that it should be used sparingly.
Stupid way: Pass by reference
void insert(T &val)
so that the pointer points at the longer lived original.

How do I write this node counter?

Hi I am trying to create a function that counts the number of nodes in the binary tree. I am getting an error that says mismatch of functions. I have gotten other errors and can't seem to get it to work. I know the idea just am having a hard time figuring this one out. Thank You! Edit - My error is mismatch of parameter list.
template<class T>
class BinaryTree
{
private:
struct TreeNode
{
T value;
TreeNode *left;
TreeNode *right;
};
TreeNode *root;
void insert(TreeNode *&, TreeNode *&);
void NodeNumber(TreeNode *&, int&); //My NodeNumber declaration
public:
BinaryTree()
{
root = nullptr;
}
void insertNode(T);
int NodeNum();
};
template <class T>
void BinaryTree<T>::insertNode(T item)
{
TreeNode *newNode = nullptr;
newNode = new TreeNode;
newNode->value = item;
newNode->left = newNode->right = nullptr;
insert(root, newNode);
}
template <class T>
void BinaryTree<T>::NodeNumber(TreeNode *&root, int&)
{
if (root = nullptr)
return;
else
root->right;
root->left;
count = count + 2;
}
template <class T>
int BinaryTree<T>::NodeNum()
{
int count = 0;
NodeNumber(root,count);
return count;
}
You have numerous mis-designs and errors in this class. I will focus on the outright errors. I don't know which of those mis-designs has been mandated by your professor and which are yours.
BinaryTree<T>::NodeNumber, as it is currently written, will crash every time. To figure out why, think carefully about exactly what this line does:
if (root = nullptr)
How does that line differ from these two?
root = nullptr;
if (root)
Secondly, what do the lines:
root->left;
and:
root->right;
do exactly? Why do you think they do that?
Lastly, when exactly should you be adding to count and why? Where is that true?
You didn't give a name to the 2nd parameter in this function, which I assume should be count.
// original
template <class T>
void BinaryTree<T>::NodeNumber(TreeNode *&root, int&)
{
if (root = nullptr)
return;
else
root->right;
root->left;
count = count + 2;
}
A few comments:
If you have a non-null root pointer, you want to visit both left and right child trees. It looks weird that right is in the "else" case, while left is not. I suggest getting rid of the "else" and just return if root is null, and otherwise process both left and right after the if.
You are not testing if the root pointer is null; you are setting it to null.
There is no reason to pass a reference to the root pointer
Your statements like "root->right" do not do anything. You want to recurse down the left child and recurse down the right child, so need to call NodeNumber again and pass your children as the root of these recursive calls, and also pass "count" down too.
Why do you increment by 2? Each node should only count as 1. (Its children will account for themselves as you recurse down them, so only add one for the node itself.)
I prefer to return the count rather than use an "out" parameter
Therefore, consider something like this:
template <class T>
int BinaryTree<T>::NodeNumber(TreeNode *root)
{
if (root == nullptr)
return 0;
int count = 1;
count += NodeNumber(root->right);
count += NodeNumber(root->left);
return count;
}
And of course, adjust the declaration and calls accordingly.

How to build a C++ Stack structure

struct Node{
int value;
Node *next;
Node(int val) :value(val), next(nullptr){}
};
class Stack
{
public:
void push(int val);
int pop();
bool is_empty(){ return first == nullptr; }
private:
Node *first = nullptr;
};
int Stack::pop(){
int ret = first->value;
first = first->next;
return ret;
}
void Stack::push(int i){
if (is_empty()){
first = &Node(i);
return;
}
Node oldFirst = *first;
first = &Node(i);
first->next = &oldFirst;
}
Here is how I wrote the code, however, there is a problem that when I finished push() the pointer of first isn't point to the right object. I'm wondering how I can solve that problem.
The expression &Node(i) creates a temporary object and give you a pointer to it. And then the temporary object is immediately destructed, leaving you with a pointer to a non-existing object.
You need to use new to allocate a new object.
You have a similar problem with &oldFirst, which give you a pointer to a local variable, which will be destructed once the function returns. You need to use a pointer variable.

C++ pointers not working?

I have a problem with working with c++ pointers. I'm trying to code a splay tree by using a Node struct and Tree struct. However, upon testing, I have encountered a problem. The portion of my code that's not working is below:
struct Node {
Node* l, *r, *p;
int v;
Node() {}
Node(int _v, Node* _p) : v(_v), p(_p) {}
};
struct Tree {
Node* root;
Tree() : root(0) {}
//...
void insert(int k) {
if (!root) {
root = new Node(k, 0);
return;
}
Node* cur = new Node();
cur->v = root->v;
while (1) {
int x = cur->v;
cout << x << endl;
return;
if (k <= x) {
//cout << x << endl;
//return;
if (!cur->l) {
cur->l = new Node(k, cur);
//splay(cur->l);
return;
} else cur = cur->l;
} else {
if (!cur->r) {
cur->r = new Node(k, cur);
//splay(cur->r);
return;
} else cur = cur->r;
}
}
}
//...
};
int main() {
Tree t = Tree();
t.insert(1);
t.insert(5);
return 0;
}
First, I inserted a node with value 1 in the tree; since there was no root, the tree assigned its root as a new node with value 1. Then, when I inserted 5 into the tree, something weird happened. If you leave the code like it is (keeping the first cout), then it will print out 1 for x. However, if you comment out the first cout and return and uncomment the second cout and return, you'll find that it prints out a random garbage number for x, even though no modifications were made. Can somebody tell me what's wrong?
C++ does not initialize class members automatically.
struct Node {
Node* l, *r, *p;
int v;
Node() {}
Node(int _v, Node* _p) : v(_v), p(_p) {}
};
When you create a new node in your code C++ allocates a piece of memory for the Node but it will not clear it. So the values of l, r & p will be whatever was there.
In your algorithm the tests: if (!cur->r) & (!cur->l) currently fail because there is uninitialized garbage in the nodes and not NULL.
As a result when you try to insert the second node the algorithm thinks that there is a valid node to the right of root. And tries to read the memory there and the value there which is the junk x you see. Depending on the value of the junk it may also crash for some people running the code :)
Also I'm 99.9% certain that Node* cur should be a pointer to a Node in the tree and not a new node so:
Node* cur = new Node(); cur->v = root->v; is wrong and should be Node* cur = root;
Proper Initialization -
In c++11 you can do:
struct Node {
Node* l = nullptr;
Node *r = nullptr;
Node *p = nullptr;
int v = 0;
Node() {}
Node(int _v, Node* _p) : v(_v), p(_p) {}
};
Otherwise
struct Node {
Node* l;
Node *r;
Node *p;
int v;
Node() : l(NULL), r(NULL), p(NULL), v(0){}
Node(int _v, Node* _p) : l(NULL), r(NULL), p(_p), v(_v) {}
};
You should initialize members of a class in the same order they were defined.
Now there are a lot of other things that are problematic in the code:
Tree seems to allocate lots of nodes but does not release any memory. (easiest to just use unique_ptr for l and r and root Node)
Is tree the owner of subnodes? Or should it be Node owning and allocating left and right? (goes away if you use std::unique_ptr for left and right)
You are not initializing the members in the order they are defined. This can cause all kind of errors. (since the compiler reorders initialization without telling you)
Node and Tree handle raw pointers but do not define a proper operator=, copy ctor (or delete them) (goes away if you use unique_ptr)
Tree is missing a dtor to clean allocated memory (goes away if you use unique_ptr)

Pointers - passing ptr to a ptr or passing address of a ptr

I am trying to remove the left child (10) of a sample binary search tree using two methods:
Method1: By passing pointer to a pointer to the current node.
Method2: By passing address of the pointer to the current node. This does not removes the node, but calling delete corrupts the pointer arrangement, causing a crash while printing the nodes.
The tree looks like this and I am trying to delete 10 and replace it with 5
20
|
10--|---30
|
5---|
I have some understanding of pointers. But still, I am not clear with this behavior of pointers.
#include <iostream>
class Node
{
public:
Node(int key) : leftChild(0), rightChild(0), m_key (key){}
~Node(){}
Node *leftChild;
Node *rightChild;
int m_key;
};
Node* build1234(int, int, int, int);
void print(Node *);
void print1234(Node *);
void removeLeft(Node **nodePtr)
{
Node *oldPtr = *nodePtr;
if(*nodePtr)
{
*nodePtr = (*nodePtr)->leftChild;
delete oldPtr;
}
}
int main()
{
Node *demo1 = build1234(10, 20, 30, 5);
Node *demo2 = build1234(10, 20, 30, 5);
print1234(demo1);
print1234(demo2);
//Method1 - 10 is correctly removed with 5
Node **nodePtr = &demo1;
nodePtr = &(*nodePtr)->leftChild;
removeLeft(nodePtr);
print1234(demo1);
//Method2 - 10 is not removed
Node *node = demo2;
node = node->leftChild;
removeLeft(&node);
print1234(demo2);
return 0;
}
Node* build1234(int B, int A, int C, int D)
{
Node *root = new Node(A);
root->leftChild = new Node(B);
root->rightChild = new Node(C);
root->leftChild->leftChild = new Node(D);
return root;
}
void print(Node *node)
{
if(node)
{
print(node->leftChild);
std::cout << "[" << node->m_key << "]";
print(node->rightChild);
}
}
void print1234(Node *node)
{
std::cout << std::endl;
print(node);
}
Note: This question is not about BST, but pointers. If you see the two calls to removeLeft(nodePtr) and the removeLeft(&node) in the main() function.
How are these two different?
Why the second method fails to achieve the desired result?
In the first case, you are passing an address of a pointer that exists in the tree, so you are modifying the contents of the tree directly.
In the second case, you are passing an address of a variable that is local to main() instead. The tree is not modified, and deleting from the address is accessing stack memory, which is why it crashes
You're overthinking it. All you need is a function removeLeft(Node*) that unhooks the left node and deletes it, recursively:
void removeLeft(Node * p)
{
removeBoth(p->leftChild); // recurse, OK if null
delete p->leftChild; // OK if already null
p->leftChild = 0; // necessary to make recursion terminate
}
void removeBoth(Node * p)
{
if (!p) return;
removeLeft(p);
removeRight(p);
}
If you are bad with pointers consider using smart pointers.
When using smart pointers use shared_ptr<Node> instead of Node * and make_shared(new Node); instead of new Node and remove all deletes. now you can handle pointers without caring for deletes and memory corruption.