Pointers as function returns in C/C++

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
In this lesson we will talk about pointers as return type for functions. Pointer is just another data type. It's just that a pointer stores the address of another data type. So it is quite possible for a function to return pointer. But we must understand the use cases in which we may want to return a pointer from a function. So let us try to understand this. I'll get started by writing some code. Now I want to write a very simple C program initially. I want to write a function Add that will take two integers as argument and sum these two numbers and return the sum. So let's say we declare another variable c and c equals a + b and the function returns c. Now in the main method I'll initialize two variables. Let's name these variables x and y. Let's say x is equal to 2 and y is equal to 4 and we will have another variable z which will be the return of this function Add and we will pass x and y as arguments to this function. Finally, I'll print something like sum is equal to z. No prizes for guessing the output here. Now I'll modify this code slightly, but before that I want to talk about this concept once again that x, y and z are local variables to main function and a, b, and c are local to Add function. What really happens when we call the Add function is that value in this variable x of main is copied to variable a of Add. And value in y of main is copied to b of add. And what if we name these variables in main a, b and c instead of x, y and z. If we run this code, output will be the same. This time what we will say is that the value of a in main is copied to a of Add and the value of b in main is copied to b of Add. This a in main and this a in Add - they're not the same. You can verify this by printing something like this. I'm printing the addresses of these two 'a's in my code and as you can see address of a in main is something like 2883032 and in Add it is 2882792. So they're not the same. That means these variables are not the same. They're at different memory addresses. The names of variables are local or specific to a particular function. In our example here, the method or the function main can be called "calling" function and the function Add can be called "called" function in this particular call, when we're saying that c is equal to Add and passing a and b. And this call where a and b in main are getting copied to a and b in add, this is called a call by value. Now what I want do is, instead of passing by value I want to pass the addresses of these two variables. So I want to say that I want to pass the address of a and address of b to the Add function. So the signature of Add function should be such that it should receive the addresses. So I'll say that, okay, it takes 2 pointers to integers a and b. And now we can access the values at these addresses by using this asterisk operator which is used to de-reference an address. Now such a call is called call by reference. a and b are integers local to main function and in the function Add, a and b are not integer variables. a and b are pointer variables, pointer to integers. So their type is different. They're not int, they're int* But at the end of the day, they're also variables which are local to the function add. It's just that they're not integers. And now I'm using these two variables which are pointer to integers to access these two variables a and b which are in the main method. And to do so we use the asterisk operator and now, this code should also work. I'll write a few more print statements inside this function Add. I have tried to print a and I have tried to print *a and initially I was printing &a. So now &a should give us the address of the pointer variable. a should gives us the address of a in main because that is what this variable stores and *a should give us the value of a in main. Let us see in the output. Now as you can see here, the address of a in main is 3537612 and address of a in Add is something else, but the value of a in Add which is the address of a of main is equal to 3537612. So the first and the third lines are same And using the address, we're printing the value which is equal to 2. Now I'll clean up some of these print statements. Coming back to our function add, we're returning this value c. And once again in the main method, we're collecting this value c in another variable which is c of main. Now why not do something like pass the address of this c in Add function. So what we will do now is we will say that we want to return pointer to integer from this function and here we will return &c. Now & when it is put in front of a variable it gives us the address. Now of course, here we will have to collect this particular address, so we will have to define a pointer variable. Now this would be ok. Now when we're printing, we will have to print the value at address being pointed to by this variable. Now what we just did is we modified this Add function to return a pointer to integer. There are two syntax-es We can say int and then put this * sign or we can say int and put the * sign in front of the function name Add and both these syntax-es are valid. Now this function is returning pointer to integer. Let us run this program and see what happens. Let me also strike off this print statement here. Okay, so the output seems to be alright. Now have you caught some logical error with this code already? If you haven't stay with me for sometime. Now what I want to do is I want to write another function, a simple function that will print "hello world". So I'll name this function PrintHelloWorld and in this function I'll write a simple print statement. Now before I print this sum, what I'll do is I'll call this function PrintHelloWorld() And let's see what happens now. Oops - this looks weird! Sum is not correct now. I just saw that it was coming fine in my last run when I did not call this PrintHelloWorld. What happened? So let's try to understand what really happened here? I'll come back to this familiar diagram of various sections of application's memory. The memory that is allocated to a program is typically divided into these sections. All the local variables and the information about function call executions goes into the stack. So let us run through this code, let us simulate this code and see what's really happening in the memory. For each function call, some part of memory from the stack is allocated for its execution. Now we call this the stack frame of that method or that function. When the program starts executing, first the main method is invoked. So in the stack frame the memory will be allocated for the main function and all the local variables of the main function will live inside this stack frame. Let's say the starting address of this stack frame is 100 and the end address of this stack frame is 130. And we will have 3 local variables created here - a, b and ptr. a and b are integers and ptr is an integer pointer. Let's say a is at address 100 and b is at address 112 and ptr is at address 120. I am just making these assumptions. Now when the main method will come at this line where it is calling Add function, its execution will pause and now memory will be allocated for the execution of Add. At any time whatever function is at the top of the stack is executing. main method will wait for Add function to complete and return. Here I should say a is equal to 2, b is equal to 4 and now Add comes here in the stack. Let's say Add gets memory from 130 to 160.and Add also has 3 local variables - a, b and c. a and b are pointers to integers. The value of a will be 100 and the value of b will be 112. Let's say their addresses are 130, 140 and 144. Once again these are just random assumptions. Now c is calculated as *a + *b. a is pointing to this location and b is pointing to this location. *a is value at address stored in a and *b is value at address stored in b. So this c will be 6 here. These two values will be added. Now this add function will return the address of its local variable c which is 144 and finish its execution. So this ptr will be 144 and now the memory that is allocated to Add function will be de-allocated. Now this memory above address 130 can be used for other function calls. And even though this variable ptr stores the address 144, the address of this particular block (it kind of points to this particular block), the date here is not guaranteed because this memory has been de-allocated. Now we come here to this PrintHelloWorld and now memory from stack will be allocated to PrintHelloWorld above this stack frame of main method. This is main. So let's say that PrintHelloWorld gets this memory block from address 130 to address 150. Now there is no local variable in this PrintHelloWorld function. But still, function call execution involves storage of some information. Now this section, from 130 to 150 is for PrintHelloWorld. I'll write PHW - shortcut for PrintHelloWorld. And it has been over-written. So this block at 144 no more stores value 6. So when we come here at this print statement, to print the value at this particular address, we get some garbage value. Now the obvious question would be, why did we get the right value when we were not making the call to PrintHelloWorld. I would say that I just got lucky. Maybe because I did not call any other function after making a call to Add, my machine did not overwrite or erase the data at that particular memory location. But when I made a call to PrintHelloWorld that memory got used. If you see, we have passed the addresses of these two variables a and b of main to Add function. But that is alright because called function always comes above the calling function in the stack. So any time this called function is executing, calling function will be in the memory. So if Add is executing, main is guaranteed to be in the memory. So addresses of variables in main will be accessible to Add. But if we try to return a local variable from the called functionback to the calling function - like if we want to return a local variable from Add to main, when that function finishes and the control returns back to the calling function that memory has already been de-allocated. So it is ok to pass something from bottom to top in this call stack, or I should rather say that it is ok to pass a local variable or address of a local variable from bottom to top in the stack but it is not ok to return the address of a local variable from top to bottom in the call-stack. I hope this makes sense. So now the obvious question would be - what are the uses cases in which we may want to return pointers from functions. Well, if we have address of some memory block in the heap section or some memory block in the global section, then we can safely return the address of these blocks because anything in the heap has to be explicitly de-allocated. We control its de-allocation unlike stack. And anything which is in the global section, a global variable, lives for the entire lifetime of the program. I can use malloc or new operator in C++ to get some memory on heap. So if I modify my code something like this, I will declare this c as a pointer to integer and get some space allocated on the heap using a call to malloc. malloc is a library function that returns pointer, but it returns pointer to an address which is on the heap. So we get a memory block and using this pointer variable now, we can write this value - *a + *b - at that particular memory block. And then we can return this address c, which is the same address that malloc returned us but we are safe now because we are returning address of a block which is on the heap and not on the stack. And this will work now. Now in this code, let's say this call to malloc gives us this block at address 500 in the heap. c now is only pointing to this block and using c we have written this data here, this value 6. And now when add finishes, the address returned by the Add function which is address 500 is still valid. We still have the data there and it will not be de-allocated. Anything on the heap has to be explicitly de-allocated. So while returning pointers from functions, we need to be careful about the scope. We must be sure that the address is not re-used to store something else or that the data is not cleared from that address. In most cases we will be returning pointers to memory that is allocated on the heap, or memory that is in the global section, the global variables section. In our coming lessons, one place where we will be using pointers as function returns in our code is implementation of linked list data structure. So this was pointers as function returns. Thanks for watching.
Info
Channel: mycodeschool
Views: 235,360
Rating: 4.9537573 out of 5
Keywords: pointers, coding, interview, programming, c++
Id: E8Yh4dw6Diw
Channel Id: undefined
Length: 15min 14sec (914 seconds)
Published: Fri Apr 12 2013
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.