Dynamic Memory Allocation
Dynamic Memory Allocation
TABLE OF CONTENTS
1. Acknowledgement 2
2. Introduction 4
3. Topic Introduction 5
8. Advantages of Dynamic 16
Memory Allocation
9. Disadvantages of Dynamic 16
Memory Allocation
10. References 18
3|Page
INTRODUCTION
As it is clear from the name of the topic, the topic deals with the functions associated with
dynamic memory allocation. This is my attempt to provide all the information as a zest or
summary. I have tried to explain each and every term associated with dynamic memory
allocation as far as possible. I hope that the reader will be able to know the fundamentals of
dynamic memory allocation after reading this document.
4|Page
1. TOPIC INTRODUCTION:
After listening the word “Dynamic Memory Allocation” the first thing which strikes our
mind is “Memory Allocation”. What is memory allocation???
The term “Memory Allocation” refers to the process of reserving memory for the variables
and functions used in a program i.e. whenever we run a program , first memory is reserved
for it either statically or dynamically which is utilised by the program variables and functions.
(a) STATIC MEMORY ALLOCATION: - Static memory allocation means that memory
for program is reserved at the compile time i.e. when the program is compiled. It would
become more clear from the following program written in C:-
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <alloc.h>
void main()
{
clrscr()
int arr[5],i; Here memory for arr[5]and i is allocated statically
i. e. at compile time.
for(i=0;i<5;i++)
{
printf(“\n Enter the number”);
scanf(“%d”,&arr[i]);
}
scanf(“%d\t”,&arr[i]);
}
getch();
}
Void main()
{
char *line;
int linelen = 100;
line = malloc(linelen); Here 100 bytes are allocated at run time
printf(“\n ENTER A LINE”)
getline(line, linelen);
getch();
}
The key idea is to regard all the available memory as a large global pool that can be used for
any purpose whatsoever. When you need memory, you ask for just the amount you need; it is
given to you from the global pool and is marked as being no longer `free' so that a subsequent
request for memory does not allocate this same block again for a different purpose. Memory
allocation is done by some sort of procedure call; in C, malloc(n) allocates a block of
memory of size n bytes.
It is your responsibility to return memory to the global pool when you are finished with it;
when you do so it will be marked `free' again and be available for other uses (you might get it
again the next time you request some memory).
To continue, we imagine that all the available memory is one large array to be used as a
global pool:
6|Page
We use gray shading to indicate the regions of memory that belong to the global pool, i.e.
which are free. At present, all of it is free.
Now, if the user needs memory to store the name JOE, he must requests enough space to
store the string "JOE". As it happens, in C, all strings must be terminated by a special
character called `NULL' whose code is 0 and which is written \0. Therefore, the user needs 3
bytes to store J, O, and E, plus an additional byte for NULL. Thus he requests 4 bytes by
calling malloc(4).
Suppose he is given the first 4 bytes from the pool; then memory would now look like this:
The memory allocator keeps track of what memory is free and what memory has been
allocated. It now knows that the 4 bytes which it gave to the user are no longer free; they are
no longer in the global pool. This we represent visually by the fact that these bytes are no
longer shaded gray.
The question marks now visible indicate that we do not know in what state the bits of this
block of memory really are.
A memory allocator typically makes no guarantee about this issue. The block of memory
which is allocated and returned to the user must be presumed to contain garbage. It is the
responsibility of the user to then initialize this block properly so that its contents become
meaningful.
In the present case, the user simply copies the string "JOE" into it:
You can see that it takes up exactly the space that is needed for it. The rest of memory can be
used to store the other names.
Suppose the next name is MARYJANE: 8 characters + 1 NULL. The user asks for 9 bytes
and copies the string into them:
You may wonder why this new block is not contiguous with the previous one. The reason is
that, in general, it won't be. This, mainly for two reasons:
7|Page
The memory allocator might very well decide to allocate the next block from some
other part of memory.
Often, the memory allocator needs to allocate a little bit more than the user requested
so that it can store, just before the user's block, some information about it, such as its
size. Thus, when the user wants to `free' the block, the memory allocator can find out
how big it is and return the correct number of memory locations to the global pool.
where the arrows point to the start of the blocks allocated to the user. In the following, we are
going to ignore these details.
What to remember
The memory allocator keeps track of what is allocated and what is free.
When we obtain memory from the global pool, we must assume that it contains
garbage, and properly initialize it.
We must not assume that successive requests will allocate contiguous memory blocks.
If the user now says he is finished with the name JOE, the corresponding block of memory is
returned to the global pool and becomes free:
(a). MALLOC ( )
(b). CALLOC ( )
(c). FREE ( )
(d). REALLOC ( )
8|Page
(a). MALLOC( ) : The function malloc is used to allocate a certain amount of memory
during the execution of a program. The malloc function will request a block of memory from
the heap. If the request is granted, the operating system will reserve the requested amount of
memory. When the amount of memory is not needed anymore, you must return it to the
operating system by calling the function free. Main features of malloc() function have been
described below
Example :
int*ptr;
ptr=malloc(10*sizeof(int));
Since type of pointer it returns is void, so typecasting is required to change
the return pointer type.
Example of typecasting:
int*ptr;
ptr=(int*)malloc(10*sizeof(int));
#include<stdio.h>
int main()
{
int *ptr_one;
if (ptr_one == 0)
{
printf("ERROR: Out of memory\n");
return 1;
}
*ptr_one = 25;
printf("%d\n", *ptr_one);
free(ptr_one);
9|Page
return 0;
}
(b).CALLOC( ) : The function calloc() will allocate a block of memory for an array. All of
these elements are size bytes long. During the initialization all bits are set to zero. Main
features of calloc() function are described below.
Example :
int*ptr;
ptr = (int*)calloc(10,2);
#include<stdio.h>
#include<stdlib.h>
int main ()
{
int a,n;
int * ptr_data;
free (ptr_data);
return 0;
}
(c). FREE( ) : If you have allocated a memory block with the functions malloc(), calloc() or
realloc() then you need to free the previously allocated memory. Its main features are:s
#include<stdio.h>
#include<stdlib.h>
int main ()
{
int * buffer;
(d). REALLOC( ) : The function realloc() reallocates a memory block with a specific new
size. If you call realloc() the size of the memory block pointed to by the pointer is changed to
the given size in bytes. This way you are able to expand and reduce the amount of memory
you want to use (if available of course.)
It is possible that the function moves the memory block to a new location, in which way the
function will return this new location. If the size of the requested block is larger then the
previous block then the value of the new portion is indeterminate.
If the pointer is NULL then the function will behave exactly like the function malloc(). It will
assign a new block of a size in bytes and will return a pointer to it.
If the size is 0 then the memory that was previously allocated is freed as if a call of the
function free() was given. It will return a NULL pointer in that case. Main features are:
#include<stdio.h>
#include<stdlib.h>
int main ()
{
int * buffer;
exit (1);
}
free (buffer);
return 0;
}
Functio Task
n
malloc() Allocates memory requests size of bytes and returns a pointer to the Ist byte of
allocated space
calloc() Allocates space for an array of elements initializes them to zero and returns a
pointer to the memory
C++ provides two dynamic allocation operators: new and delete. These operators are
used to allocate and free memory at run time. Dynamic allocation is an important part of
almost all real-world programs. As explained in Part One, C++ also supports dynamic
memory allocation functions, called malloc() and free(). These are included for the sake of
compatibility with C. However, for C++ code, you should use the new and delete operators
because they have several advantages. The new operator allocates memory and returns a
pointer to the start of it. The delete operator frees memory previously allocated using new.
13 | P a g e
Here, p_var is a pointer variable that receives a pointer to memory that is large enough to
hold an item of type type . Since the heap is finite, it can become exhausted. If there is
nsufficient available memory to fill an allocation request, then new will fail and a bad_alloc
exception will be generated. This exception is defined in the header <new>. Your program
should handle this exception and take appropriate action if a failure occurs. If this exception
is not handled by your program, then your program will be terminated.
The actions of new on failure as just described are specified by Standard C++. The trouble is
that not all compilers, especially older ones, will have implemented new in compliance with
Standard C++. When C++ was first invented, new returned null on failure. Later, this was
changed such that new caused an exception on failure. Finally, it was decided that a new
failure will generate an exception by default, but that a null pointer could be returned instead,
as an option. Thus, new has been implemented differently, at different times, by compiler
manufacturers. Although all compilers will eventually implement new in compliance with
Standard C++, currently the only way to know the precise action of new on failure is to check
your compiler's documentation. Since Standard C++ specifies that new generates an
exception on failure, this is the way the code in this book is written. If your compiler handles
an allocation failure differently, you will need to make the appropriate changes.
#include <iostream>
#include <new>
using namespace std;
int main()
{
int *p;
try {
This program assigns to p an address in the heap that is large enough to hold an integer. It
then assigns that memory the value 100 and displays the contents of the memory on the
screen. Finally, it frees the dynamically allocated memory. Remember, if your compiler
implements new such that it returns null on failure, you must change the preceding program
appropriately.
14 | P a g e
The delete operator must be used only with a valid pointer previously allocated by using new.
Using any other type of pointer with delete is undefined and will almost certainly cause
serious problems, such as a system crash.
Although new and delete perform functions similar to malloc() and free(), they have several
advantages.
1. Firstly, new automatically allocates enough memory to hold an object of the specified
type. You do not need to use the sizeof operator. Because the size is computed automatically,
it eliminates any possibility for error in this regard.
2. Secondly, new automatically returns a pointer of the specified type. You don't need to use
an explicit type cast as you do when allocating memory by using malloc().
3.Finally, both new and delete can be overloaded, allowing you to create customized
allocation systems. Although there is no formal rule that states this, it is best not to mix new
and delete with malloc() and free() in the same program. There is no guarantee that they are
mutually compatible.
Of course, the type of the initializer must be compatible with the type of data for which
memory is being allocated.
This program gives the allocated integer an initial value of 87:
#include <iostream>
#include <new>
using namespace std;
int main()
{
int *p;
try {
p = new int (87); // initialize to 87
} catch (bad_alloc xa) {
cout << "Allocation Failure\n";
return 1;
}
cout << "At " << p << " ";
cout << "is the value " << *p << "\n";
15 | P a g e
delete p;
return 0;
}
The main advantage of using dynamic memory allocation is preventing the wastage of
memory. This is because when we use static memory allocation, a lot of memory is wasted
because all the memory allocated cannot be utilised. Thus dynamic memory allocation helps
us to allocate memory as and when required and thus saves memory.
Freeing Memory
The user is responsible for freeing up memory when he is finished with it. This is a serious
responsibility, a potential source of bugs that are very hard to find.
For example, suppose you free up a location before you're actually finished with it. Then
further access to the location will either cause a run-time error (memory violation) or, what is
worse (but more common), you will get access to a location that is being used for some
completely unrelated purpose.
Trouble also occurs if you forget to free up some space. If you do this, you are losing the
advantages of dynamic allocation. And in some circumstances - e.g. if you were writing the
program that manages the space on a disk drive - this could be disastrous.
There are no surefire safeguards against these problems, you must be very careful when
writing programs to return memory when you are finished with it, but not before.
Fragmentation of Memory
As the preceding example demonstrated, with dynamic allocation the `free' parts of memory
are not all together in one contiguous block. When we returned JOE's memory, we had 4 free
cells on one side of MARYJANE and all the rest on the other side. This is called
fragmentation of memory, and it can grow into a very serious problem: it is possible to have a
large amount of free memory but for it to be broken up into such tiny fragments that there is
not enough contiguous free space to store another name.
Suppose that after using dynamic allocation for a while memory becomes fragmented thus:
If only the remaining free blocks were contiguous, we'd have enough room, but, in the
present configuration, it looks like we are doomed. There are several possible solutions to this
16 | P a g e
problem. The one we will study is based on the insight that a large data structure does not
necessarily have to be allocated in one single contiguous chunk of memory. Instead it might
be decomposed into smaller components that are somehow linked together in a chain.
17 | P a g e
REFERENCES
Sites:-
http://books.google.co.in
http://wikipaedia.com
http://wiki.answers.com
Books:-
ANSI C by Balagurusamy