Memory Allocation-Introduction To Programming-Lecture Notes, Study notes of Computer Programming

A program is a precise sequence of steps to solve a particular problem. This course includes basic programming structure like loops, operator, memory allocation, reference, pointers etc. It teaches how to be a good programmer. This lecture handout is about: Memory, Allocation, Dynamic, Errors, Programming, Integers, Arrays, Resources, Required, Static, Functions, Expression, Pointer, Null

Typology: Study notes

2011/2012

Uploaded on 08/06/2012

anchal
anchal 🇮🇳

4.6

(9)

95 documents

1 / 12

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
280
Memory Allocation
After having a thorough discussion on static memory allocation in the previous
lectures, we will now talk about dynamic memory allocation. In this lecture, the topics
being dilated upon include- advantages and disadvantages of these both types of
memory allocation and the common errors, which usually take place while
programming with dynamic memory allocation. Let’s first talk about the dynamic
memory allocation.
Dynamic Memory Allocation
Earlier, whenever we declared arrays, the size of the arrays was predefined. For
example we declared an array of size 100 to store ages of students. Besides, we need
20, 25 or 50 number of students to store their ages. The compiler reserves the memory
to store 100 integers (ages). If there are 50 integers to be stored, the memory for
remaining 50 integers (that has been reserved) remains useless. This was not an
important matter when the programs were of small sizes. But now when the programs
grow larger and use more resources of the system, it has become necessary to manage
the memory in a better way. The dynamic memory allocation method can be helpful
in the optimal utilization of the system.
It is better to compare both the static and dynamic allocation methods to understand
the benefits of the usage of dynamic memory allocation. In static memory, when we
write the things like int i, j, k ; these reserve a space for three integers in memory.
Similarly the typing of char s[20] will result in the allocation of space for 20
characters in the memory. This type of memory allocation is static allocation. It is also
known as compile time allocation. This memory allocation is defined at the time when
we write the program while exacting knowing how much memory is required.
Whenever, we do not know in advance how much memory space would be required,
it is better to use dynamic memory allocation. For example if we want to calculate the
average age of students of a class. Instead of declaring an array of large number to
allocate static memory, we can ask number of students in the class and can allocate
memory dynamically for that number. The C language provides different functions to
allocate the memory dynamically.
The programs, in which we allocate static memory, run essentially on stack. There is
another part of memory, called heap. The dynamic memory allocation uses memory
from the heap. All the programs executing on the computer are taking memory from it
for their use according to the requirement. Thus heap is constantly changing in size.
Windows system may itself use memory from this heap to run its processes like word
processor etc. So this much memory has been allocated from heap and the remaining
is available for our programs. The program that will allocate the memory
dynamically, will allocate it from the heap.
Let’s have a look on the functions that can be used to allocate memory from the heap.
Before actually allocating memory, it is necessary to understand few concepts. We
have already studied these concepts in the lectures on ‘pointers’. Whenever we
allocate a memory what will we get? We need to be careful about that. When we say
int i, a space is reserved for an integer and it is labeled as i. Here in dynamic
memory, the situation is that the memory will be allocated during the execution of the
program. It is difficult to determine whether the memory allocated is an array, an
integer, 20 integers or how much space is it? To over this uncertainty, we have to use
pointers.
docsity.com
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download Memory Allocation-Introduction To Programming-Lecture Notes and more Study notes Computer Programming in PDF only on Docsity!

Memory Allocation

After having a thorough discussion on static memory allocation in the previous lectures, we will now talk about dynamic memory allocation. In this lecture, the topics being dilated upon include- advantages and disadvantages of these both types of memory allocation and the common errors, which usually take place while programming with dynamic memory allocation. Let’s first talk about the dynamic memory allocation.

Dynamic Memory Allocation

