 Hello and welcome back. In this lecture, we are going to look at the first part of a two part series on pointers and dynamic memory. Here is a quick recap of some of the relevant topics we have already studied. We have looked at variables and pointers to variables in the C++ programming language. We have seen how storage for variables is basically allocated stack segment. We have seen the use of the address of operator or the unary ampersand operator and the use of the content of operator or the unary star operator. However, in all that we have studied so far, the memory locations that we accessed either directly by their name or through their addresses, all of these memory locations were basically for local variables or arrays of functions and they were statically allocated in the stack segment when the function was called. In this lecture, we are going to see storage in another part of the memory allocated to a process by the operating system. Specifically, we are going to look at storage in the data segment, which is also called the heap. This will require us to study dynamic allocation of memory in C++. We will see how to access dynamically allocated memory. We will also look at some good programming practices when using dynamic memory. Now, if you recall, we had said earlier in one of the previous lectures that when a program is executing or in other words, when a process is running, the operating system allocates a part of the main memory for use by the process. This might be the part of the memory allocated for the process. We had also seen that this memory is actually divided into three segments, port segment which stores the executable instructions, the stack segment which basically stores the call stack and the activation records that are there in the call stack and the data segment. In our earlier study, we had said that we will look at how this data segment is used later. Now, the time for that has come. In this lecture and the next, we are actually going to see how this data segment is used for storing dynamically allocated memory locations. Now, when you look at the local variables or local arrays of a function, they are statically declared in the body of the function. We have to declare all the local variables and arrays that we want to use in a function. As a result, the memory for each of these variables and arrays are basically allocated in the activation record of the function when the function is called. And since the activation record gets pushed into the call stack and the call stack resides in the stack segment. So, basically all of this memory allocated for local variables and arrays really resides in the stack segment. And once the function ends and the control returns to the caller, the entire activation record is freed. So, all of these local variables and arrays also cease to exist once the function returns control to the caller. But what if the size of a local array that I want to use in a function is actually dependent on the input? For example, I might want to read the number of students in a class and store the marks of all of these students in an integer array. I do not know a priori how many students there are going to be in the class. I am going to seek this as an input from the user. And depending on how many students are there, I would then like to allocate an array of an appropriate size. However, if I have to declare this array statically in my program, then I must predetermine what its size is. And more often than not, what we will end up doing is to put a large value for the size of the array so that in all the situations that can arise in practice, that size suffices. However, as you will realize that this is a bit wasteful of memory because in the activation record space for that entire large conservative estimate of the array size is actually going to be stored. Here is another example. I might want to read a sequence of characters ending with dot and store it in a character array. Since I do not know a priori, how many characters I am going to read for reading the dot. Therefore, I cannot determine when I am writing the program what the right size for this character array should be. So, once again here, we might end up actually reserving space for an array of sufficiently large size such that all the character sequences that we might read can be accommodated in that large character array. But once again, this is wasteful of memory. Here is another example, a memory location that is allocated in a function may actually be required in the caller function after the called function returns. For example, I might want to call a function whose job it is to read and store a sequence of characters in a character array. And then when this function returns to the calling function, calling function must use this character array to do some other processing. Now, if the called function is going to have the character array as a local array within itself, then when this called function returns, the calling function does not have access to the character array in which the called function read and store the sequence of characters. So, in order to address problems like these, you realize that we really need a mechanism for allocating memory locations dynamically. What do I mean by dynamic memory allocation? That this allocation is actually going to happen at runtime and how much memory is going to be allocated could really depend on the values of various expressions that we are reading or computing. For example, number of students may determine the size of an array that I want to dynamically allocate for storing marks of the students. The number of characters in a name may determine the size of the array that I want to dynamically allocate to store the characters in the array. So, that is what we mean by dynamic memory allocation. The memory is actually allocated at runtime and how much memory is going to be allocated could depend on the values of various variables or expressions at the time when the memory is being allocated. So, here is a simple program which illustrates this. Here, I have an integer variable called num students and I read in its value. Here is how the part of memory allocated for this program looks like stack segment, data segment and code segment. Now, after I have read in the number of students, I might actually want to allocate an integer array A of size num students so that I can store the quiz marks of all these students in the array A. Now, if you think about it, num students is a local variable of the main function. So, therefore, at compile time, I know that I am going to need this variable, it is a type integer. So, I know exactly how much memory is going to be required for it. As a consequence, I can allocate space for this variable in the activation record of main when the function main gets called. And of course, activation record stored in the call stack in the call segment. So, these four locations may be storing the value of num students. Why are there four locations? Because each location in memory stores one byte and an integer requires four bytes for its value to be stored. Note that these locations have been allocated in the stack segment. However, if I look at this array A that I want to allocate, then the size of this array A depends on the value of num students that I am going to read in from the user. As a result, I do not know how much memory I will require at compile time. Consequently, I cannot reserve space for this array A when the activation record of main is created in the stack segment. Only after main starts executing, can I figure out what the value of num students is and only then would I know how big this array is A is going to be. But in the activation record, if I cannot store space for this array A, then where should the memory space for this array A come from? Well, it turns out that here is where the data segment also called the heap where it comes to our rescue. So, now we must figure out how do we allocate an array of size num students at runtime in the data segment. From the constructs of C++ we have seen so far, there is nothing that would allow us to do this. All the variables and arrays were allocated statically in the activation record in the stack segment when the function was called. We could not allocate memory once the function started executing, but now we actually need to do that. So, how do we do that in C++? Well, C++ actually provides a special construct for dynamically allocating memory in the heap also called the data segment and this is the construct. So, here I am going to use this special construct in C++ called new which is basically telling the computer to dynamically allocate memory on the heap and how much memory should it allocate. Here by using these square brackets and by putting num students in between, I am basically saying allocate space for an array, the square brackets denote an array and what is the size of the array that is the value of num students and each element in that array is going to be an integer. So, this is the construct that I am going to use basically dynamically allocate an array of size num students where each element in the array is an integer and this construct is actually going to return a pointer to an integer. So, therefore, the type of a which is what I am assigning the return value of this construct type of a should be in star. So, here is how things look like I have my main program in it I have num students which is our integer variable allocated on the stack segment. Since the new construct is going to return an integer pointer when I ask it to allocate space for an array. So, I have also kept a variable a which is a type integer pointer and we have seen earlier that integer pointers are basically storing addresses and if all addresses in our memory require 32 bits then I need four locations in main memory. Now, this is a local variable of main therefore space for this is going to be reserved in the stack segment in the activation record. After that I read in the number of students let us say that value is 2. So, that comes here the space reserved for num students and then I execute the statement where I am saying please give me an array of size 2 where each element in the array is an integer. Now, the space for this could not have been stored in the stack segment because I did not know the value of num students when the activation record for main was created space for this is now actually allocated from the data segment of the heap. And here you can see I have allocated space for two integers each integer takes four locations and the address of the first byte of the first of these integers is let us say x 0 to 4. So, a is going to contain the value x 0 to 4. Now, after this if I say that store 10 in the 0th element of a and store 15 in the first element of a I expect 10 and 15 to be stored in these two integers space for which has been has been reserved in the data segment of the heap. Well, but how are the addresses of a 0 and a 1 calculated here I only got the address of the starting byte of these two consecutive integers stored in the heap segment. So, how are the addresses of a 0 and a 1 going to be calculated? Well, this is not very difficult if you think about it the compiler knows that a is pointed to an integer and that integer is basically the first in an array of integers. How did the compiler know this from this statement? I am clearly saying I want to allocate an array of integers and a is going to be pointed to the first of those integers. The compiler also knows that each element of this array is of int data type the compiler also knows that each int takes four consecutive memory locations. Therefore, it is easy to see that the address of a 0 will be basically the address that is contained in a plus 0. And in general the address of a I would be the address that is contained in a plus four times I where is this four coming from because each integer in this array requires four consecutive memory locations takes up four addresses. So, this is also what is called address arithmetic we are basically adding and multiplying things here to compute the address. And once we have that address we can access the right element of the dynamically allocated array. The generic format for dynamic memory allocation is something like this dynamically allocate memory for a variable of type t. I declare a variable which is a pointed to t and then I use that variable and assign it the value that is returned the address that is returned by new t. So, I am saying give me space for a new variable of type t and the address of that is going to be of type t star and that is going to be assigned to my bar. How am I going to access the variable? This is using our usual star operator the content of operator we access it as star my bar pointer dynamically allocate memory for an array of n elements of type t. I am going to do something very similar I accept that instead of saying new t I will say new t and then an array of size n. So, basically this is saying please allocate space for an array of size n where each element in the array is of type t and the address for the first element in that array is going to be returned and therefore, the variable in which I store it must be of type t star the array elements are accessed as my array 0 through my array n minus 1. This n of course has to be an integer which tells us how many elements to allocate in the array. So, as you would notice that new returns a pointer to type t in both cases therefore, the variables here are declared to be of type t star and as you would also notice that an array of type t here my array is basically treated like a variable of type t star that can be indexed using the square bracket. Now, when you are using dynamically allocated memory there are some good programming practices that you should be aware of most often a call to new will successfully allocate the requested memory from the heap and will return you the address to the first allocated byte. However, we cannot take new for granted C++ does allow new to fail in which case it returns the zero address which is also called the null pointer therefore, you should always check new has returned the zero address before dereferencing that address this is this will actually avoid unnecessary program crashes particularly if your program is dynamically allocating too much memory and you have run out of space on the heap and this is a real issue programmers actually encountered this situation in real life. So, this is how you should do dynamic memory allocation after you allocate memory for the array you check whether it is not null and only then you access the elements of the array. So, in summary in this lecture we looked at how to dynamically allocate memory on the heap we looked at the new construct we also saw how to access dynamically allocated variables and arrays and some good programming practices when using dynamically allocated memory. Thank you.