YTread Logo
YTread Logo

Pointers as function returns in C/C++

Jun 07, 2021
In this lesson we will talk about

pointers

as a return type for

function

s. The pointer is just another data type. It's just that a pointer stores the address of another data type. Therefore, it is quite possible for a

function

to return a pointer. But we need to understand the use cases where we may want to return a pointer from a function. So let's try to understand this. I'll start by writing some code. Now I want to initially write a very simple C program. I want to write an Add function that will take two integers as an argument and add these two numbers together and return the sum.
pointers as function returns in c c
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 call these variables x and y. Let's say x equals 2 and y equals 4 and we'll have another variable z that will be the return of this Sum function and we'll pass x and y as arguments to this function. Finally, I'll print something like sum equals z. There are no prizes for guessing the exit here. Now I'll tweak this code a bit, but before I do that I want to talk about this concept one more time, that x, y, and z are local to the main function and a, b, and c are local to the Add function.
pointers as function returns in c c

More Interesting Facts About,

pointers as function returns in c c...

What actually happens when we call the Add function is that the value in this variable x of main is copied to the variable a of Add. And the value in y of main is copied to b of add. What if we named these variables in main a, b, and c instead of x, y, and z? If we run this code, the output will be the same. This time what we'll 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.
pointers as function returns in c c
There is a in main and there is a in Add: they are 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, the address of a in main is something like 2883032 and in Add it's 2882792. So they're not the same. That means these variables are not the same. They are at different memory addresses. Variable names are local or specific to a particular function. In our example here, the main method or function may be called a "called" function, and the Add function may be called a "called" function in this particular call, when we say that c equals Add and pass a and b .
pointers as function returns in c c
And this call where a and b in main are copied to a and b in add is called call by value. Now what I want to do is, instead of passing by value, I want to pass the addresses of these two variables. So I mean I want to pass the address of a and the address of b to the Add function. So the signature of the Add function must be such that it receives the addresses. So I'll say, okay, it takes 2

pointers

