C++ - Setting a node to NULL doesn't work [duplicate] - c++

This question already has answers here:
Function does not change passed pointer C++
(4 answers)
Closed 5 years ago.
#include <iostream>
using namespace std;
struct node{
int val;
node* left, *right;
};
void _delete(node *root)
{
root = NULL;
}
void change(node *root)
{
root->val = 6;
}
int main()
{
node * root = new node;
root->val = 5;
change(root);
_delete(root);
cout<<root->val<<endl;
return 0;
}
The output of the above program is 6. It seems as if the _delete function has no effect on the root node but change function has an effect on the root node. It is almost as if delete treats the argument passed as a local variable but change treats the argument as a global variable. Is there anything that I am missing out or is this normal? If it is normal, please explain.

Since you pass the pointer by value in your _delete function, the value in the caller is not changed.
The quickest fix is to write
void _delete(node*& root)
i.e. pass the pointer by reference: note the &; you might also want to call delete on the pointer there too else you leak memory. The function change works as it is since you are using the pointer to member operator ->.

Related

Linked List not properly being deleted when passed as a parameter in C++ [duplicate]

This question already has answers here:
What's the difference between passing by reference vs. passing by value?
(18 answers)
Closed 3 days ago.
I have a method called deleteList that takes a head of a single linked list as an input and it removes all the nodes.
In the method deleteList I can verify that all the nodes are deleted, but when the execution returns back to the main, myList is not empty. So in the subsequent call to LengthOfList, the code fails with an exception.
[Please note that I am unable to change the signature of deleteList]
Here is the code:
#include <iostream>
using namespace std;
typedef struct CodeNode* List;
struct CodeNode
{
char data;
List next;
CodeNode(char new_data, List new_next)
: data(new_data), next(new_next) {
}
};
int LengthOfList(List head)
{
int len = 0;
for (List ptr = head; ptr != nullptr; ptr = ptr->next) {
len++;
}
return len;
}
void deleteList(List head)
{
List prev = head;
while (head)
{
head = head->next;
delete(prev);
prev = head;
}
// I can verify that head is null and all the nodes have been deleted
}
int main(void)
{
List temp1 = new CodeNode('3', nullptr);
List temp2 = new CodeNode('2', temp1);
List myList = new CodeNode('1', temp2);
cout << "Before " << LengthOfList(myList);
deleteList(myList);
cout << "After " << LengthOfList(myList); // CODE FAILS HERE because myList is pointing to a bad memory address (it SHOULD be NULL)
}
Pass by reference
void deleteList(List& head)
The & makes all the difference. If you want a function to alter a variable in the calling function then you pass by reference.
All your code is doing is modifying the variable head in the function deleteList which is not the same variable as head in main. By using a reference you make head in deleteList an alias for the variable used in the calling function, and therefore changes to it effect that variable.
Another option is to return the changed variable, so in main
myList = deleteList(myList);
and in deleteList
List deleteList(List head)
{
...
return head; // return modified head
}
Both approaches work, it's a style choice which you choose.
I just noticed your comment, 'please note I'm unable to change the signature of deleteList'. Then I'm afraid your code is guaranteed to fail. There is no solution given the peculiar constraints you have been given.
It's amazing how often we see this here, newbie struggling with some problem, but unable to use any of the solutions that any normal programmer would use because of artificial constraints placed on the task by their teacher. In some cases, like yours, these constraints are so severe that there is literally no solution to the task that they've been given. I suggest you ask your teacher for some advice.
In short, your solution is doing exactly this.
#include <iostream>
typedef struct CodeNode* List;
struct CodeNode {
char data;
List next;
CodeNode(char new_data, List new_next): data(new_data), next(new_next) {}
};
int main() {
List myList = new CodeNode('1', nullptr);
cout<<myList->data<<endl;
delete(myList);
cout<<myList->data<<endl;
return 0;
}
// given error
// AddressSanitizer: heap-use-after-free on address
// 0x602000000010 at pc 0x000000342fd6 bp 0x7fffcb6b5110 sp 0x7fffcb6b5108
And, accessing myList after deletion is supposed to be undefined as this is an example of heap use after free which occurs when a program continues to use a pointer after it has been freed.
Useful Links
ASAN heap use after free
Use after free error?
Solution
john's answer has already given the answer on how passing by reference can actually update the underlying variable and produce the desired effect.
I just wanted to supplement the reason for your understanding.

Passing an object by reference (C++) [duplicate]

This question already has answers here:
How to pass a pointer variable as a reference parameter?
(2 answers)
Reason to Pass a Pointer by Reference in C++?
(7 answers)
C++ passing pointer reference
(3 answers)
Closed 8 months ago.
I want a method that creates a binary tree from an array and returns nothing. So I would have to work by reference but I am having some troubles with the proper syntax to use.
I have obviously tried to search before posting this question, I have seen similar posts but no answer were truly helpfull.
Here what i have done so far :
My Class :
class Node
{
private:
int data;
Node* left;
Node* right;
public:
[...]
void make_tree(Node* node, int values[], int size);
};
The method :
// Every operations are done a copy of node, I want them to be done on the original object
void Node::make_tree(Node* node, int values[], int size)
{
if (size <= 0)
{
return;
}
else
{
if (!node)
{
node = new Node(values[size]);
}
else if (!node->has_data())
{
node->set_data(values[size]);
}
// recursive call
make_tree(node->left, values, size - 1);
make_tree(node->right, values, size - 1);
}
}
The call :
int main()
{
int tab[] = { 5,3,4,9,7,6 };
Node* root = new Node();
/* I want "root" to be passed by reference so every modifications
are done on the original object and not a copy who will be destroyed
at the end of the method scope. */
root->make_tree(root, tab, 6);
root->print_tree(); // there is nothing more in root
}
Since I am already passing a pointer to the object "root", I am confused on how I could do it.
Thank you.
PS: I am aware that my recursive call does not do what I described it should do. That is a problem for an other time.
PPS : first post btw, so if you see something I did wrong, please, tell me.
void Node::make_tree(Node* node, int values[], int size);
Node pointer cannot be modified inside the function, as you pass it by value (only the copy is modified).
You can use a reference, as suggested in comments :
void Node::make_tree(Node* &node, int values[], int size);
Or you can also use a pointer to a pointer void Node::make_tree(Node** node, int values[], int size); but there will be more work to modify your code.

Value in a portion of memory is changed due to declaration [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
How to initialize a local struct object in C++ (cannot create a new object as a local variable)?
(1 answer)
Closed 1 year ago.
My background: I didn't read too much about memory allocation through stack and heap, but stack allocation it's 'casually' said to be faster. I think that when you create an object with new keyword you are using somehow heap allocation, I don't expect it when I just do
A a;.
Problem:
I'm trying to implement a linked list in C++ with the possibility to insert an element in any position nth. For this I implemented a flag, that would help control the position, but when i use this declaration the data in my head pointer changes. I reduced the original code, but the following resumes the problem:
#include <iostream>
struct node {
int data;
node* next;
node* prev;
node(int dat) { data = dat; next = nullptr; prev = nullptr; }
};
struct Linked_list {
node* head;
node* tail;
Linked_list(int data) {
node init(data);
head = &init;
tail = &init;
}
void insert() {
node* iterator = head;
std::cout << head->data;
int flag = 0;
//prints -858993460 if we declare the flag.
//If flag declaration doesn't exist prints 12;
}
};
int main()
{
Linked_list A(12);
A.insert();
}
Why is this happening? I really need to implement it dinamically?

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).

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) {
// ...
}