|
|||||
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
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
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
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
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
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
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
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
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
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
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
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
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:
|
|||||