 Hello and welcome back. This is the second part of our two part lecture on pointers and dynamic memory. Here is a quick recap of some of the relevant topics we have studied. We have studied the usage of variables and pointers to variables in C++ programs. We have seen the usage of the address of operator and the content of operator. We have seen how memory can be allocated on the stack segment as well as on the data segment or heap. In the last lecture, we looked at the new construct in C++ which allows us to dynamically allocate memory in the data segment or heap. In this lecture, we are going to see how dynamically allocated memory persists across function calls. And therefore, we will need to explicitly deallocate dynamically allocated memory. And we will also look at some good programming practices when deallocating dynamically allocated memory. Let us start with a simple function. In this function, I basically want to read the quiz marks of a certain number of students. And then I want to do some computation on it like finding the minimum and the maximum marks. So, in this function, I have this integer variable num students. I ask for the number of students in the class and read in that number in num students. Then I ask for the marks of all the students. And I call this function read quiz marks which takes as a parameter num students, the number of students in the class. And what I expect this function to do is to dynamically allocate an integer array of the same size as the number of students, read in the marks of all the students into that array and return to main a pointer to the first element in that array of integers. So, q marks has to be a pointer to an integer. So, as you can see that read quiz marks will basically take in an integer number and it will return a pointer to an integer. How might this function read quiz marks look like? Here is a sample implementation of read quiz marks. As a precondition, I have n greater than 0 as post condition. I guarantee that the marks of the students are going to be stored in a dynamically allocated array that is going to be returned. Inside read quiz marks, I dynamically allocate an integer array of size n. And then if that dynamic allocation failed, I return null. So, note that I could have put this as part of my post condition that if dynamic allocation fails, we are going to return null. I did not do that here only to save space, but in good programming practice, you should indicate this as part of the post condition. And if the dynamic allocation was successful, then I will simply iterate through this for loop, read in all the marks and store them in the marks array and finally return marks. Now, what is marks going to contain? It is basically going to contain the address of the first element in this dynamically allocated array. So, that is going to be returned to the main function. Let us see how the memory layout might look like as we execute this program. So, here I have the stack segment and the data segment in main memory. Here is the main function and when the main function is called by the operating system, the activation record of the main function will be in the call stack in the stack segment. In this activation record, each of the local variables of main function will be present. They will be allocated space in the activation record. And let us say that we have now read in the value of num students and that is 2. The value of q marks is still initialized. So, I have not shown anything over here, q marks basically contain some garbage value now. And then I go ahead and invoke this function read quiz marks. What is going to happen? The parameter here is num students which is 2. So, when I call read quiz marks, an activation record for read quiz marks will be pushed into the call stack in the stack segment. So, for the time being, let us assume that the stack is growing this way from the top to the bottom here. So, this is the bottom of the stack and this is pushed on top of the stack. And in the activation record of read quiz marks, I will have space for the formal parameter n which of course has the value 2 that is the value of num students. I also have space for marks and I should also have space for I but I have not shown that here just to keep the diagram simple. Now, when I execute the statement, I am dynamically allocating an array of size n that is 2 and this array will be allocated in the data segment. We have seen this in the last lecture. These are the addresses of the first bytes of the set of 4 bytes that is allocated for storing each integer. So, hex 400 to hex 403 stores the first element of the array and hex 404 to hex 407 stores the second element of the array. And I copy the address of the first element in the array to marks as a result of executing this assignment. And then finally, in this loop, let us say I have read in these two integer marks 10 and 15. And finally, when I return marks, what am I doing? I am basically saying the value of hex 400 should be returned to the main function and the activation record of read quiz marks will be gone. And in the main function, since the value returned by read quiz marks is assigned to q marks, so q marks will get the value hex 400. Note that the two array elements allocated in the data segment have stayed back, but now I can no longer call them as mark 0, marks 1 because I have come out of I have returned from the read quiz marks function in which mark 0 and marks 1 were the elements of the local array. Now, I have come out of this function, so I cannot call them using marks 0 and mark 1. So, although the activation record of read quiz marks is non-existent in the stack segment, the memory that was dynamically allocated in that function still persists. And interestingly, the main function has the address of this dynamically allocated memory. So, it can access this memory. What might the main function do by accessing this memory? Well, it might do a whole bunch of things here. If you go through this code, you will see that it is doing some sanity checks and then it is basically calculating the minimum and maximum of the marks. But now the question is that since read quiz marks returned without freeing up these two dynamically allocated memory locations, when is this memory going to be freed or deallocated? Now, it turns out that in C++ memory that is dynamically allocated by any function is not going to be automatically deallocated or freed when the function returns. So, unless you explicitly deallocate dynamically allocated memory, all of this is just going to hang around in the data segment until the program ends execution. And this can be very wasteful of memory. Let us see an illustration of how wasteful this can be. So, here is a modified version of our read quiz marks function which I am calling alternate read quiz marks. The only difference with respect to the previous function is highlighted in brown over here. I have a new integer pointer variable called temp which I am using to store the address of a new dynamically allocated integer array of the same size as n. Here is the sanity check to check if the new function actually succeeded. And in this loop in which I read in the marks, I am also adding 10 to each marks and storing it in this array temp which is a dynamically allocated array. And then I am going to do some computation with them and finally return marks. How might the memory layout look like in this case? So, of course, the activation record of main is there and these are the two local variables of main. The activation records of alt read quiz marks will contain the space for the formal parameter n, space for marks and temp which are basically going to store addresses and also space for i which I have not shown here to keep the diagram simple. And let us say that we have read in inside this for loop values 10 and 15 for mark 0 and marks 1 and 10 has been added to each of these and the values 20 and 25 have been stored in 10, in temp 0 and temp 1. Now, when I execute return marks, what happens? The activation record for alternate read quiz marks will be gone, but these two arrays which were allocated will persist in the data segment. But in the main function, what am I going to do? I am actually going to use only the integers at the address which I can access from q marks. So, basically I can access only this array of integers which contain the marks and so I will be basically only using this array and not using this array. So, array temp is of no use in main, but it persists in the heap and this is why we have wasted memory space. So, this is why we need to explicitly deallocate dynamically allocated memory and C++ provides a special construct to do this. If you had allocated memory for a single variable like this, we had studied this in the last lecture, then you can deallocate that memory by simply saying delete and the name of the pointer type variable which stores the address of the dynamically allocated variable. And if you allocated an array dynamically like this, you basically deallocate that array in the same way except that you put these two square brackets here to indicate to the computer that you were deallocating an entire array that was dynamically allocated. So, note the slight difference in usage. We basically use a square brackets here to say that I am deleting an entire array. Otherwise the keyword to be used is delete. A good programming practice when deallocating, you must always deallocate dynamically allocated memory once you have no further use of it, but you should also check for the validity of an address before you deallocate memory at that address. So, instead of just saying delete my array, you should perhaps check whether my array is not equal to null and only then delete my array because deallocate memory at the null address, then your program is going to crash. The null address of the zero address recall is outside the memory space of every process. So, here is how you might deallocate dynamically allocated memory in all read quiz marks. Just check whether temp is not equal to null and delete it. Note that by the time we have reached this point in this function, we know that temp is not equal to null, but I would still insist that before you use delete, you should always check that temp not equal to null. This is good programming practice. That would take away the dynamically allocated array temp. And now when you come back in the main function, you only have that part of the dynamically allocated memory persisting that you really need. And now it is main's responsibility to deallocate this dynamically allocated memory. This was allocated inside all read quiz marks, but since all read quiz marks didn't deallocate it, now main must deallocate it. And this is how main is going to deallocate that array. So, in summary, we saw the persistence of dynamically allocated memory across function calls. We saw the need for explicit deallocation of dynamically allocated memory. We saw the delete construct to help us do this. And we also saw some good programming practices when deallocating dynamic memory. Thank you.