C++ pointer troubles - c++

I am having trouble with the following code. I am a java developer trying to teach myself c++. Mainly my code in main() is not inserting anything to the root Node. Can anyone help me. I am sure there is something off with my pointers.
class Node{
public:
Node* left;
Node* right;
int data;
Node(int n){
data = n;
right = NULL;
left = NULL;
}
};
class BST{
Node* root;
public:
BST(){
root = NULL;
}
void insert(int e){
pinsert(root, e);
}
void pinsert(Node* sr, int e){
if(sr == NULL){
sr = new Node(e);
}
else{
if((sr->data) > e ){
pinsert(sr->left, e);
}
else{
pinsert(sr->right, e);
}
}
}
};
int main(){
BST tree;
tree.insert(6);
tree.insert(7);
}

You pass sr by value and assign to it. This won't change you root. Pass it by reference instead:
void pinsert( Node*& sr, int e)

The problem with your insert is when you begin with an empty list. When you pass a Node * to your pinsert function, the argument is passed by value, so your function ends up with a copy of the pointer. When the pointer is NULL, you change the pointer to point to your new node. Since you only have a copy of the pointer in pinsert, this only changes the copy of the pointer. When the function returns, the pointer, and the list, is unchanged.
Pass a reference to the pointer to get around this:
void pinsert(Node *&sr, int e)
Now the rest of your code doesn't need to change, and your function can change the pointer.
This problem is analogous to passing object references in java: you can change the contents of the object, by setting fields and calling methods, but you can't change the argument to a new object, or to null.