for the integers a and b. And now we can access the values ​​at these addresses using this asterisk operator which is used to dereference an address.
Now such a call is called a call by reference. a and b are integers local to the main function and in the Add function, a and b are not integer variables. a and b are pointer variables, pointer to integers. So your type is different. They're not int, they're int* But at the end of the day, they're also variables that are local to the add function. It's just that they're not whole numbers. And now I'm using these two variables that point to integers to access these two variables a and b that are in the main method. And to do that we use the asterisk operator and now this code should work too.
I'll write a few more print statements inside this Add function. I have tried to print a and I have tried to print *a and initially it was printing &a. So now &a should give us the address of the pointer variable. a should give us the address of a in main because that's what this variable stores, and *a should give us the value of a in main. Let's see at the output. Now, as you can see here, the address of a in main is 3537612 and the 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 equal and using the address, we are printing the value which is equal to 2. I will now clean up some of these print instructions. Going back to our add function, we are returning this value c. And once again in the main method, we collect this value c in another variable which is c for main. Now why not do something like pass the address of this c in the Add function? So what we'll do now is say we want to return the pointer to the integer of this function and here we'll return &c.
Now & when put in front of a variable gives us the address. Now, of course, here we'll need to collect this particular address, so we'll need to define a pointer variable. Now this would be fine. Now, when we're printing, we'll need to print the value in the direction this variable is pointing to. Now what we just did is modify this Add function to return a pointer to an integer. There are two syntaxes. 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 syntaxes are valid.
Now this function is returning the pointer to the integer. Let's run this program and see what happens. Let me also cross out this statement printed here. Ok, so the output seems fine. Now, have you caught any logical errors with this code yet? If you haven't stayed with me for a while. Now what I want to do is write another function, a simple function that prints "hello world". So I'll call this function PrintHelloWorld and in this function I'll write a simple print statement. Now, before I print this sum, what I'm going to do is call this function PrintHelloWorld() And let's see what happens next.
Wow, this looks weird! The sum is not correct now. I just saw that it was working fine on my last run when I didn't call PrintHelloWorld. What happened? So let's try to understand what really happened here. I'll return to this familiar diagram of various sections of application memory. The memory that is allocated to a program is normally divided into these sections. All local variables and information about function call executions go on the stack. So let's walk through this code, simulate this code, and see what's actually going on in memory. For each function call, a part of the stack memory is allocated for its execution.
Now we call this the stack frame of that method or that function. When the program starts to run, the main method is called first. 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 start address of this stack frame is 100 and the end address of this stack frame is 130. And we'll 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'm just making these assumptions. Now when the main method gets to this line where it is calling the Add function, its execution will stop and memory will now be allocated for the Add execution. At any time, whatever function is at the top of the stack is running. The main method will wait for the Add function to complete and return. Here it should say that a equals 2, b equals 4, and now Add comes here on 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 your addresses are 130, 140, and 144. Again, these are just random guesses. Now c is calculated as *a + *b. a points to this location and b points to this location. *a is the value at the address stored in a and *b is the value at the 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 your local variable c which is 144 and end its execution. So this ptr will be 144 and now the memory allocated to the Add function will be deallocated.
Now this memory above address 130 can be used for other function calls. And even though this ptr variable stores address 144, the address of this particular block (somehow points to this particular block), the date here is not guaranteed because this memory has been deallocated. Now we come to this PrintHelloWorld and now the stack memory will be allocated to PrintHelloWorld above this main method stack frame. This is main. So let's say that PrintHelloWorld fetches this block of memory from address 130 to address 150. Now there is no local variable in this PrintHelloWorld function. But still, the execution of the function call involves the 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 overwritten. So this block at 144 no longer stores the value 6. So when we get here in this print statement, to print the value at this particular address, we get a garbage value. Now the obvious question would be, why did we get the correct value when we weren't calling PrintHelloWorld? I'd say I was just lucky. Perhaps because I didn't call any other functions after making a call to Add, my machine didn't overwrite or delete the data in that particular memory location.
But when I made a call to PrintHelloWorld that memory was used. If you see, we have passed the addresses of these two variables a and b from main to the Add function. But that's okay because the called function is always above the calling function on the stack. So every time this called function is executed, the called function will be in memory. So if Add is running, main is guaranteed to be in memory. So the addresses of the variables in main will be accessible to Add. But if we try to return a local variable from the called function to the calling function, like if we want to return a local variable from Add to Main, when that function finishes and control

returns

to the calling function, that memory has already been deallocated. .
So, it's okay to pass something from the bottom up on this call stack, or rather, it's okay to pass a local variable or the address of a local variable from the bottom up on the stack, but it's not okay to return the address of a local variable from top to bottom on the call stack. I hope this makes sense. So now the obvious question would be: what are the use cases in which we might want to return function pointers? Well, if we have the address of some block of memory in the heap section or some block of memory in the global section, then we can safely return the address of these blocks because anything on the heap has to be deallocated explicitly.
We control its deallocation unlike the stack. And whatever is in the global section, a global variable, lives for the lifetime of the program. I can use malloc or new operator in C++ to get some memory on the heap. So if I modify my code like this, I'll declare this c as a pointer to an integer and allocate some heap space by calling malloc. malloc is a library function that returns a pointer, but it returns a pointer to an address that is on the heap. So we get a block of memory and using this pointer variable now, we can write this value - *a + *b - to that particular block of memory.
And then we can return this address c, which is the same address that malloc returned to us, but now we're safe because we're returning the address of a block that's 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 on the heap. c now only points to this block and by using c we have written this data here, this value 6. And now when the addition is finished, the address returned by the Add function, which is address 500, is still valid.
We still have the data there and it won't be deallocated. Anything on the heap has to be deallocated explicitly. So when returning function pointers, we need to be careful about the scope. We need to make sure that the address isn't reused to store something else or that data isn't erased from that address. In most cases, we will return pointers to the memory that is allocated on the heap, or the memory that is in the global section, the global variables section. In our next few lessons, one place we'll use pointers as function returns in our code is in the implementation of the linked list data structure.
So this was pointers as the function returns. Thanks for watching.

If you have any copyright issue, please Contact