issues in understanding pointers - c++

The following codes are from the book Programming Interviews Exposed
I am having problem to understand the concept of pointers. Why can't we use the code no. 1.
Code no. 1
bool insertInFront( IntElement *head, int data )
{
IntElement *newElem = new IntElement;
if( !newElem ) return false;
newElem->data = data;
head = newElem; // Incorrect!
return true;
}
Code no. 2
bool insertInFront( IntElement **head, int data )
{
IntElement *newElem = new IntElement;
if( !newElem ) return false;
newElen->data = data;
*head = newElem; // Correctly updates head
return true;
}

In code 1, you are assigning the pointer location of newElem to the local copy of head. When the function returns, head is destroyed, and you will have a memory leak (you lose the pointer to newElem, leaving you with no way to delete it.) You've only changed the function's local copy of the pointer, the caller's copy is unaffected.
In code 2, head is a pointer-to-a-pointer. You don't have just a pointer, you actually have a pointer to the caller's pointer. This allows you to alter the caller's pointer, storing the pointer to newElem When the function returns, head is destroyed, but it's only the pointer-to-a-pointer. The original pointer is intact in the caller's scope.

Say you are calling function 1 as:
insertInFront(H, data);
Upon calling of a function, the computer makes duplication of arguments, then release them when the function returns. So in code No.1, head=newElem assigned the address of newElem to head(which is a duplicate of H), then released head, and the address of newElem is lost forever.
In code No.2, however, the function should be called as:
insertInFront(&H, data);
This means the ADDRESS of H is duplicated to head, and the address of newElem is assigned to *head, i.e. where head is pointing, which results in H. In this way you get the address of newElem after the function returns.

The concept of pointers are very complicated. Basically the way you need to think about pointers are that they are 'values' themselves. so:
*head = some_memory_address_that_points_to_head;
could be thought of as:
int im_a_pointer_to_head = some_memory_address_value_to_head;
So if we apply this same concept to your first function:
bool insertInFront(int im_a_pointer_to_head, int data)...
You are essentially passing in a copy of the value of your head pointer, changing it within the function only changes the temporary copy made for this function and does not actually change where the original pointer is pointing to.
The second function solves this because you are actually passing in the copy of the pointer that is pointing to the pointer that is pointing to the head (try saying that 3 times fast!). In this case, you are not changing the copied value, but instead are changing where the actual pointer is pointing to.

To change the value of anything passed via a function argument (and have that change persisted) outside of the function call, you MUST have the memory address of whatever it is whose value you want to change. This is another way of saying that you must "pass by reference" instead of "pass by value" -- otherwise pass by value will cause the function to just alter the COPY.

Related

Clarification on passing a pointer by reference

