This question already has answers here:
Can someone help me understand this? int *& pr [duplicate]
(3 answers)
What does *& mean in a function parameter
(5 answers)
Closed 10 years ago.
In the following code:
void insert(Node *& aNode, int x) {
if (!aNode) {
aNode = new Node(x);
aNode->next = aNode;
return;
}
Node *p = aNode;
Node *prev = NULL;
do {
prev = p;
p = p->next;
if (x <= p->data && x >= prev->data) break; // For case 1)
if ((prev->data > p->data) && (x < p->data || x > prev->data)) break; // For case 2)
} while (p != aNode); // when back to starting point, then stop. For case 3)
Node *newNode = new Node(x);
newNode->next = p;
prev->next = newNode;
}
What is Node *& aNode?
How should I use this function, I mean, which type of parameter should I pass?
I think this code is C++, not C, and Node *&aNode is a reference to a pointer to a Node, so you would pass a Node* to the function, and function would make a reference to that (so the memory location your Node* is pointing to can change).
You may find the Wikipedia article on References (C++) interesting.
A simple example:
#include <iostream>
void addOneToValue(int num) {
++num;
}
void addOneToRef(int &num) {
++num;
}
int main() {
int num = 0;
// print 0
std::cout << num << std::endl;
// print 0 again (addOneToValue() has no effect)
addOneToValue(num);
std::cout << num << std::endl;
// print 1 (addOneToRef() changes the value of num)
addOneToRef(num);
std::cout << num << std::endl;
}
#crashmstr's comment reminded me that I should say how they're different from pointers. Wikipedia does a better job that I could though:
It is not possible to refer directly to a reference object after it is defined; any occurrence of its name refers directly to the object it references.
Once a reference is created, it cannot be later made to reference another object; it cannot be reseated. This is often done with pointers.
References cannot be null, whereas pointers can; every reference refers to some object, although it may or may not be valid.
References cannot be uninitialized. Because it is impossible to reinitialize a reference, they must be initialized as soon as they are created. In particular, local and global variables must be initialized where they are defined, and references which are data members of class instances must be initialized in the initializer list of the class's constructor.
Most compilers will support a null reference without much complaint, crashing only if you try to use the reference in some way.
Related
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.
I know that pointers hold the address of a variable. And references point to the same address in the symbol table (that is, the same address of the variable, that they are assigned to).
My question is, how do reference to pointers exactly work. And when do we need them, as opposed to using pointer alone (and not using reference to pointer). It will be helpful if you could explain me the use of reference to pointer, with respect to a singly linked list.
I have the following code that deletes the head pointer of a linked list using a function:
struct Node
{
int data;
Node* next;
};
struct Node* newNode(int data)
{
Node* temp = new Node;
temp->data = data;
temp->next = nullptr;
return temp;
}
Node* deleteHead(Node* &head)
{
if (head)
{
Node* temp = head;
head = head->next;
delete temp;
}
return head;
}
int main()
{
Node* head = newNode(1);
head->next = newNode(6);
head->next->next = newNode(4);
head->next->next->next = newNode(8);
head = deleteHead(head);
Node* temp = head;
while (temp != nullptr)
{
cout << temp->data << " " << endl;
temp = temp->next;
}
return 0;
}
In the deleteHead(Node* &head) function, the function takes the argument, Node* &head. But, the code works fine, even when the argument is Node* head. for what cases do we need to pass Node* & instead of Node* in a linked list?
Following is the deleteHead(Node* &head) function above, which works the same, if we only use Node* head as the argument, instead of Node* &head -
You pass a pointer by reference for the same reason you pass a non-pointer by reference: To let the function modify its value.
Let me use a simpler example
#include <iostream>
void foo(int*& x) {
*x = 42; // change the value of the int x points to
x = nullptr; // change the value of x
}
The first line modifies the value x points to (but it does not modify x). The second line modifies x itself.
int main() {
int y = 42;
int* y_ptr = &y;
foo(y_ptr);
if (y_ptr == &y) std::cout << "cannot happen";
}
Because we set x = nullptr, y_ptr will not point to y anymore after the call.
Now if we modify foo to not take a reference we get:
#include <iostream>
void foo(int* x) {
*x = 42; // change the value of the int x points to
x = nullptr; // change the value of x
}
Again the first line modifies the int pointed to by x. However, now the second line only has an effect on x local to the function.
int main() {
int y = 42;
int* y_ptr = &y;
foo(y_ptr);
if (y_ptr == nullptr) std::cout << "cannot happen";
}
The value of y_ptr cannot change by passing it to foo, because it is passed by value.
In your code you have
Node* deleteHead(Node* &head)
{
if (head)
{
Node* temp = head;
head = head->next;
delete temp;
}
return head;
}
And when you write head = deleteNode(head) two things are happening:
the function modifies head (because it is passed by reference) to point to head->next.
the function also returns this "new" head (pointing to head->next) and that is assigned to head.
So you basically asign to headtwice. Because head is passed by reference deleteNode would do the right thing without using the return value:
deleteNode(head); // this already does modify head
...or put the other way around: If you return the "new" head (head->next) from the fucntion and assign it to head, then it does not matter if you pass the pointer by reference, because the assignment done inside the function has the same effect.
Your code is similar to
int* bar(int*& x) {
x = nullptr;
return x;
}
and then call it via
int y = 42;
int* y_ptr = &y;
y_ptr = bar(y_ptr);
where the same effect could be achieved by not using the returned value bar(y_ptr). Or the same without pointers (because pointers really make no difference here):
int moo(int& x) {
x = 0;
return x;
}
int x = 42;
x = moo(x); // same as `moo(x)`
PS: You dont need both (return the pointer and assign it already in the function), so better make the function return void.
So,
both, reference and pointer contain an address of variable/memory.
reference has semantic of variable (if you set the value, you write data into referenced memory),
pointer has semantic of pointer (if you set the value, pointered memory isn't changed) and you can set the pointer which addresses an other memory.
about deleteHead(Node* &head) - you use the reference of real variable that contains pointer of Node. The function returns new value of head in the same variable and as return value too.
References are "safe pointers" that are used with value semantics (which is really helpful in an operator overloading context), so the usage of references is very similar to the usage of pointers in C, except these points:
References hold a single value and not an array
References are non-null (which is not always desirable)
It means that you can (or, should) pass a reference whenever you want to change the original passed variable (and not a copy of it).
Saying that, the C (rought) equivalent to your function is Node* deleteHead(Node** head).
Note that since you passed a reference, the original head variable was modified and thus your function becomes a bit weird, since it both modifies head and returns its value.
You can use one of the following options:
(1) deletes head (if the list size is non-empty) and returns a pointer to the next element, this is not advisable since it will leave head as a dangling pointer. This is your original function but it does not receive a reference.
Node* deleteHead(Node* head)
{
if (head)
{
Node* temp = head; // You might want to use auto
head = head->next;
delete head;
}
return head;
}
(2) The same as your function, but returns no value (because you already modified head). This one will not work without passing a reference.
void deleteHead(Node* &head)
{
if (head)
{
Node* temp = head->next;
delete head; // deletes the content of head
head = temp;
}
}
With the reference to pointer deleteHead function, you may use head = deleteHead(head) or deleteHead(head) since head is just a reference of head in the main function, any change on head in the deleteHead function is actually applied on head variable in the main function. With the pointer version, you must use head = deleteHead(head).
This problem seems like a trivial one but I am unable to get my head around it.
I am trying to add a node by passing in a root element to a function insert. The function first checks if the current root is empty, if it is, it simply creates a new node and set it as a root. My first attempt was something like this
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node(int x) {
data = x;
}
};
void insert(Node *node, int x) {
cout << &node << "\n";
if(node == NULL) {
node = new Node(x);
}
}
int main () {
Node *aNode;
aNode = NULL;
insert(aNode, 8);
cout << aNode << "\n";
return 0;
}
This of course didn't work since I was passing pointers by value which was causing aNode to be still NULL and with some googling I came to know I need to pass pointers by reference, my second attempt was something like this
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node(int x) {
data = x;
}
};
void insert(Node **node, int x) {
if(*node == NULL) {
*node = new Node(x);
cout << *node->data << "\n"; //gives error but program runs fine without it
}
}
int main () {
Node *aNode;
aNode = NULL;
insert(&aNode, 8);
cout << aNode->data << "\n";
return 0;
}
Now that worked without the cout in insert function since the cout in main printed 8 which is what I wanted but compiler gave error request for member 'data' in '* node', which is of pointer type 'Node*' (maybe you meant to use '->' ?) while at cout of insert. I changed the insert as follows to run some tests and results were confusing
void insert(Node **node, int x) {
if(*node == NULL) {
Node *bNode = new Node(x);
cout << bNode << "\n"; // prints address of bNode
cout << *node << "\n"; // prints NULL which is correct
*node = bNode;
cout << *node << "\n"; // prints the same address as of bNode
cout << bNode->data << "\n"; // prints 8
cout << *node->data << "\n"; // gives error WTF!!!
}
}
Can somebody please explain?
#RemyLebeau comment was spot on and pointed out the exact problem. So here is the solution.
Problem Background
So I had a pointer to an object of type Node aNode and had a function insert(Node *node, int x). I wanted the function insert to check if given pointer to node doesn't point to anything then create a new node and set the reference in provided node. The expectation was that after setting the reference aNode will point to the newly created node as well. However it was a false expectation because I was passing the pointer by value instead of reference which meant node in the function insert was a different one than aNode
Buggy Solution
So the solution was to pass reference of aNode to function insert. So I changed my function call to insert, to this
insert(&aNode, 8);
And change the function definition of insert to this
void insert(Node **node, int x)
That fixed the problem, since **node was now dereferened to the address of aNode and I was able to get its value by simply dereferencing node by *node. The problem occured when I tried to access members of Node by *node->data. The reason was that * and -> are actually operators and -> has higher precedence than *. So while evaluating *node->data it was actually executing in this way *(node->data) which means compiler was actually trying to dereference node->data instead of node. The quick solution was just to access data like this (*node)->data.
Right Solution
Although through parenthesis I was able to achieve the desired behavior but the syntax was ugly. The right solution as #pm100 pointed to use reference in function definition instead of dereferencing it twice which means declare function like this
void insert(Node *&node, int x)
instead of like this
void insert(Node **node, int x)
That enabled to access node members simply like node->data instead of (*node)->data
If you are new to pointers like me do watch https://www.youtube.com/watch?v=Rxvv9krECNw
So I am working on Binary search tree function. Why do I have to add a &sign in front of the node pointer? I thought it is already a pointer and it already points to a location. I understand that if I add a node, then I need to make sure the parent node point to the new node or the parent's node will still point to NULL. But why don't I have to do that if I pass my node pointer as node*&?
bool bst::remove123(int data, node*& x)
{
if (x == NULL)
{
return false;
}
else if (x->getData() < data)
{
return remove123(data, x->right);
}
else if (x->getData() > data)
{
return remove123(data, x->left);
}
else
{
node* old = x;
if (x->left == NULL)
{
x = x->right;
}
else if (x->right == NULL)
{
x = x->left;
}
else
{
replacement(old, x->left);
}
delete old;
return true;
}
}
Thank you
node*& x is a reference to a node*. This means that when bst::remove123 modifies x to point to a different address, the code that called bst::remove123 sees the same change in the node* variable that it passed to the method. If you declared the x parameter as node *x instead, then bst::remove123 would only be modifying a copy of the variable passed in that parameter, and those changes would be lost after the method returned. While the & is used to designate a reference, this is very different to the & operator (often used with pointers) which returns the address of the variable following it.
int n = 10;
int *pn = &n; // Create a pointer to int, set it to the address of n.
int& rn = n; // Create an int reference, set it to reference the same variable as n.
*pn = 5; // Set n to 5 via a dereferenced pn. A dereferencing operator *
// is needed to indicate that we want to change the memory that
// pn points to, not the address that the pointer contains.
rn = 20; // Set n to 20 via the reference rn. Unlike with pointers,
// references do not use a dereferencing operator.
I have TWO implementations of this.
Why does this particular implementation NOT work? I have a pointer to a pointer and im changing the inside point but it doesn't retain the change in the main function
#include <iostream>
using namespace std;
struct Node {
int value = 4;
Node* next;
};
void insertFront(Node*, Node**);
int main(){
Node head;
head.value = 32;
head.next = nullptr;
Node** headptr = new Node*;
(*headptr) = new Node;
*(*headptr) = head;
(*headptr)->value = 32;//redundant, I know
(*headptr)->next = nullptr;//redundant, I know
cout << head.value << endl;
insertFront(new Node, headptr);
cout << head.value << endl;
system("pause");
return 0;
}
void insertFront(Node* newHead, Node** head2){
cout << "Inside before swap " << (*head2)->value << endl;
newHead->next = *head2;
*head2 = newHead;
cout << "Inside after swap " << (*head2)->value << endl;
}
Why does this one work? Can someone please explain IN DETAIL the pointer magic going on? I have a vague idea but im still a little bit confused. I understand that using a pointer to the head pointer allows you to change the head address globally but it's still a little bit cloudy. Can someone please clarify, what is going on with these pointers in both implementation?
#include <iostream>
using namespace std;
struct Node {
int value = 4;
Node* next;
};
void insertFront(Node*, Node**);
int main(){
Node** head = new Node*;
(*head) = new Node;
(*head)->value = 32;
(*head)->next = nullptr;
cout << (*head)->value << endl;
insertFront(new Node, head);
cout << (*head)->value << endl;
system("pause");
return 0;
}
void insertFront(Node* newHead, Node** head2){
cout << "Inside before swap " << (*head2)->value << endl;
newHead->next = *head2;
*head2 = newHead;
cout << "Inside after swap " << (*head2)->value << endl;
}
Both implementations are using double-indirection wrong, and both leak memory. You're question seems more about double-indirection than just about what works and what doesn't (whether you realize it or not). Its a C question, and though also applicable in C++, it is less so with that language because reference parameters make this somewhat easier (arguably).
I could simply say "use references to pointers" (which you could do), but that would be like you saying "why doesn't my car work?" and me answering "because this car over here will work". So I will provide a C answer (much to the dismay of my own common sense, as I can feel the furnaces firing up from the flamethrowers about to be sent my way). If I have time, I will include the C++ answer (using references), but no guarantees on that.
Pointers to pointers are no different than any other pointer type. All pointer types are types who's variables are defined to "point" to something of that type (I know, its repetitive and trivial, but bear with me here). The trivial example:
void foo(int x)
{
x = 5;
}
obviously doesn't change x on the caller side, and you seem keenly aware of that. If you want to change an in/out parameter using pointers, you need to declare the formal parameter to be a pointer-to type, dereference said-pointer parameter within the function body, and pass the address from the caller. Ie.
void foo(int *p)
{
*p = 5;
}
int main()
{
int x = 0;
foo(&x);
}
The truth is parameters are all pass-by-value in C, even pointer parameters. Yeah, read that again. You say what? Seriously. Its true. It just so happens the "value" you're passing is an address rather than the value within some variable, and in so being as such, the receiver must be something that is prepared to take, and manipulate, data via that address: a pointer.
Now. Pointers to pointers are no different. Pointers to pointers hold addresses of (wait for it...) pointers. Just like our first example, this:
struct Node
{
int data;
struct Node *next;
}
vod foo(Node* ptr)
{
Node *p = new Node();
p->data = 0;
p->next = ptr;
ptr = p;
}
int main()
{
Node *root = nullptr;
foo(root);
}
won't work. You can fix this several ways. One way is using a pointer-to-pointer (the C way). Another uses a reference to pointer (the C++ way).
First the C way, which demonstrates the whole mantra of passing something by address means declaring the parameter to be a pointer-to type (in this case a pointer to pointer type), and passing the address of the thing to modify:
void foo(Node** ptr)
{
Node *p = new Node();
p->data = 0;
p->next = *ptr;
ptr = p;
}
int main()
{
Node *root = nullptr;
foo(&root); // LOOK: passing address of our root pointer
}
Do you see how, just like in our trivial example using int and int*, we have to pass the address of the thing we're modifying to a function that takes a pointer-to-type? In this case the "type" is, itself, a pointer type.
Now, arguable, the C++ way using a reference is trivial by comparison, but IMHO it isn't as clear what is going on, only because there is literally a single character difference between the version that doesn't work and the version that does. Look at this:
vod foo(Node*& ptr) // LOOK added &
{
Node *p = new Node();
p->data = 0;
p->next = ptr;
ptr = p;
}
int main()
{
Node *root = nullptr;
foo(root);
}
Notice how everything else in this is identical to the version that does not work. Everyone has their preferences, and knowing what to look for allows me to use either method, but I can see why some have such difficulty writing and debugging what is essentially double-indirection code hidden in a reference type. Some engineers prefer to send all their out-params as pointer-to types, and I'm generally one of them.
Peeling Back Your Code
After all of that, lets peel back your code and see where things go to hell. I'll dissect the one that does not work, and hopefully you can see why neither version is honestly very good:
First your type:
struct Node
{
int value = 4;
Node* next;
};
Nothing horridly questionable here. The default value assignment in the structure definition. This will puke on non-current-day C++, so likely throw that out for now. If you want a default value, make a constructor (which you should have anyway to ensure all members are properly initialized to something):
struct Node
{
int value;
Node* next;
Node(int val = 4)
: value(val)
, next()
{}
};
Ok. Next up..
void insertFront(Node*, Node**);
You seem to want to use a pure node interface. Most people writing a linked list would do this:
void insertFront(Node** ppRoot, int value);
but we'll go with your version for now. The actual implementation of this:
void insertFront(Node* newHead, Node** head2)
{
newHead->next = *head2;
*head2 = newHead;
}
is correct. Yes it could orphan anything previously being pointed to by newHead->next, but that doesn't seem to be a concern of yours, so we go with it for now.
Finally the torrent: main().
int main()
{
Node head;
head.value = 32;
head.next = nullptr;
Node** headptr = new Node*;
(*headptr) = new Node;
*(*headptr) = head;
(*headptr)->value = 32;//redundant, I know
(*headptr)->next = nullptr;//redundant, I know
cout << head.value << endl;
insertFront(new Node, headptr);
cout << head.value << endl;
system("pause");
return 0;
}
This has multiple issues. First, your mixing dynamic nodes with non-dynamic nodes.
Node head;
head.value = 32;
head.next = nullptr;
Bad idea. This is no reasonable way calling code (in particular cleanup code that deletes each node from the list), has any clue whether something being pointed to is dynamic or not. Don't do that.. Using the constructor version of Node from above, this should simply be:
Node* head = new Node(32);
Next you're dynamically allocating a pointer; (not a Node; a pointer)
Node** headptr = new Node*;
Bad idea. there is no need to do that at all. You already have a pointer variable to your list head (its called, not-coincidentally, head). This appears all to be a setup for invoking the insertion function. To do that, everything from Node** headptr = new Node*; on down can simply be replaced with this:
insertFront(new Node(10), &head); // LOOK: passing address of head pointer
cout << head->value << endl;
The way you are using your pointers is so, so wrong.
Let's look at this code:
Node** headptr = new Node*;
(*headptr) = new Node;
*(*headptr) = head;
(*headptr)->value = 32;//redundant, I know
(*headptr)->next = nullptr;//redundant, I know
cout << head.value << endl;
insertFront(new Node, headptr);
cout << head.value << endl;
Let's first clean up this code a bit. There is no reason to allocate a Node * on the free store (using new), and then reference it through a Node **. It can and should simply be a local variable and referenced directly. To do that, we replace Node** headptr = new Node*; with simply Node *phead, and replace all instances of (*headptr) with merely phead:
Node* phead;
phead= new Node; // #2
*phead= head; // #3
phead->value = 32;//redundant, I know
phead->next = nullptr;//redundant, I know
cout << head.value << endl;
insertFront(new Node, &phead); // here we are passing the address of phead so that insertFront() can modify it
cout << head.value << endl;
Now look at this code carefully. You allocated space for a new Node on line 2, and made phead point to it. You copied the contents of head into this new Node on line 3. Then your insertFront() call modified a newly allocated node and set phead to point to that new node instead. At no point did any pointer ever point to head, and its value is never touched; when you check head.value, of course they remain the same.