Earlier, whenever we declared arrays, the size of the arrays was predefined. For example we declared an array of size 100 to store ages of students. Besides, we need 20, 25 or 50 number of students to store their ages. The compiler reserves the memory to store 100 integers (ages). If there are 50 integers to be stored, the memory for remaining 50 integers (that has been reserved) remains useless. This was not an important matter when the programs were of small sizes. But now when the programs grow larger and use more resources of the system, it has become necessary to manage the memory in a better way. The dynamic memory allocation method can be helpful in the optimal utilization of the system. It is better to compare both the static and dynamic allocation methods to understand the benefits of the usage of dynamic memory allocation. In static memory, when we write the things like int i, j, k ; these reserve a space for three integers in memory. Similarly the typing of char s[20] will result in the allocation of space for 20 characters in the memory. This type of memory allocation is static allocation. It is also known as compile time allocation. This memory allocation is defined at the time when we write the program while exacting knowing how much memory is required. Whenever, we do not know in advance how much memory space would be required, it is better to use dynamic memory allocation. For example if we want to calculate the average age of students of a class. Instead of declaring an array of large number to allocate static memory, we can ask number of students in the class and can allocate memory dynamically for that number. The C language provides different functions to allocate the memory dynamically. The programs, in which we allocate static memory, run essentially on stack. There is another part of memory, called heap. The dynamic memory allocation uses memory from the heap. All the programs executing on the computer are taking memory from it for their use according to the requirement. Thus heap is constantly changing in size. Windows system may itself use memory from this heap to run its processes like word processor etc. So this much memory has been allocated from heap and the remaining is available for our programs. The program that will allocate the memory dynamically, will allocate it from the heap. Let’s have a look on the functions that can be used to allocate memory from the heap. Before actually allocating memory, it is necessary to understand few concepts. We have already studied these concepts in the lectures on ‘pointers’. Whenever we allocate a memory what will we get? We need to be careful about that. When we say int i, a space is reserved for an integer and it is labeled as i. Here in dynamic memory, the situation is that the memory will be allocated during the execution of the program. It is difficult to determine whether the memory allocated is an array, an integer, 20 integers or how much space is it? To over this uncertainty, we have to use pointers.

docsity.com

Whenever we allocate any memory from the heap, the starting position of the block of the memory allocated is returned as an address that is kept in a pointer. Then we manipulate the memory with the help of this pointer. We have to introduce a new type of a pointer, called ‘ void’. We have used the pointers of type- int, char, float etc. For these, we write like *int i ; which means i is a pointer to an integer. In this case, the compiler automatically knows that i has the address of the memory, occupied by an integer. Same thing applies when we write *char s. It means s is a pointer to a character data type. So every pointer we have used so far pointed to a specific data type. The functions used for dynamic memory allocation, provide a chunk of memory from heap. The function does not know for what data type this chunk of memory will be used? It returns a pointer of type void. A pointer ptr of type void is declared as under. *void ptr ; The ‘void’ is a special type of pointers. We have to cast it before its use. The cast means the conversion of ‘void’ into a type of pointer that can be used for native data type like int, char, float etc. The operator used for casting, in C, is standard cast operator. We write the name of the type in parentheses. Suppose we have a pointer ptr defined as a void pointer like *void ptr ; Before using this pointer to point to a set of integers, we will at first cast it. It means that it will be converted into a type of a pointer to an integer. The syntax of doing this casting is simple and is given below. ( int * ) ptr ; Here both int and * are written in parentheses. The int is the data type into which we are converting a void pointer ptr. Now ptr is a pointer to an integer. Similarly, we can write char, float and double instead of ‘int’, to convert ptr into a pointer to char, float and double respectively. Casting is very useful in dynamic memory allocation. The memory allocation functions return a chunk of memory with a pointer of type void. While storing some type of data , we at first, cast the pointer to that type of data before its usage. It is an error to try to use the void pointer and dereference it. In case, we write *ptr and use it in an expression, there will be an error. So we have to cast a void pointer before its use. Another interesting aspect of pointer is the NULL value. Whenever we define a pointer or declare a pointer, normally, it is initialized to a NULL value. NULL has been defined in the header files stdlib.h and stddef.h. So at least one of these files must be included in the program’s header to use the NULL. A NULL pointer is a special type of pointer with all zeros value. All zeros is an invalid memory address. We can’t use it to store data or to read data from it. It is a good way to ascertain whether a pointer is pointing to a valid address or has a NULL value.

calloc Function

The syntax of the calloc function is as follows. *void calloc (size_t n, size_t el_size) This function takes two arguments. The first argument is the required space in terms of numbers while the second one is the size of the space. So we can say that we require n elements of type int. We have read a function sizeof. This is useful in the cases where we want to write a code that is independent of the particular machines that we are running on. So if we write like void calloc(1000, sizeof(int))

