 Hello and welcome. In this lecture, we are going to look at the flow of control in a program with function calls. Here is a quick recap of some of the relevant topics we have already studied. We have seen the use of simple functions in programs. Basically, a function encapsulates a computational sub task and allows us to do modular programming. We have seen how one function can be invoked from another function and we have also seen that functions mostly return values of specified types. We have also looked at in some detail the contract centric view of programming with functions. In this lecture, we are going to see in great detail how control flows in a program when a function is called and when a function call returns and we will see that this flow of control is implemented through activation records and call stack. So, let us recall the encoding example that we had seen in an earlier lecture. We wanted to store the quiz 1 and quiz 2 marks of all CS11 students in an encoded form so that others cannot figure out the actual marks. The encoding strategy we had decided upon was that the ordered pair of marks m comma n will be encoded as 2 raised to m times 3 raised to n and we are going to assume that all marks are integers in 1 through 10. Here is the C++ program structure that we had seen earlier. I have only written down those parts of the program where I want to focus these are the parts with function calls. The other parts I have blanked out with 3 dots. So, here in the main function I have a loop which is iterated for every student where we read in the marks and then call this function my encode which takes to integer parameters and returns an integer value which gives the encoded version of these 2 marks. Now, the function my encode in turn calls a function power to raise 2 to the power of quiz 1 marks and 3 to the power of quiz 2 marks. So, this is another function called within the function call my encode and of course, power raises base to the exponent and returns that value. Now, in the contract centric view of programming with functions we said that we do not need to worry about the internals of a function when we are using it and this is achieved by specifying preconditions and post conditions and respecting those whenever we call a function. So, this is very important in the use of programming with functions. Let us recall the preconditions we had used there. We had said that quiz 1 marks and quiz 2 marks should lie between 1 and 10 and why did we say that? So, that the result which is 2 raise to quiz 1 marks time 3 raise to quiz 2 marks can indeed be represented within 32 bits and of course, if this precondition is satisfied this function guarantees that the return value is exactly as we expect. For the power function we had a precondition base greater than 0 exponent greater than equal to 0 and I have also added another part to the precondition here. This is important which we had not discussed in the earlier lecture that the result base raise to exponent should lie between 1 and 2 raise to 31 minus 1. This is the range of positive numbers positive integers that can be stored in the integer data type and so we require this as part of the precondition and if this precondition is satisfied then the return value will indeed be as expected. Now, let us look at how control flows in this program with two different function calls calls to my encode and calls to power. So, here is our little running man showing how the control is being executed in this function. We are inside the for loop and we have now encountered this function call. What do we do? We remember where to return back when this function call returns in some book keeping information and then we go to the first executable instruction of my encode and then we start execution from there and we encounter power. Now, this is the function call power. So, again we have to remember where to return back from power and start executing the function power the instructions in the function power and after executing those instructions when we hit return result when we execute this instruction we have to go back and look at this book keeping information to figure out where to return control to and once we have done that we do not need this book keeping information we can proceed ahead with our execution of my encode. We encounter this function call again we keep track of where we should return back come to power and start executing the instructions there when we hit result there we look up this book keeping information to figure out where to go to then this book keeping information is no longer needed and finally, we execute the remainder of instructions execute the return statement here and now this book keeping information tells us where we should return to. So, we return there the book keeping information is no longer needed we now execute the remainder of the instructions. Now, this is a for loop. So, I might go back into the for loop and execute the loop one more time. So, as you will see we are keeping track of book keeping informations every time a function is called. So, that we know where to return to when we encountered the return statement in a function and now this control returns there and we continue execution that is the second invocation of the function power and this time maybe we have put a large exponents of power is running a bit more it is taking a bit more time to run power and then after we have run power after we have executed the instructions in power we are going to execute the return result instruction and then this book keeping information tells us where to return to and then we execute the subsequent instructions return from the function my encode execute subsequent instructions in the function main and maybe this time when we go back to the for loop we have to exit from the for loop. So, we execute instructions after the for loop and return now having seen this animation of how control flows let us take a closer look at what exactly is happening. The operating system called the function main I have sort of represented here by saying that the operating system at some point of time called the function main the main called the function my encode with two parameters. So, I have sort of put that on top of the previous entry that I had kept there because this is the latest function called that happened the main code in turn calls the function power with some other values of parameters. So, now I put that on top of the previous two entries because that is the latest function called that happens. So, now when power returns I have to look at the latest function called that happened and I have to figure out where to go back to in main code specifically I will go back to exactly the location exactly the instruction where main code called power. And after that this entry is no longer needed then my encode calls power again with different values of the parameters. So, I store that information on top of the stack of information because that is the latest function called that happened when power returns to my encode I have to see what was the latest function called where was the function invoked and when power returns I will have to go back to exactly that instruction where this function was invoked and then that entry is no longer needed now my encode returns to main. So, I have to go back and figure out where did my main call my encode I have to go back there after that that entry is no longer needed and finally main returns to OS after which this entry is not needed anymore. So, if you look at the way I was managing the information over here I basically needed to keep track of which function was called, but whenever there was a return I wanted to access information about the latest function that was called. So, I really need to access information in the last and first out order. So, that is what we need to do we need to store information about function calls such that we can access them in the last and first out order, but this is exactly what a stack allows us to do you can think of a stack of papers when I put in one paper it goes to the bottom of the stack the next paper goes on top the third paper goes on top of that and when I am removing papers I am removing from the top of the stack at any point of time and then if I want to add some more papers again it again goes back to the top of the stack and removing again removes always from the top of the stack. So, this is exactly how we want to manage information about function calls. So, that is what the computer actually does it uses a call stack to store information about function calls and we will soon see that this call stack resides in a special reserved part of the main memory. So, now the question is we know that we must use a stack what is the information that we must store in this call stack. Now, let us recall the flow of control again we made a function call there and we kept this bookkeeping information here and then when we executed this return statement inside my encode we use this bookkeeping information to figure out where to come back to which means that I need to remember where to return in the calling function in addition after I have returned back here I am going to execute further instructions in the calling function. So, I must also remember what the values of variable look various local variables where in the calling function at the time I made this function call. So, this basically tells us what we must store in the stack now to understand how it is exactly stored let us see how the memory for an executing program also called a process looks like. Now, the operating system is going to allocate only a part of the main memory for use by a process. So, this is the main memory the operating system may allocate this part for use by our process and this part is further going to be divided into three segments the code segments stores all the executable instructions the machine instructions in the program the data segment is used for dynamically allocated data we will see this in a later lecture the stack segment stores the call stack that we have just seen. Now, that you know that a program is actually stored in a part of main memory. So, it is easy to see that each instruction of the program which is stored in some location of main memory will also have a memory address and inside a computer in the CPU we use a special register called the program counter that always holds the memory address of the current instruction being executed by the computer. This is very convenient when implementing function calls and returns because when a particular function is called from another function all we need to do is we need to note the value of the PC at the time the function was called we need to save it somewhere and when we are returning from the called function we should simply resume execution at the saved value of the PC. So, this is how we actually manage information so that we can figure out exactly where to return when a function returns and this is what is formalized and what is called an activation frame or an activation record every time a function is called we make an entry in the call stack and this entry is called the activation frame or record. For example, if the main function calls my encode this is the caller function this is the call function the activation record for the callee will contain memory space for all the local variables of the callee it will contain space for the program counter value in the caller when the callee was called. So, in our case it will have the address of the instruction in main that called my encode it will have space for the return value of the callee and it will have some additional bookkeeping information also let us not worry about that. Now, once we know that this is the information that is saved in an activation frame which will go on to the call stack let us see how activation records are used in a call stack. So, let us say a function calls another function in this particular case my encode calls power. So, in the call stack we already have the activation record for main this was already invoked main in turn invoked my encode. So, the activation record for my encode is also there and now my encode is invoking power when my encode when my encode invokes power a fresh activation record for power is created the values of all these function parameters from the calling function to the called function gets copied from the activation record of my encode to the activation record of power the PC value of the caller the address of the instruction that called this function power is saved here in this yellow thin rectangle here other bookkeeping information is updated and finally, the activation record of the callee is pushed on to the call stack. What happens when a function returns in this case when the power function returns its activation record is popped out from the call stack the return value of this function here we had a return result the return value was reciting the activation record of the power it will now be copied to the activation record of the caller which is now on top of the stack the value of the PC which was the location in my encode where power was called will be popped from this activation record and loaded in the PC of the CPU the activation record of the callee will then be freed up and it is an execution will resume exactly at the location given by this updated value of the PC. That is the instruction in my encode where power was called so in summary in this lecture we looked at flow of control in function calls and returns we looked at how memory is laid out for a running program which is also called the process and we saw the use of call stacks and activation records in function calls and returns thank you.