1) Memory Allocation
2) Dynamic Memory Allocation
3) calloc Function
4) malloc Function
5) free ()
6) realloc Function
7) Memory Leak
8) Dangling Pointers
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
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
integers (ages). If there are 50 integers to be stored, the memory for remaining
integers (that has been reserved) remains useless. This was not an important matter
the programs were of small sizes. But now when the programs grow larger and use
resources of the system, it has become necessary to manage the memory in a better
The dynamic memory allocation method can be helpful in the optimal utilization of
It is better to compare both the static and dynamic allocation methods to understand
benefits of the usage of dynamic memory allocation. In static memory, when we write
things like int i, j, k ; these reserve a space for three integers in memory. Similarly
typing of char s will result in the allocation of space for 20 characters in
This type of memory allocation is static allocation. It is also known as compile
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
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
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
allocate the memory dynamically.
The programs, in which we allocate static memory, run essentially on stack. There
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
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
So this much memory has been allocated from heap and the remaining is available
programs. The program that will allocate the memory dynamically, will allocate it
Let’s have a look on the functions that can be used to allocate memory from the
Before actually allocating memory, it is necessary to understand few concepts. We
already studied these concepts in the lectures on ‘pointers’. Whenever we allocate
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
determine whether the memory allocated is an array, an integer, 20 integers or how
space is it? To over this uncertainty, we have to use pointers.
Whenever we allocate any memory from the heap, the starting position of the block
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
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
the conversion of ‘void’ into a type of pointer that can be used for native data
int, char, float etc. The operator used for casting, in C, is standard cast operator.
the name of the type in parentheses. Suppose we have a pointer ptr defined as a
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
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
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
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
in the header files stdlib.h and stddef.h. So at least one of these files must be
the program’s header to use the NULL. A NULL pointer is a special type of pointer
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
address or has a NULL value.
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
numbers while the second one is the size of the space. So we can say that we require
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
on. So if we write like
void calloc(1000, sizeof(int))
It will return a memory chunk from the heap of 1000 integers. By using
sizeof (int) we
are not concerned with the size of the integer on our machine whether it is of 4
bytes or 8
bytes. We will get automatically a chunk that can hold 1000 integers. The said memory
will be returned if a chunk of similar size is available on the heap. Secondly,
should be available on heap in continuous space. It should not be in split blocks.
function returns a pointer to the starting point of the allocated memory. It means
starting point of the chunk is gotten, then the remaining memory is available in
sequence from end to end. There cannot be gaps and holes between them. It should
single block. Now we have to see what happens when either we ask for too much
memory at a time of non-availability of enough memory on the heap or we ask for
memory that is available on the heap , but not available as a single chunk?. In
the call to calloc will fail. When a call to memory allocation functions fails,
it returns a
NULL pointer. It is important to understand that whenever we call a memory allocation
function, it is necessary to check whether the value of the pointer returned by
is NULL or not. If it is not NULL, we have the said memory. If it is NULL, it will
that either we have asked for too much memory or a single chunk of that size is
available on the heap.
Suppose, we want to use the memory got through calloc function as an integer block
have to cast it before using. It will be written as the following statement.
(int *) calloc (1000, sizeof (int)) ;
Another advantage of calloc is that whenever we allocate memory by using it. The
memory is automatically initialized to zeros. In other words it is set to zeros.
we normally declare a pointer of type which we are going to use. For example, if
going to use the memory for integers. We declare an integer pointer like
int *iptr; Then
when we allocate memory through calloc, we write it as
iptr = (int *) calloc (1000, sizeof(int)) ;
(int *) means cast the pointer returned by calloc to an integer pointer and we hold
it in the
declared integer pointer iptr. Now iptr
is a pointer to an integer that can be used to
manipulate all the integers in that memory space. You should keep in mind that after
above statement, a NULL check of memory allocation is necessary. An ‘if statement’
be used to check the success of the memory allocation. It can be written as under
if (iptr == NULL)
any error message or code to handle error ;
If a NULL is returned by the calloc, it should be treated according to the logic
so that the
program can exit safely and it should not be crashed.
The next function used for allocating memory is malloc.
The malloc function takes one argument i.e. the number of bytes to be allocated.
syntax of the function is
void * malloc (size_t size) ;
It returns a void pointer to the starting of the chunk of the memory allocated from
heap in case of the availability of that memory. If the memory is not available
fragmented (not in a sequence), malloc will return a NULL pointer. While using malloc,
we normally make use sizeof operator and a call to malloc function is written in
malloc (1000 * sizeof(int)) ;
Here * is multiplication operator and not a dereference operator of a pointer.
In the above call, we request for 1000 spaces in the memory each of the size, which
accommodate an integer. The ‘sizeof(int)’ means the number of bytes, occupied by
integer in the memory. Thus the above statement will allocate memory in bytes for
integers. If on our machine, an integer occupies 4 bytes. A 1000 * 4 (4000) bytes
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
Let’s say we have a problem that states ‘Calculate the average age of the students
class.’ The program prompts the user to enter the number of students in the class
allows the user to enter the ages of the students. Afterwards, it calculates the
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,
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
loop to get the ages of the students and store these to the memory, got through
function. We write these values of ages to the memory by using the pointer
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
screen. The advantage of this (using malloc) is that there is no memory wastage
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
Whenever we get a benefit, there is always a cost. The dynamic memory allocation
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
memory allocated is no longer in use, it should be freed to make it a part of heap
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.
ensure it, we use a function free. This function returns the
allocated memory, 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.
very important to note that whenever we allocate memory from the heap by using
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
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";
// 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 ;
Following is a sample out put of the program.
How many students are in the class ? 3
Enter the age of student 1 = 12
Enter the age of student 2 = 13
Enter the age of student 3 = 14
The average age of the class is 13
Sometimes, we have allocated a memory space for our use by malloc
function. But we
see later that some additional memory is required. For example, in the previous
where (for example) after allocating a memory for 35 students, we wanted to add
more student. So we need same type of memory to store the new entry. Now the question
arises ‘Is there a way to increase the size of already allocated memory chunk ?
same chunk be increased or not? The answer is yes. In such situations, we can reallocate
the same memory with a new size according to our requirement. The function that
reallocates the memory is realloc. The syntax of
realloc is given below.
void realloc (void * ptr, size_t size ) ;
This function enlarges the space allocated to ptr (in some previous call of calloc
malloc) to a (new) size in bytes. This function receives two arguments. First is
that is pointing to the original memory allocated already by using calloc or malloc.
second is the size of the memory which is a new size other than the previous size.
Suppose we have allocated a memory for 20 integers by the following call of malloc
a pointer iptr points to the allocated memory.
(iptr *) malloc (20 * sizeof(int)) ;
Now we want to reallocate the memory so that we can store 25 integers. We can
reallocate the same memory by the following call of realloc.
realloc (iptr, 25 * sizeof(int)) ;
There are two scenarios to ascertain the success of ‘realloc’. The first is that
the current location if possible. It is possible only if there is a memory space
contiguous to the previously allocated memory. In this way the value of the pointer
the same that means it is pointing to the same starting position, but now the memory
more than the previous one. The second way is that if such contiguous memory is
available in the current location, realloc goes back to the heap and looks for a
block of memory for the requested size. Thus it will allocate a new memory and copy
contents of the previous memory in this new allocated memory. Moreover it will set
value of the pointer iptr to the starting position of this memory. Thus iptr is
to a new memory location. The original memory is returned to the heap. In a way,
handling dynamic arrays. The size of the array can be increased during the execution.
There is another side of the picture. It may happen that we have stored the original
of iptr in some other pointer say sptr. Afterwards, we are manipulating the data
both the pointers. Then ,we use realloc for the pointer iptr. The realloc does not
contiguous memory with the original and allocates a new block of memory and points
by the pointer iptr. The original memory no longer exists now. The pointer iptr
now as it is pointing to the starting position of the new memory. But the other
is no longer valid. It is pointing to an invalid memory that has been freed and
may be is
being used some other program. If we manipulate this pointer, very strange things
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
realloc, the pointer(s) that have the value of the original pointer have been updated.
also important to check the pointer returned by realloc for NULL value. If realloc
that means that it cannot allocate the memory. In this case, it returns a NULL value.
checking NULL value, ( if realloc is successful), we should update the pointer that
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
common errors that can happen with the memory allocation.
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
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.
other words, the heap size is decreased as we had allocated memory from it despite
fact that it was never utilized. If this step of allocating memory and then destroy
pointer to this memory carries on then the size of the heap will going on to decrease.
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.
problem with memory leak is that you may be unaware of the memory leak caused by
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
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
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
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
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
happening. Then there come the very sophisticated debugging techniques by which
was found that memory is being allocated continuously without freeing and thus the
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
memory leak can happen is that suppose our main program calls a function. There,
function, a pointer iptr is declared as a pointer to an integer. Then we call calloc
malloc in the function and allocate some memory. We use this memory and goes back
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 pointing
to it no
longer exists. Now this memory is unreferenced which means it is leaked. This is
memory leak. Now if this function is being called repeatedly it means a chunk of
is being allocated and is left unreferenced each time. Thus, each time a memory
from heap will be allocated and will become useless(as this will be unreferenced)
heap size may become zero. As a programmer, it is our responsibility and a good
thumb will be that in which function the memory is allocated, it should be freed
Sometimes the logic of the program is that the memory is being allocated somewhere
is being used somewhere else. It means we allocate memory in a function and use
another function. In such situations, we should keep in mind that this all scenario
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
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.
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.
memory leakage is at operating system level. The operating system does not know
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.
is make it sure that when we allocated memory in the program this memory should
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 other side of the coin is also that if we are using dynamic memory allocation
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
Memory leak is one subtle type of error that can happen. There is another one. This
one is even more dangerous. This is dangling pointer. It has the inverse effect
memory leak. Suppose, there was a pointer that was pointing to a chunk of memory,
by some reason that memory has deallocated and has gone back to heap. The pointer
has the starting address of that chunk. Now what will happen if we try to write
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
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
some other program. This may halt the machine as the position that is being tried
written may be a critical memory position. How does this situation arise? Lets consider
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
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
processing with the help of ptr2. In the meantime, we go to exit the function. To
allocated memory we use the pointer ptr1. Thus the memory allocated goes back to
and some other program may use it. The pointer ptr2 has the address of the same
that it got from the ptr1. Now ptr2 points in a way to the memory that no longer
to the program. It has gone back to the heap. We can read the data residing at that
memory location. But now if we try to write something in that location everything
break loose. We have to be very careful. The pointer ptr2 points to no location
it is called
dangling pointer. We have to be very careful about memory leak and dangling pointer.
The dynamic memory allocation is a very useful technique. In it what memory we require
we take from the heap and use it and when it is no longer required we send it back
heap. All the programs running on our machine (which are running on modern operating
systems which are multitasking) work efficiently. They take memory of their requirement
from the memory resources and return it back after using.
The sharing is not limited to memory resources this also include printers attached
the computer. The printer resource is being used by different programs like MS WORD,
EXCEL and even may be by our program if we want to print something. We are also
sharing the other resources like keyboard, monitor, and hard disk etc. But in terms
dynamic usage we are also sharing the memory. Our program in a way has to be a good
neighbor to use the memory. It should use memory as long as it required and then
use it should give back this memory to the heap so that other programs can use this
resource. So remember to free the memory it is as important as the allocation of
So what interesting things we can do with memory allocation. A common thing in file
handling is to copy a file. Our hard disks being electro mechanical devices are
It is very expensive to access them. So while reading from them or writing to them
that a big chunk should be written or read from them so that fewest disk writes
reads should occur. In order to do that, think combining dynamic memory allocation
disk read and write. Suppose we have to copy a file. We can easily find out the
size of the
file in bytes. Now we allocate this number of bytes from heap. If this size of memory
successfully allocated, we can say for a single file read of this allocated size.
the entire file will be read to memory. This way we read a whole file with one command.
Similarly, we can use a command to write the whole file. In this way we can be assured
that we are doing the more efficient disk access.
Following are the examples, which demonstrate the use of dynamic memory allocation.
In the following simple example we allocate a memory which is pointing by a character
pointer. We copy an array of characters to that location and display it. After that
that memory before exiting the program.
//This program allocates memory dynamically and then frees it after use.
char s1 = "This is a sentence";
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";
/* Use a nonzero return to indicate an error has occurred */
cout << "s1: “ << s1 << endl;
cout << "s2: “ << s2 << endl;
The output of the program is given below.
S1: This is a sentence
S2: This is a sentence
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
//store a certain number of a structure.
Employee *workers, *wpt;
cout <<"How many employees do you want\n“ ;
cin >> num;
// the pointer workers gets the starting address of the memory if allocated
workers = (Employee *) malloc(num * sizeof(Employee));
if (workers == NULL)
cout << "Unable to allocate space for employees\n";
// A nonzero return is usually used to indicate an error
cout << “Memory for “ << num << “ employees has allocated successfully” ;
//now free the allocated memory
A sample output of the program is as below.
How many employees do you want
Memory for 235 employees has allocated successfully
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
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
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
the memory allocated? Yes, you will see that the size has decreased. It proves that
heap is being shared between all of the programs running on that machine at that
Dynamic memory allocation is a very efficient usage of computer resources as oppose
static memory allocation. The benefit of static memory is that its usage is very
clean, there are no errors. But disadvantage is that there are chances of wastage
The dynamic memory allocation is very efficient in terms of resources but added
is that freeing the memory is necessary, pointers management is necessary. You should
avoid the situations that create memory leakage and dangling pointers.
• Using dynamic memory is more efficient then the static memory.
• Immediately after a memory allocation call, check whether the memory has
• Whenever possible free the allocated memory in the same function.
• Be careful about memory management to prevent memory leakage and dangling
• Before exiting the program, make sure that the allocated memory has freed.