docsity.com

In the above call, we request for 1000 spaces in the memory each of the size, which can accommodate an integer. The ‘sizeof(int)’ means the number of bytes, occupied by an integer in the memory. Thus the above statement will allocate memory in bytes for 1000 integers. If on our machine, an integer occupies 4 bytes. A 1000 * 4 (4000) bytes of memory will be allocated. Similarly if we want memory for 1000 characters or 1000 floats, the malloc function will be written as malloc (1000 * sizeof(char)) ; and malloc (1000 * sizeof(float)) ; respectively for characters and floats. So in general, the syntax of malloc will be. malloc (n * sizeof ( datatype )) ; where ‘n’ represents the numbers of required data type. The malloc function differs from calloc in the way that the space allocated by malloc is not initialized and contains any values initially. Let’s say we have a problem that states ‘Calculate the average age of the students in your class.’ The program prompts the user to enter the number of students in the class and also allows the user to enter the ages of the students. Afterwards, it calculates the average age. Now in the program, we will use dynamic memory. At first, we will ask the user ‘How many students are in the class? The user enters the number of students. Let’s suppose, the number is 35. This number is stored in a variable say ‘ numStuds’. We will get the age of students in whole numbers so the data type to store age will be int. Now we require a memory space where we can store a number of integers equal to the value stored in numStuds. We will use a pointer to a memory area instead of an array. So we declare a pointer to an integer. Suppose we call it iptr. Now we make a call to calloc or malloc function. Both of them are valid. So we write the following statement *iptr = (int ) malloc (numStuds * sizeof (int)) ; Now we immediately check iptr whether it has NULL value. If the value of iptr is not NULL, it will mean that we have allocated the memory successfully. Now we write a loop to get the ages of the students and store these to the memory, got through malloc function. We write these values of ages to the memory by using the pointer iptr with pointer arithmetic. A second pointer say sptr can be used for pointer arithmetic so that the original pointer iptr should remain pointing to the starting position of the memory. Now simply by incrementing the pointer sptr , we get the ages of students and store them in the memory. Later, we perform other calculations and display the average age on the screen. The advantage of this (using malloc) is that there is no memory wastage as there is no need of declaring an array of 50 or 100 students first and keep the ages of 30 or 35 students in that array. By using dynamic memory, we accurately use the memory that is required.

free ()

Whenever we get a benefit, there is always a cost. The dynamic memory allocation has also a cost. Here the cost is incurred in terms of memory management. The programmer itself has to manage the memory. It is the programmer’s responsibility that when the memory allocated is no longer in use, it should be freed to make it a part of heap again. This will help make it available for the other programs. As long as the memory is allocated for a program, it is not available to other programs for use. So it is programmer’s responsibility to free the memory when the program has done with it. To ensure it, we use a function free. This function returns the allocated memory,

docsity.com

got through calloc or malloc, back to the heap. The argument that is passed to this function is the pointer through which we have allocated the memory earlier. In our program, we write free (iptr) ; By this function, we call the memory allocated by malloc and pointed by the pointer iptr is freed. It goes back to the heap and becomes available for use by other programs. It is very important to note that whenever we allocate memory from the heap by using calloc or malloc, it is our responsibility to free the memory when we have done with it.

Following is the code of the program discussed above.

//This program calculates the average age of a class of students //using dynamic memory allocation

#include <iostream.h> #include <stdlib.h> #include <string.h>

