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 very 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 takes two integers as an argument, adds them, and

returns

the sum.
pointers as function returns in c c
So let's say we declare another variable c and c is equal to a + b and the function

returns

c. Now in the main method, I will initialize two variables. Let's call 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 that will be the return of this Add function and we will pass x and y as arguments to this function. Finally, I'll print something like sum equals z. No prizes for guessing the outcome here. Now I will modify this code slightly, but before that I want to talk about this concept one more time: x, y, z are variables 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 main variable x is copied to the Add variable a. And the value in y of main is copied to b of add. What if we name these variables in main a, b and c instead of x, y and z? If we run this code, the result will be the same. On this occasion 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.
pointers as function returns in c c
This one in main and this one in Add are not the same. You can verify this by printing something like this. I am 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 is 2882792. So they are not the same. That means that 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 can be called function "call" and the Add function can be called function "call" in this particular call, when we say that c is equal to Add and we 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. Therefore, the signature of the Add function must be such that it receives the addresses. So I'll say that, okay, it takes 2

pointers

to 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, pointers to integers. So your type is different. They are not int, they are int* But at the end of the day, they are also local variables for the add function. It's just that they are not integers. 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 also work. I'll write a few more print statements inside this Add function. I tried printing a and I tried printing *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 exit. Now, as you can see here, the address of a in parent 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 in parent is equal to 3537612.
So the first one and the third lines are the same. And using the address, we print the value which is equal to 2. Now I'm going to clean up some of these print statements. Going back to our add function, we return this value c. And once again in the main method, we collect this value c into another variable which is c from main. Now why not do something like pass the address of this c into the Add function? So what we will do now is say we want to return the pointer to an 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 nice. Now when we print, we will have to print the value in the address that this variable points 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 * sign in front of the Add function name and both syntaxes are valid.
Now this function returns the pointer to an integer. Let's run this program and see what happens. Let me also cross out this printed statement here. Okay, so the result seems fine. Have you already detected any logical errors with this code? If you don't stay with me for some time. Now what I want to do is write another function, a simple function that prints "hello world." So I will call this function PrintHelloWorld and in this function I will 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 now.
Oops, this seems weird! The sum is not correct now. I just saw it going fine on my last run when I didn't call this 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 allocated to a program is usually divided into these sections. All local variables and information about function call executions go on the stack. So let's run this code, simulate this code and see what's actually happening in memory. For each function call, a portion of stack memory is allocated for execution.
Now we call this the stack frame of that method or that function. When the program starts running, the main method is called first. So in the stack frame, 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 ending address of this stack frame is 130. And here we will create 3 local variables: a, b and ptr. a and b are integers and ptr is an integer pointer. Let's say a is at address 100, b is at address 112, and ptr is at address 120.
I'm just making these assumptions. Now when the main method reaches this line where it calls the Add function, its execution will stop and memory will now be allocated for the execution of Add. At any time any function at the top of the stack is executed. The main method will wait for the Add function to complete and return. Here it should say that a is equal to 2, b is equal to 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 of the address stored in a and *b is the value of 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 its local variable c which is 144 and will 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 although this ptr variable stores address 144, the address of this particular block (it sort of 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 stack frame of the main method. This is main. So let's say PrintHelloWorld gets this block of memory from address 130 to address 150. Now there is no local variable in this PrintHelloWorld function. But still, executing a function call involves storing some information.
Now this section, 130 to 150, is for PrintHelloWorld. I will write PHW: shortcut for PrintHelloWorld. And it has been overwritten. So this block at 144 no longer stores the value 6. So when we come here to 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 were not making the call to PrintHelloWorld? I would say I was just lucky. Maybe because I didn't call any other functions after making an Add call, my machine didn't overwrite or erase the data in that particular memory location.
But when I made a call to PrintHelloWorld that memory got used to it. 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 always appears on top of the calling function on the stack. So every time this called function is executed, the calling function will be in memory. So if Add is running, main is guaranteed to be in memory. Therefore, 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 wanted to return a local variable from Add to Main, when that function ends 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 I should say that 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. from a local variable up and down the call stack. I hope this makes sense. So now the obvious question would be: what are the use cases where we might want to return function pointers? Well, if we have the 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 must be explicitly deallocated.
We control its deallocation unlike the stack. And anything in the global section, a global variable, will live for the entire life of the program. I can use malloc or the new operator in C++ to get some memory on the heap. So if I modify my code this way, I will declare this c as a pointer to an integer and get some space allocated on the heap using a call to 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 - into 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 are safe because we are returning the address of a block that 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 of the heap. c now just points to this block and 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 will not be deallocated. Everything on the heap must be explicitly deallocated. So when returning function pointers, we need to be careful about the scope. We must ensure that the address is not reused to store something else or that data is not deleted from that address. In most cases, we will return pointers to memory allocated on the heap, or to memory that is in the global section, the global variables section. In our next lessons, one place where we will use pointers as function returns in our code is the implementation of the linked list data structure.
So these were pointers as the function returns. Thanks for watching.

If you have any copyright issue, please Contact