ZeePedia

Dynamic Memory Allocation, calloc, malloc, realloc Function, Dangling Pointers

<< Pre-processor, include directive, define directive, Other Preprocessor Directives, Macros
History of C/C++, Structured Programming, Default Function Arguments >>
img
CS201 ­ Introduction to Programming
Lecture Handout
Introduction to Programming
Lecture No. 24
Reading Material
Deitel & Deitel - C++ How to Program
Chapter 15, 18
15.3, 18.10
Summary
1)
Memory Allocation
2)
Dynamic Memory Allocation
3)
calloc Function
4)
malloc Function
5)
free ()
6)
realloc Function
7)
Memory Leak
8)
Dangling Pointers
9)
Examples
10)
Exercise
11)
Tips
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
Page 295
img
CS201 ­ Introduction to Programming
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.
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
Page 296
img
CS201 ­ Introduction to Programming
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))
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, this memory
should be available on heap in continuous space. It should not be in split blocks. The
function returns a pointer to the starting point of the allocated memory. It means that if
starting point of the chunk is gotten, then the remaining memory is available in a
sequence from end to end. There cannot be gaps and holes between them. It should be a
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 this case,
the call to calloc will fail. When a call to memory allocation functions fails, it returns a
Page 297
img
CS201 ­ Introduction to Programming
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 the function
is NULL or not. If it is not NULL, we have the said memory. If it is NULL, it will mean
that either we have asked for too much memory or a single chunk of that size is not
available on the heap.
Suppose, we want to use the memory got through calloc function as an integer block We
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. For casting
we normally declare a pointer of type which we are going to use. For example, if we are
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 the
above statement, a NULL check of memory allocation is necessary. An `if statement' can
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.
malloc Function
The malloc function takes one argument i.e. the number of bytes to be allocated. The
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 the
heap in case of the availability of that memory. If the memory is not available or is
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 the
following way.
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 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.
Page 298
img
CS201 ­ Introduction to Programming
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, 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.
Page 299
img
CS201 ­ Introduction to Programming
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 ;
}
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
Page 300
img
CS201 ­ Introduction to Programming
Enter the age of student 3 = 14
The average age of the class is 13
realloc Function
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 example,
where (for example) after allocating a memory for 35 students, we wanted to add one
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 ? Can the
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 or
malloc) to a (new) size in bytes. This function receives two arguments. First is the pointer
that is pointing to the original memory allocated already by using calloc or malloc. The
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 and
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 it extends
the current location if possible. It is possible only if there is a memory space available
contiguous to the previously allocated memory. In this way the value of the pointer iptr is
the same that means it is pointing to the same starting position, but now the memory is
more than the previous one. The second way is that if such contiguous memory is not
available in the current location, realloc goes back to the heap and looks for a contiguous
block of memory for the requested size. Thus it will allocate a new memory and copy the
contents of the previous memory in this new allocated memory. Moreover it will set the
value of the pointer iptr to the starting position of this memory. Thus iptr is now pointing
to a new memory location. The original memory is returned to the heap. In a way, we are
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 value
of iptr in some other pointer say sptr. Afterwards, we are manipulating the data through
both the pointers. Then ,we use realloc for the pointer iptr. The realloc does not find
contiguous memory with the original and allocates a new block of memory and points it
by the pointer iptr. The original memory no longer exists now. The pointer iptr is valid
now as it is pointing to the starting position of the new memory. But the other pointer sptr
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 can
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
Page 301
img
CS201 ­ Introduction to Programming
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 pointing to it no
longer exists. Now this memory is unreferenced which means it is leaked. This is a
Page 302
img
CS201 ­ Introduction to Programming
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
Page 303
img
CS201 ­ Introduction to Programming
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 ptr1. Thus the memory allocated goes back to heap
and some other program may use it. The pointer ptr2 has the address of the same memory
that it got from the ptr1. Now ptr2 points in a way to the memory that no longer belongs
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 might
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 to the
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 with
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 of
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 after
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 memory.
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 very slow.
It is very expensive to access them. So while reading from them or writing to them we try
that a big chunk should be written or read from them so that fewest disk writes and disk
reads should occur. In order to do that, think combining dynamic memory allocation with
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 is
successfully allocated, we can say for a single file read of this allocated size. This means
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.
Examples
Following are the examples, which demonstrate the use of dynamic memory allocation.
Example 1
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 we free
that memory before exiting the program.
//This program allocates memory dynamically and then frees it after use.
#include <iostream.h>
Page 304
img
CS201 ­ Introduction to Programming
#include <stdlib.h>
#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;
};
Page 305
img
CS201 ­ Introduction to Programming
int main()
{
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
Page 306
img
CS201 ­ Introduction to Programming
·
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 dangling
pointers.
·
Before exiting the program, make sure that the allocated memory has freed.
Page 307
Table of Contents:
  1. What is programming
  2. System Software, Application Software, C language
  3. C language: Variables, Data Types, Arithmetic Operators, Precedence of Operators
  4. C++: Examples of Expressions, Use of Operators
  5. Flow Charting, if/else structure, Logical Operators
  6. Repetition Structure (Loop), Overflow Condition, Infinite Loop, Properties of While loop, Flow Chart
  7. Do-While Statement, for Statement, Increment/decrement Operators
  8. Switch Statement, Break Statement, Continue Statement, Rules for structured Programming/Flow Charting
  9. Functions in C: Structure of a Function, Declaration and Definition of a Function
  10. Header Files, Scope of Identifiers, Functions, Call by Value, Call by Reference
  11. Arrays: Initialization of Arrays, Copying Arrays, Linear Search
  12. Character Arrays: Arrays Comparisonm, Sorting Arrays Searching arrays, Functions arrays, Multidimensional Arrays
  13. Array Manipulation, Real World Problem and Design Recipe
  14. Pointers: Declaration of Pointers, Bubble Sort Example, Pointers and Call By Reference
  15. Introduction, Relationship between Pointers and Arrays, Pointer Expressions and Arithmetic, Pointers Comparison, Pointer, String and Arrays
  16. Multi-dimensional Arrays, Pointers to Pointers, Command-line Arguments
  17. String Handling, String Manipulation Functions, Character Handling Functions, String Conversion Functions
  18. Files: Text File Handling, Output File Handling
  19. Sequential Access Files, Random Access Files, Setting the Position in a File, seekg() and tellg() Functions
  20. Structures, Declaration of a Structure, Initializing Structures, Functions and structures, Arrays of structures, sizeof operator
  21. Bit Manipulation Operators, AND Operator, OR Operator, Exclusive OR Operator, NOT Operator Bit Flags Masking Unsigned Integers
  22. Bitwise Manipulation and Assignment Operator, Programming Constructs
  23. Pre-processor, include directive, define directive, Other Preprocessor Directives, Macros
  24. Dynamic Memory Allocation, calloc, malloc, realloc Function, Dangling Pointers
  25. History of C/C++, Structured Programming, Default Function Arguments
  26. Classes and Objects, Structure of a class, Constructor
  27. Classes And Objects, Types of Constructors, Utility Functions, Destructors
  28. Memory Allocation in C++, Operator and Classes, Structures, Function in C++,
  29. Declaration of Friend Functions, Friend Classes
  30. Difference Between References and Pointers, Dangling References
  31. Operator Overloading, Non-member Operator Functions
  32. Overloading Minus Operator, Operators with Date Class, Unary Operators
  33. Assignment Operator, Self Assignmentm, Pointer, Conversions
  34. Dynamic Arrays of Objects, Overloading new and delete Operators
  35. Source and Destination of streams, Formatted Input and Output, Buffered Input/Output
  36. Stream Manipulations, Manipulators, Non Parameterized Manipulators, Formatting Manipulation
  37. Overloading Insertion and Extraction Operators
  38. User Defined Manipulator, Static keyword, Static Objects
  39. Pointers, References, Call by Value, Call by Reference, Dynamic Memory Allocation
  40. Advantages of Objects as Class Members, Structures as Class Members
  41. Overloading Template Functions, Template Functions and Objects
  42. Class Templates and Nontype Parameters, Templates and Static Members
  43. Matrices, Design Recipe, Problem Analysis, Design Issues and Class Interface
  44. Matrix Constructor, Matrix Class, Utility Functions of Matrix, Input, Transpose Function
  45. Operator Functions: Assignment, Addition, Plus-equal, Overloaded Plus, Minus, Multiplication, Insertion and Extraction