int main( ) {

int numStuds, i, totalAge, *iptr, *sptr; cout <<"How many students are in the class? " ; cin >> numStuds; // get the starting address of the allocated memory in pointer iptr iptr = (int *) malloc(numStuds * sizeof(int)); //check for the success of memory allocation if (iptr == NULL) { cout << "Unable to allocat space for " << numStuds << " students\n"; return 1; // A nonzero return is usually used to indicate an error } sptr = iptr ; //sptr will be used for pointer arithmetic/manipulation i = 1 ; totalAge = 0 ; //use a loop to get the ages of students for (i = 1 ; i <= numStuds ; i ++) { cout << "Enter the age of student " << i << " = " ; cin >> *sptr ; totalAge = totalAge + *sptr ; sptr ++ ; } cout << "The average age of the class is " << totalAge / numStuds << endl; //now free the allocated memory, that was pointed by iptr free (iptr) ; sptr = NULL ; }

docsity.com

happen. The program may crash or the computer may halt. We don’t know what can happen. Now it becomes the programmer’s responsibility again to make it sure that after realloc, the pointer(s) that have the value of the original pointer have been updated. It is also important to check the pointer returned by realloc for NULL value. If realloc fails, that means that it cannot allocate the memory. In this case, it returns a NULL value. After checking NULL value, ( if realloc is successful), we should update the pointer that was referencing the same area of the memory.

We have noticed while getting powers of dynamic memory allocation, we face some dangerous things along with it. These are real problems. Now we will talk about the common errors that can happen with the memory allocation.

Memory Leak

The first problem may be the unreferenced memory. To understand this phenomenon, suppose, we allocate memory from heap and there is a pointer pointing to this memory. However, it is found that this pointer does not exist any more in our program. What will happen to the memory we had allocated. That chunk of memory is now unreferenced. Nothing is pointing to that memory. As there is no pointer to this memory, our program can’t use it. Moreover, no other program can use it. Thus, this memory goes waste. In other words, the heap size is decreased as we had allocated memory from it despite the fact that it was never utilized. If this step of allocating memory and then destroy the pointer to this memory carries on then the size of the heap will going on to decrease. It may become of zero size. When there is no memory on heap, the computer will stop running and there may be a system crash. This situation is called a memory leak. The problem with memory leak is that you may be unaware of the memory leak caused by the program. Suppose there is 128 MB memory available on heap. We run our program that allocates 64 KB memory and terminates without freeing this memory. It does not effect but when if the memory is being allocated in a loop, that, suppose runs 1000 times and in each loop it allocates 64 KB of memory with out freeing the previous one. Then this program will try to allocate 64 * 1000 KB memory and at a certain point there will be no memory available and the program will crash. The same thing (no memory available) happens to other programs and the whole system locks up. So memory leak is a very serious issue. This bug of memory leak was very common in the operating systems. This was a common thing, that the system was running well and fine for 4-5 hours and then it halted suddenly. Then the user had to reboot the system. When we reboot a system all the memory is refreshed and is available on the heap. People could not understand what was happening. Then there come the very sophisticated debugging techniques by which this was found that memory is being allocated continuously without freeing and thus the heap size becomes to zero. Thus memory is leaking out and it is no longer useable.

Let us see how does this happen and what we can do to prevent it. A simple way in which memory leak can happen is that suppose our main program calls a function. There, in the function, a pointer iptr is declared as a pointer to an integer. Then we call calloc or malloc in the function and allocate some memory. We use this memory and goes back to the main function without freeing this memory. Now as the pointer iptr has the function scope it is destroyed when the function exits. It is no longer there but the memory allocated remains allocated and is not being referenced as the pointer

docsity.com

pointing to it no longer exists. Now this memory is unreferenced which means it is leaked. This is a memory leak. Now if this function is being called repeatedly it means a chunk of memory is being allocated and is left unreferenced each time. Thus, each time a memory chunk from heap will be allocated and will become useless(as this will be unreferenced) and the heap size may become zero. As a programmer, it is our responsibility and a good rule of thumb will be that in which function the memory is allocated, it should be freed in the same function. Sometimes the logic of the program is that the memory is being allocated somewhere and is being used somewhere else. It means we allocate memory in a function and use it in another function. In such situations, we should keep in mind that this all scenario is memory management and we have to take care of it. We allocate memory in a function and cannot free it here because it is being used in some other function. So we should have a sophisticated programming to make it sure that whenever we allocate a memory it should be freed somewhere or the other. Now it is not to do just with function calls. It also has to do when the program ends. Let consider, our program is running and we allocate memory somewhere and somewhere else there is a condition on which the program exits. If we exit without freeing the memory then there is a memory leak. The memory leakage is at operating system level. The operating system does not know that this memory is not being used by anyone now. From its aspect, some program is using this memory. So whenever we write program we should free the allocated memory wherever it is allocated. But at the program exit points we should do some task. This task is make it sure that when we allocated memory in the program this memory should be freed at exit points. The second necessary thing is that after freeing the memory, explicitly assign NULL to the pointer. Its benefit is that this pointer can be checked if it is pointing to some memory. Whereas we do get this considerable flexibility in doing dynamic memory management, it is also our responsibility for freeing all the memory that we allocated from the heap. The other side of the coin is also that if we are using dynamic memory allocation in our program then we should check immediately if we have got memory. If we did not get (allocated) memory then exit the program in a good and safe way rather than to crash the program.

Dangling Pointers

Memory leak is one subtle type of error that can happen. There is another one. This other one is even more dangerous. This is dangling pointer. It has the inverse effect of the memory leak. Suppose, there was a pointer that was pointing to a chunk of memory, now by some reason that memory has deallocated and has gone back to heap. The pointer still has the starting address of that chunk. Now what will happen if we try to write something in the memory using this pointer? Some very strange thing can happen. This can happen that when we have put that memory back to heap some other program starts to use that memory. Operating system itself might have started using that memory. Now our program, by using that pointer try to write something in the memory that is being used by some other program. This may halt the machine as the position that is being tried to written may be a critical memory position. How does this situation arise? Lets consider a case. We have two pointers ptr1 and ptr2. These are pointers to integers. We allocate some memory from the heap by using calloc or malloc. The pointer ptr1 is pointing to the starting point of this allocated memory. To use this memory through a variable pointer we use the pointer ptr2. At start, we put the address of ptr1 in ptr2 and then do our processing with the help of ptr2. In the meantime, we go to exit the function. To free the allocated memory we use the pointer

docsity.com

#include <string.h>

int main() { char s1[] = "This is a sentence"; char *s2; s2 = (char ) malloc(strlen(s1) + 1); / Remember that stings are terminated by the null terminator, "\0', and the strlen returns the length of a string not including the terminator / if (s2 == NULL) { cout << "Error on malloc"; return 1; / Use a nonzero return to indicate an error has occurred */ }

strcpy(s2,s1);

cout << "s1: “ << s1 << endl; cout << "s2: “ << s2 << endl; free(s2); return 0; }

The output of the program is given below. S1: This is a sentence S2: This is a sentence

Example 2 Following is another example that allocates a memory dynamically according to the requirement and displays a message for the failure or success of the memory allocation.

// This program shows the dynamic allocation of memory according to the requirement to //store a certain number of a structure.

#include <iostream.h> #include <stdlib.h> #include <string.h>

struct Employee { char name[40]; int id; };

int main() {

docsity.com

Employee *workers, *wpt; int num; cout <<"How many employees do you want\n“ ; cin >> num; // the pointer workers gets the starting address of the memory if allocated successfully workers = (Employee *) malloc(num * sizeof(Employee)); if (workers == NULL) { cout << "Unable to allocate space for employees\n"; return 1; // A nonzero return is usually used to indicate an error } cout << “Memory for “ << num << “ employees has allocated successfully” ; //now free the allocated memory free(workers) ; } A sample output of the program is as below. How many employees do you want 235 Memory for 235 employees has allocated successfully

Exercise

As an exercise, you can find the maximum available memory from the heap on your computer. You can do this by using a loop in which first time you allocate a certain number of bytes(say 10000). If it is successfully allocated then free it and in the next iteration allocate twice of the previous size of memory. Thus we can find the maximum amount of memory available. Suppose you find that 2MB memory is available. Then run some other applications like MS WORD, MS EXCEL etc. Now again run your program and find out the size of the memory available now. Is there any difference in the size of the memory allocated? Yes, you will see that the size has decreased. It proves that the heap is being shared between all of the programs running on that machine at that time.

Dynamic memory allocation is a very efficient usage of computer resources as oppose to static memory allocation. The benefit of static memory is that its usage is very neat and clean, there are no errors. But disadvantage is that there are chances of wastage of resources. The dynamic memory allocation is very efficient in terms of resources but added baggage is that freeing the memory is necessary, pointers management is necessary. You should avoid the situations that create memory leakage and dangling pointers.

Tips

 Using dynamic memory is more efficient then the static memory.  Immediately after a memory allocation call, check whether the memory has allocated successfully.  Whenever possible free the allocated memory in the same function.  Be careful about memory management to prevent memory leakage and

docsity.com