This is kind of silly, but I can't really explain why this is happening. As an exercise, I wanted to reverse a singly-linkedlist and I did this by defining the method:
class solution {
void reverseLinkedList(Node*& head) {
Node* curr = head;
Node* prev = NULL;
while (curr != NULL) {
Node* _next = curr->next;
curr->next = prev;
prev = curr;
curr = _next;
}
head = prev;
}
In my main function, I make the call
solution s;
s.reverseLinkedList(head);
Node* iterator = head;
while (iterator != NULL) {
std::cout<<iterator->data<<std::endl;
iterator = iterator->next;
}
Where I previously defined my head pointer to some linkedlist. The while loop is for printing my linkedlist and the function does it job. This only worked after I passed the head node by reference; I initially tried to pass Node* head instead of Node*& head in the beginning, and it only printed the first element of my linkedlist (and without reversing it). For example, if I didn't pass by reference for a list 1->2->3, I would print out just 1.
I thought passing a pointer would be enough? Why did I get such weird behaviour without passing by reference>
Local variables in C++ (stored in the stack) have block scope, i.e., they run out of scope after the block in which they are defined is executed.
When you are passing in a pointer to the function, a copy of the pointer is created and that copy is what is passed. Once the function is executed, the variables in the function workspace run out of scope. Any non-static Automatic variables created within the function are destroyed.
When you pass in by reference you don't pass in a copy of the variable but you pass in the actual variable, thereby any changes made to the variable are reflected on the actual variable passed into the function(by reference).
I would like to point out that the pointer to the next node is stored in memory and has an address to the location it is stored. So if you want to not pass in by reference you can do this:
Use a pointer to the pointer, which points to the memory location at which pointer variable(address) to the next node is stored
Pass in this to the function (not by reference)
Dereference the pointer and store the new address you want to point to.
I know this is a bit confusing, but look into this small piece of code that adds a node to a linked list.
void addNode(Node** head, int newData)
{
Node* newNode = new Node;
newNode->data = newData; // Can also be done using (*newNode).data
newNode->next = *head;
*head = newNode;
}
I thought passing a pointer would be enough?
void reverseLinkedList(Node* head) // pass pointer by value
// head is a copy here
Passing a pointer by value creates a copy to be used inside the function.
Any changes made to that pointer inside the function is only reflected in the function scope. Since those changes are only reflected in the pointer's copy and not in the original pointer.
Once the pointer (copy) goes out of scope, those changes are "discarded" due to end of life.
Thus, you need a reference.
void reverseLinkedList(Node&* head) // changes made in head will be
// reflected in original head pointer
When you pass a pointer regularly (IE by value) it creates a copy of the pointer. Any changes made to this pointer do not effect the original pointer.
Passing a pointer by reference is sending a reference to that pointer (very similar to passing a pointer to a pointer) and therefor any changes made to that pointer are effecting its 'original' state.
For example:
//WRONG does not modify the original pointer, causes memory-leak.
void init(Object* ptr, int sz) {
ptr = new T[sz];
}
vs
//Correct original pointer is a set to a new block of memory
void init(Object*& ptr, int sz) {
ptr = new T[sz];
}
In
void reverseLinkedList(Node* head)
The pointer is passed by value.
This sounds silly, it's a freaking pointer, right? Kind-of the definition of pass by reference. Well, the Node that's being pointed at is passed by reference. The pointer itself, head is just another variable that happens to contain the address of some other variable, and it's not being passed by reference.
So head contains a copy of the Node pointer used to call reverseLinkedList, and as with all parameters passed by value, any modifications to the copy, pointing head somewhere else, are not represented in the calling function.

How to null struct when passed to function?

I want to NULL the head structure in case the head->next is NULL.
However it doesn't work when I pass it into a function to null it.
void remove(struct node* head)
{
int val;
cout << "Enter a value to delete: ";
cin >> val;
if (head->next == NULL)
if (head->data == val)
head = NULL;
}
Though it works fine when not passed to the function, but done directly in the main function.
Where do I go wrong?
The pointer passed as an argument to remove is being copied into the function. The head inside the function is a copy of that pointer. You set that copy to NULL and the one outside is left unchanged. You can simply take the pointer by reference:
void remove(struct node*& head)
{
// ...
}
Note the ampersand in the type of head. This means it's a "reference to pointer to node" and lets you reference precisely the object that is passed, rather than a copy of it.
The problem is that you are passing the pointer which lets you modify the node it points to, but you can't modify the pointer itself because the pointer itself is passed by value. So you can't do this in your remove function:
node = NULL;
A solution that people have given you is to pass it as a reference to the pointer, as in node *&head and this works perfectly fine. However I believe you'd like to know that the general convention for this sort of thing (modifying a pointer itself) is by passing a double pointer (i.e. a pointer to the pointer to node):
void remove(node **head) { ... }
Then in main you pass it the address of the pointer:
node *theHead = blah;
remove(&theHead);
Then in remove you can change the value of the pointer:
*head = NULL;
And you can also dereference it of course:
(*head)->next; // etc

Why use **head (and not *head) in RemoveHead(node) function?

In most of the explanations in the book the author insists of using **list passing instead of *list, however as per my understanding I feel there is nothing wrong in *list. Please someone explain me in detail if i am wrong. For example, to delete head of a linked list, the author says the below code is wrong.
void RemoveHead(node *head)
{
node *temp = head-> next; /* line 1 */
free(head);
head = temp;
}
Instead he says the below code must be used
void RemoveHead(node **head)
{
node *temp = (*head)-> next;
free(*head);
*head = temp;
}
In your first example:
head = temp;
Does nothing outside the function, it only sets the local variable head to temp inside the function. Whatever variable the caller passed in will remain unchanged. The author is correct, you need to use pointers or (better) references (if you're using C++).
Well. When you want to modify a integer variable inside a function, you pass it by reference. That is, you pass its address.
int x = 5;
void modify_value (int* x)
{
(*x) = 7; // is not 5 anymore
}
With pointers is the same. If you want to modify a pointer. You have to pass it by reference. That is, you have to pass its address. Which is a pointer to a pointer.
int* ptr_x = &x;
void modify_pointer (int** ptr_x)
{
*ptr_x = NULL; // is not &x anymore
}
Author is right. ** is effectively pass by reference (i.e. you can change 'head').
In your version (pass by value), head remains unchanged in the calling code.
When passing a node* as the argument, you can free, and modify the contents of the memory address pointed by that pointer. However, modifications performed on the pointer itself will not be seen from outside the function, since the pointer is passed by value.
On you second example, since you are passing a pointer to the head pointer, you can actually modify the actual head pointer, not just the memory pointed by it.
So in your second function, when *head = temp; is executed, you are modifying the address to which the pointer passed as argument points to.
Therefore, the author is right.
The author is correct. In your first example, you're modifying a local copy of head - the caller won't notice that anything has changed. head will still have been freed, so you're on track for a crash in pretty short order. You need to pass a pointer to modify the caller's variable.

Pointer - returning Local reference in C++

I'm not sure if this question has been asked before ( searched through SOF and couldn't find an answer)
I wrote a LinkedList class and a function to reverse it.The function as follows,
struct LinkedList::element* LinkedList::recurrsiveReverseList(element* head){
element* tempList;
if(head->next == NULL){
return head;
}else{
tempList = recurrsiveReverseList(head->next);
head->next->next = head;
head->next = NULL;
return tempList;
}
}
here I am declaring a local pointer variable and making some changes to it and returning it back to the caller. In C++, when I declare a local variable inside a function the scope exists only inside the function. Now when I return the pointer from the function how does it work? I am able to understand the logic and get the result (luckily) but I am not able to completely understand the working here.
Can somebody clear my doubt?
The scope of tempList terminates when you exit the function but tempList is a pointer to a block of memory whose scope does not terminate there because it's been undoubtedly allocated by new. Memory allocated in such a way is valid right up until the point you delete it, regardless of how many functions you go in to or out of.
By passing the pointer back to the caller, it preserves said pointer elsewhere, where you can use it.
A simple example:
static char *fn (void) {
char *rv = new char[42];
return rv;
}
int main (void) {
char *x = fn();
delete [] x;
return 0;
}
In the code above, the scope of rv is limited to the fn function after it's declared.
The scope of x is limited to the main function after it's declared.
However the memory allocated by new comes into existence within fn and continues to exist after returning to main. The address of said memory, initially stored in rv, is transferred to x by the assignment of the fn return value to x.
Not sure if someone else explained it this way, but the pointer itself is nothing more than a number, like... 0x12345678. That number in turn addresses a position in the memory of a computer that contains the actual value you are looking for, which is the linked list node.
So when you return that address, it's okay that the original variable was destroyed. Like copying down a street address to a different piece of paper, then throwing away the original paper. The house that is at the address you have is still there.
The pointer object tempList ceases to exist when you leave the function. But that's ok; you're returning (a copy of) the value that was stored in the object, not the object itself. It's just like
int n = 42;
return n;
(Returning the address of a local variable is what gets you into trouble.)
I assume your linked list nodes are allocated on the free store (i.e. with new).
When you create an object with new, it is created on the free store and exists until you call delete on it. You can make as many pointers to that location as you want, and it exists independent of any function calls it may have been made in. So in this function, you are just returning a pointer by value to that location on the free store. The pointer is just a number which is the address of the object, like returning an int by value.
tl;dr: You obviously know you can return local objects by value because a copy is made. In this function, it returns a copy of the pointer which points to a location on the free store which is only destroyed when delete is called with a pointer to that memory location.
As another note, you probably should not return a pointer to the new head of the list but rather take a pointer to the head of the list by reference and change the list through that, so if someone forgets to assign their old head pointer to the one returned by recurrsiveReverseList, things aren't messed up.
The scope of usage of tempList variable is limited within the method as its local, but it holds a memory address which is what is returned.
The code that call its will receive this memory address, not the variable tempList.

In C++, are changes to pointers passed to a function reflected in the calling function?

If I pass a pointer P from function f1 to function f2, and modify the contents of P in f2, will these modifications be reflected in f1 automatically?
For example, if I need to delete the first node in a linked list:
void f2( Node *p)
{
Node *tmp = p;
p = p -> next;
delete tmp;
}
Will the changes made to P be reflected in the calling function, or will it now point to a memory space that has been deallocated?
( My intuitive answer here is no, changes are not reflected. However, good sources tell me that the above code will work. Can someone take the time to give the answer and explain the reasoning behind it also please? Also, if the above code is faulty, how can we achieve this without using a return type? )
If I pass a pointer P from function f1 to function f2, and modify the contents of P in f2, will these modifications be reflected in f1 automatically?
No. Since C and C++ implement pass-by-value, the value of the pointer is copied when it’s passed to the function. Only that local copy is modified, and the value is not copied back when the function is left (this would be copy-by-reference which a few languages support).
If you want the original value to be modified, you need to pass a reference to the pointer, i.e. change your signature of f2 to read:
void f2( Node*& p)
However, your f2 not only changes the pointer p, it also changes its underlying value (= the value being pointed to) by using delete. That change is indeed visible to the caller.
This will work, althrough not the way you want to.
If you call it like:
Node* mynode = new Node(); /*fill data*/
f2(mynode);
-> there will be the content of mynode undefined.
it will pass the value of the pointer to another function, and the value (p) will be local for function f2. If you want to modify it, use this way:
Node* mynode = new Node(); /*fill data*/
f2(&mynode);
void f2(Node** p)
{
Node* tmp = *p;
*p = (*p)->next;
delete tmp;
}