Pointer - returning Local reference in C++ - 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.

Related

Initialize a pointer to an object

Given an object, e.g. listNode.
If I initialize a pointer to an object with:
listNode* head_node;
How is this any different from
listNode* head_node = NULL;
In the first case listNode* head_node; the compiler will allocate some memory to hold the pointer. That memory can contain any value (for example it could be some random value from when that location was used for something else) and, in fact, reading it will result in undefined behavior.
In the second case listNode* head_node = NULL;, the compiler will allocate some memory to hold the pointer and then write NULL to that location so the pointer is guaranteed to be NULL.
One thing to note, you should use nullptr as opposed to NULL. See this answer for why.
In the first case, you are declaring a pointer variable. In the second case, you are declaring a pointer variable and initializing it to NULL. Any variable that is declared but not initialized leads to undefined behaviour when you try to access the variable. This has nothing to do specifically with pointers, pointers are just like any other variable. For example, if you write int a; and then you cout << a; you will see that a most likely has a random integer value written in it. But if you write int a = 0; and then you cout << a; you will see that a is always 0 on any compiler on any machine. This is well defined behaviour as opposed to undefined behaviour.
I would discourage the use of raw pointers in your case, as you most likely want always them to be initialized to nullptr, plus your listNode is most likely "owned" by the list itself. Try to use std::unique_ptr<listNode> instead: it will both initialize you pointer to nullptr by default and release the allocated memory when the pointer goes out of scope, meaning that if the head of the list will be deleted, all the other nodes in the list will automatically be deleted as well.

Is there any significance of having a static keyword for a dynamically created array?

I am allowed to execute this code without an error. So I believe C++ allows this.
Ex:
char *foo (char *start, int n) {
static char* temp; //Does this have any significance?
temp = new char[n];
for (int j=0; j<n; j++)
temp[(n-1)-j]=start[j];
return temp;
}
int main(){
char *c;
char a[6]={'1','2','3','4','5','\0'};
c = a;
int n = sizeof(a);
c = foo(c,n);
delete []c; //Does this delete the static array created in foo()?
return 0;
}
P.S.- I know there is a better way of reversing an array but the Q is not focused on that. I just was not able to come up with a better example.:)
EDIT: I understand temp gets created in heap and I don't need to use static. But does static keyword in variable declaration make any difference while creating a dynamic array in memory mapping, etc.?
The temp variable is static, the memory block whose address it stores is dynamically allocated (new char[n]) and freed (delete []c).
They are different objects.
The array doesn't care about temp (it doesn't even know about it). You can store the address of the array in many variables; this doesn't change its behaviour in any way.
I understand temp gets created in heap.
temp is not created in the heap. It is a local variable; local variables are not stored in the heap.
static char* temp; //Does this have any significance?
The static keyword makes temp a permanent variable, that exists since the program starts until it ends. The static keyword ensures its value is not lost when the function ends. Every time the function foo() is executed (except the first one), the value of temp is the same it was the last time when it ran.
But, being a local variable, temp is available only in the foo() function.
The value of temp is a memory address. The address of the block allocated using new char[n]. This block of memory is allocated in the heap and it is valid until it is released (using delete []c). It can be accessed from main() too, given its address is somehow available in the main() function. And it is available because the call to the foo() function returns it and main() stores it in c.
delete []c; //Does this delete the static array created in foo()?
No, it deletes (in fact, releases) only the array (created in foo()). The static variable (temp) is not affected in any way.
You allocated some memory with new[] and you released it with delete[]. That's what you're supposed to do. You can manipulate a pointer to that memory however you want so long as you pass the same value to delete[] that you got from new[].
Your function should be (and is) returning the value it got from new[]. It can store that in a temporary if it wants to. The error is returning a pointer or reference to a temporary. Returning the value of a temporary is fine -- otherwise it would be almost impossible to return anything other than a constant or a pointer or reference to a parameter passed by reference or a global.

Return with Ampersand

I had to return pointer of a structure object in function but I didn't store them as pointers, so I used return &myStructObject; to return. It does not give any compile-time error but what i'm trying to do is correct?
If structure object you are referring to is local to the function then you should not return the address of that struct object. This is because when your function returns call to its caller then all local variables are destroyed from memory.
For e.g:-
Below is a fatal error
int* myFunc ()
{
int p = 4; // memory is allocated for p.
// do something.
return &p; // memory for p is deallocated and you are returning pointer to that memory
}
If the struct variable whose pointer you want to return is still in scope after returning from the function, what you are doing is correct.
On the other hand, if the struct variable in question is local to the function and will be destroyed (freed) once you return from the function, then the pointer you will return will be a dangling pointer, and will not serve your purpose.
EDIT:
By "will not serve your purpose", I mean it will not do what you think it will! There's no point discussing what harms it can do, when you are sure it doesn't do what you expect it to do!
If you have got something local in a function and you are returning address to that, it will be lost i.e. nullified. The reason is that the function you are returning the address from will be POPped from the stack and anything non-static (non-global) will be lost. In essence, anything that the programme memory hasn't got as a "lifelong" resource will be gone. You can pass pointers as an argument to the function and dereference it to modify value pointed by the pointer. But anything that is non-static (or non-global) and returned as an address will cause you access violation-type errors.

issues in understanding pointers

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.

why does pointer get its previous value returning from a function

guys how does the ptr get its previous value? code is simple, I just wondered why it doesn't store the address value that it's been assigned within the function.
#include<stdio.h>
#include<stdlib.h>
void test(int*);
int main( )
{
int temp;
int*ptr;
temp=3;
ptr = &temp;
test(ptr);
printf("\nvalue of the pointed memory after exiting from the function:%d\n",*ptr);
printf("\nvalue of the pointer after exiting from the function:%d\n",ptr);
system("pause ");
return 0;
}
void test(int *tes){
int temp2;
temp2=710;
tes =&temp2;
printf("\nvalue of the pointed memory inside the function%d\n",*tes);
printf("\nvalue of the pointer inside the function%d\n",tes);
}
output is:
value of the pointed memory inside the function:710
value of the pointer inside the function:3405940
value of the pointed memory after exiting from the function:3
value of the pointer after exiting from the function:3406180
You passed the pointer by value.
The pointer inside test is a copy of the pointer inside main. Any changes made to the copy do not affect the original.
This is potentially confusing because, by using an int*, you're passing a handle ("reference", though actually a reference is a separate thing that exists in C++) to an int and thus avoiding copies of that int. However, the pointer itself is an object in its own right, and you're passing that around by value.
(You're also attempting to point your pointer to an int that's local to the function test. Using it will be invalid.)
The pointer is passed into the function by value, in other words a copy is made of it. In the function you change the copy, but that does not alter the value in main. If you wanted to change that, you would need to use a pointer to a pointer.
In case the other answers describing the issue are not sufficient.
The code you want so you can change the value is along these lines
test(&ptr);
void test(int **tes){
int *temp2 = new int;
*tes =&temp2;
}
Alternativly, don't mess with raw pointers. shared_ptr<> and & can be your friend!