The problem is that root is always NULL, you never assign anything to it.
When you call pinsert(root, e) and then do this:
void pinsert(Node* sr, int e){
if(sr == NULL){
sr = new Node(e);
}
you send a copy of root and assign to that copy, not the root which remains NULL. You need to either send the pointer by reference (void pinsert(Node** sr, int e)) - notice 2 'stars' or void pinsert(Node*& sr, int e).

Related

Confused with Pointer Reference and Pointer

I am trying to create one singly linked list and swap two int element in sub-
function.
in function swap(int *a,int *b) , the type of parameter is int *,and it can work successfully.
in function build_sll(node *head), the singly linked list won't be created successfully.
Once I set the type of parameter to be build_sll(node *&head),and it will be created singly linked list successfully.
Confused with:
function swap(int *a,int *b) passed the address of a b, I could modify the value of a b .
function build_sll(node *head) passed only the value of pointer head. I could not modify the value of head.
why here does not pass the address of head. The only difference between them is their data type.
while set build_sll(node *head), after GDB my code, and I found that all the node object have been created successfully. In main if I visited the allocated address, it does record the node information. how to delete memory in such case.
See my code to make clear my question.
#include<iostream>
#include<cstdlib>
#include<memory.h>
using namespace std;
typedef struct node{
int num;
struct node * next;
node(int num,struct node * next)
{
this->num = num;
this->next = next;
}
}node;
void build_sll(node *&head);
void del_memory(node *&head);
void travel_sll(node *head);
void swap(int *,int *);
int main()
{
int a =10 ,b = 5;
node *head = NULL;
build_sll(head);
travel_sll(head);
del_memory(head);
swap(&a,&b);
cout << a <<" "<< b <<"\n";
exit(0);
}
void build_sll(node *&head)
{
head = new node(0,NULL);
node * tail = head;
for(int index = 1 ; index < 8;index++)
{
node * temp = new node(index,NULL);
tail -> next = temp;
tail = temp;
}
}
void travel_sll(node *head)
{
if(head)
{
head = head -> next;
while(head)
{
cout << head->num <<"\n";
head = head -> next ;
}
}
}
void del_memory(node *&head)
{
delete [] head;
}
void swap(int *a,int *b)
{
int t;
t = *a;
*a = *b;
*b = t;
}
function swap(int *a,int *b) passed the address of a b, I could modify the value of a b . function build_sll(node *head) passed only the value of pointer head. I could not modify the value of head. why here does not pass the address of head. The only difference between them is their data type.
In function swap, you want to modify/access the value of int so passing int * or int & would work. Passing arguments of type int is good for reading the value of arguments, but if you change it, only local copy is updated and not the values with which you called the function.
In function build_sll you want to change the argument of type node *. So you should pass argument of type node ** or node *& to ensure you can change the value with with it was called. Passing node * would only change the local copy (in called function) and original value in the callee function would remain unchanged.
Your options are:
Preferable node * build_sll(node *);
OK node * build_sll(node *&);
Avoid this: node * build_sll(node **); etc
If I understood the first question correctly, you're confused why you can modify the values of a and b through pointers, and can't modify the value of head through the same syntax.
If this is the case, this happens because the type of a and b is int, and int *a points to the address of the variable in memory, thus enabling you to modify in the function through dereference. You could implement the swap function like this:
void swap(int &a,int &b)
{
int t;
t = a;
a = b;
b = t;
}
and swap(a,b) would work.
As you correctly noticed, the datatype of head is different, it's node *. To modify it's value you need a pointer to the memory address, where pointer itself is stored. Thus, you need to pass a reference to the node *head to modify it. build_sll function could be implemented with dereferences too
void build_sll(node **head)
{
*head = new node(0,NULL);
node * tail = head;
for(int index = 1 ; index < 8;index++)
{
node * temp = new node(index,NULL);
tail -> next = temp;
tail = temp;
}
}
However, the syntax with double pointers is not preferred, as it leads to using dereferences constantly, so it's better to use a & syntax
function swap(int *a,int *b) passed the address of a b, I could modify the value of a b . function build_sll(node *head) passed only the value of pointer head. I could not modify the value of head. why here does not pass the address of head. The only difference between them is their data type.
Well:
swap(&a,&b);
Here you're passing the address of a, and of b - that is, you're constructing pointers which point at the values that a and b refer to, and passing those pointers as arguments to the swap function.
build_sll(head);
Here you're passing the value of head (which happens to be a pointer variable). The value passed points at something (or is null), but it doesn't point at the value that head itself refers to..
If you look inside build_s11, assuming it was declared to receive a node * parameter:
void build_sll(node *head)
{
head = new node(0,NULL);
Then you'll not that the parameter is also called head - but this is coincidental. What it does mean is that assignment is just changing the value of the parameter variable, not of the original variable. That is, head inside build_s11 is a different variable to head in the calling expression; there are two variables, and you are modifying the one inside the function, but not the one in the caller.
So why doesn't it behave the same way in swap? Well, the fundamental difference is that in build_s11 you are assigning to the parameter variable itself, whereas in swap you are assigning to the pointer target:
*a = *b;
If you wanted to see consistent behaviour, you should use consistent syntax. build_s11 could be declared as:
void build_sll(node **head);
and you would call it as:
build_sll(&head);
... and then you could change the value of of a passed-by-pointer node * value by assinging to *head:
void build_sll(node **head)
{
*head = new node(0,NULL);
node * tail = *head;
... etc. Note that it is now consistent: just as in swap you used *a and *b (rather than plain a and b), you are now using *head in build_s11 (rather than head).
Of course you can also use a reference, as you have done in your full code posting.

Getting wrong output with custom linked list implementation

I am learning list in C++ independently, and i have searched many websites about it. However, almost every approach to create a list is the same.
They usually create a struct as the node of a class. I want to create a class without using struct. So I created a class name ListNode which contains an int data and a pointer.
The main member functions of my class are AddNode and show.
Although, this program compiles successfully, it still does not work as I wish.
Here is the header file:
#ifndef LISTNODE_H_
#define LISTNODE_H_
#pragma once
class ListNode
{
private:
int data;
ListNode * next;
public:
ListNode();
ListNode(int value);
~ListNode();
void AddNode(ListNode* node,ListNode* headNode);
void show(ListNode* headNode);
};
#endif
Here is the implementation:
#include "ListNode.h"
#include<iostream>
ListNode::ListNode()
{
data = 0;
next = NULL;
}
ListNode::ListNode(int value)
{
data = value;
next = NULL;
}
ListNode::~ListNode()
{
}
void ListNode::AddNode(ListNode* node,ListNode* headNode) {
node->next = headNode;
headNode =node;
}
void ListNode::show(ListNode* headNode) {
ListNode * traversNode;
traversNode = headNode;
while (traversNode != NULL) {
std::cout << traversNode->data << std::endl;
traversNode = traversNode->next;
}
}
Main function:
#include"ListNode.h"
#include<iostream>
int main()
{
using std::cout;
using std::endl;
ListNode* head = new ListNode();
for (int i = 0;i < 3;i++) {
ListNode* Node = new ListNode(i);
head->AddNode(Node, head);
}
head->show(head);
return 0;
}
As far as I am concerned, the output should be
2
1
0
However, the output is a single zero. There must be something wrong in the AddNode and show function.
Could you please tell me what is wrong with these two functions?
When you call head->AddNode(node, head) you´re passing the memory directions which the pointers point, when the function arguments receive those directions, they are now pointing to the same directions, but those are another pointers, no the ones you declared in main. You could see it like this:
void ListNode::AddNode(ListNode* node,ListNode* headNode) {
/*when the arguments get their value it could be seen as something like:
node = Node(the one from main)
headNode = head(the one from main)*/
node->next = headNode;
/*Here you are modifying the new inserted node, no problem*/
headNode = node;
/*The problem is here, you´re modifying the memory direction
headNode points to, but the headNode argument of the function, no the one declared in main*/
}
So the pointer head in main() always points to the same first node you also declared in main().
In order to fix this you should change your code this way:
void ListNode::AddNode(ListNode* node,ListNode** headNode) {
/* second paramater now receives a pointer to apointer to a node */
node->next = *headNode;//the same as before but due to pointer syntaxis changes a bit
*headNode = node;//now you change the real head
}
And when you call it:
head->AddNode(Node, &head);//you use '&' before head
Now the real head, no the one in the function, will point to the last node you inserted.

Passing a pointer to a function

I was trying to implement BST using C++ , so i tried this:
#include <iostream>
#include <stdlib.h>
struct node
{
int value;
node* left;
node* right;
};
void insert(node *cur , int val)
{
if(!cur)
{
cur = new node;
cur->value = val;
cur->left = NULL;
cur->right = NULL;
return;
}
if(val <= cur->value)
insert(cur->left , val);
else
insert(cur->right , val);
}
using namespace std;
int main()
{
node *root = NULL;
insert(root , 20);
insert(root , 21);
cout<<(*root).value;
return 0;
}
but I have a problem, my insert() function works good, but the change in cur does not seem to reflect into the root pointer, as root remains NULL after the `insert() function calls. What is wrong here?
EDIT: Thanks for all your answers, making a pointer to a pointer seems to be to be ugly and tedious, is there any other way around, acheiving this with some other design?
Here, the root itself has been passed to insert() using pass-by-value. so, from insert(), the value of root cannot be changed. In other words, the cur is local to insert() function. Any changes made to cur itself won't impact the actual argument passed.
If you want to change the value of root from insert(), you need to pass a pointer to root from main().
To elabotare, you can change the value at the address pointed by cur from insert(). So, following the same analogy, if you change
insert(&root , 20);
void insert(node **cur , int val)
all the occurrences of cur to *cur
you should be all good to go.
If you want the function to operate on the outside pointer rather than a local copy you need to pass by reference:
void insert(node*& cur, int val)
{
// ...
}
Otherwise the function works on a copy of the pointer and the outside variable remains unchanged.
The wrong is that you pas a pointer by value, change that value but the caller does not know about it. Change it to
void insert(node **cur , int val)
{
if(!*cur)
{
*cur = new node;
(*cur)->value = val;
(*cur)->left = NULL;
(*cur)->right = NULL;
return;
}
if(val <= (*cur)->value)
insert((*cur)->left , val);
else
insert((*cur)->right , val);
}
And change function call accordingly (...exercise!)
C++ makes function calls as Call by Value. So it makes a copy of the pointer and passes that to the function. If you pass that pointer, you have access to the data the pointer is pointing to, but NOT to the pointer outside the function itself, as only the adress the pointer is pointing to is copied.
You need to pass a pointer to the pointer if you want to modify the pointer itself (that would be the C attempt) or pass by reference, of which c++ is capable of.
If you want to use the C attempt:
void insert(node ** cur , int val)
if(!(*cur))
{
(*cur) = new node;
(*cur)->value = val;
(*cur)->left = NULL;
(*cur)->right = NULL;
return;
}
or the C++ attempt (here you only have to modify the type of cur, everthing else will remain as it is):
void insert(node *& cur , int val)
If you reassign cur to a new node in insert, that does not mean that root is assigned that value (especially that root is not an address at all, but NULL).
Either pass a pointer to an empty node to insert on initialization (and update it with relevant data) or return a new node (and assign it to root in main).

Why does this binary search tree cause a stack overflow?

#include<iostream>
using namespace std;
/*main idea is to construct ordered statistic tree,which is similar of
binary search tree,width addition of one key,which shows us it's rank in given
tree,for this i introduced additional one key-rank
*/
struct node
{
int val;
node *left,*right;
int rank;
node(int t) { val=t;left=right=NULL;}
};
node *root;
void insert(node *p,int ele)
{
if(p==NULL){
p=new node(ele);
return ;
}
else if(ele<p->val)
{
insert(p->left,ele);
}
else if(ele>p->val)
{
insert(p->right,ele);
}
}
void inorder (node *p)
{
if(p!=NULL){ inorder(p->left);
cout<<p->val<<" "<<p->rank;
inorder(p->right);
}
}
int count_node(node *t)
{
int sum=0;
if(t==NULL) return 0;
else sum=1;
if(t->left) sum+=count_node(t->left);
if(t->right) sum+=count_node(t->right);
return sum;
}
int main()
{
root=NULL;
root->rank=0;
insert(root,26);
insert(root,17);
insert(root,41);
insert(root,14);
insert(root,30);
insert(root,21);
insert(root,47);
insert(root,10);
insert(root,16);
insert(root,28);
insert(root,38);
insert(root,35);
insert(root,39);
insert(root,19);
insert(root,21);
insert(root,20);
insert(root,7);
insert(root,12);
insert(root,3);
inorder(root);
return 0;
}
This code causes an overflow, but I do not understand why, because I have constructed the constructor properly.
The problem is:
root=NULL;
root->rank=0;
this cause undefined behavior because you dereference a NULL pointer. Anything can happen.
Also:
void insert(node *p,int ele)
{
if(p==NULL){
p=new node(ele);
return ;
}
//...
}
This doesn't modify the original pointer. If you call insert on a NULL pointer, it will be NULL when the function returns. You need to pass it by reference:
void insert(node *& p,int ele)
In addition to what Luchian said, you also have this problem:
void insert(node *p,int ele)
{
if(p==NULL){
p=new node(ele);
return ;
}
....
where the pointer p is passed by value. When you say p=... you are changing a copy of the pointer that is only visible to the function. You might want a reference to the pointer you're changing:
void insert(node *&p, int ele){ ... }
You have a very big issue the first two lines of your main function:
root=NULL;
root->rank=0;
If you look at your own definition above, the root is defined as a node pointer, that is it does not reserve any space for an actual node.
If you do not reserve the space yourself, than you are trying to write through uninitialized memory. What's more, you explicitly say that the root points to nothing, that is NULL. And in the very next line, you try to access it's member called rank.
You should try replacing the line:
root = NULL;
With
root = new node(0);
or something similar that actually reserves the space and constructs a node.
Alternatively, you could try assinging the rank to the root in the very end, since you insert function actually constructs the root if it is not present. edit as Luchian said, you only try to construct the root in the insert method. If you re-write the insert method in the way he has suggested, than it might all work if you just move the root->rank=0; line to the end of the insertion process.
root=NULL;
root->rank=0;
This could be the problem, you should not deference a NULL object.

Passing a object by reference in c++

This is a noobie question, but I'm not sure how to pass by reference in C++. I have the following class which sets up a Node and a few functions.
class Node
{
public:
Node *next;
int data;
Node(int dat)
{
next = NULL;
data = dat;
}
Node* getNext()
{ return next; }
void setNext(Node *n)
{ next = n;}
void reverse(Node *root)
{
Node *previous = NULL;
while(root != NULL)
{
Node *next = root->getNext();
root->setNext(previous);
previous = root;
root = next;
}
root = previous;
}
};
Now, the purpose of my little class is to create a singularly linked list and have the ability to reverse it. And it seems to work fine, if I return the node named 'previous' at the end of reverse.
But look at my main function:
int main()
{
Node *root = new Node(1);
Node *num2 = new Node(2);
Node *num3 = new Node(3);
Node *num4 = new Node(4);
root->setNext(num2);
num2->setNext(num3);
num3->setNext(num4);
root->printList();
root->reverse(root);
root->printList();
return 0;
}
printList() was omitted for sake of space, but it just prints a list given a node. The problem is, when root->reverse(root) is called, root doesn't actually end up pointing to 'previous'.
The output would be this:
1
2
3
4
// the value of previous from the reverse function is 4
1
I really don't understand the output. Anyone care to explain what's happening? (Why isn't the list reversed even though if I did something like this root = root->reverse(root) where reverse returns previous, it would) why is it that root now only points to itself? I'm new to c++ and appreciate your help!
C++ has support for reference semantics. Therefore, for a given function:
void foo(Bar& bar);
To pass by reference you do:
int main() {
Bar whatsit;
foo(whatsit);
return 0;
}
That's it!
This is commonly confused with passing a pointer, where for a function such as:
void foo(Bar* bar);
You would do:
int main() {
Bar whatisit;
foo(&whatsit);
return 0;
}
The difference is mostly a matter of semantics:
- A reference is always valid. There is no reason to check for a NULL pointer.
- A pointer could be NULL, and as such, should be checked.
It is, however, possible for a reference to refer to a NULL pointer, however, if the programmer decides to be evil and abuse reference semantics, but the principle remains.
You aren't passing by reference. You are passing a copy of the pointer. This copy still points to the same node, but it is still just a copy with local scope. Basically it is another pointer pointing to the node that the pointer in main is pointing to (ha!). At the end of your function, your assignment is assigning previous to this pointer copy, and then the function ends and the copy goes out of scope. Your pointer in main remains unchanged.
The reason returning/assigning the pointer worked is that this copy which has been set to what you want is returned and assigned to your pointer in main.
You can fix this in a multitude of ways. Pass a reference to your pointer (ugly imo), use references, or return root and do an assignment.
To pass a pointer by reference you can declare reverse as:
void reverse(Node*& root) {
// ...
}