Very often we face situations in programming where the data is dynamic in
nature i.e. the number of data items keep changing during execution of the
program. For example, in an employee database, the number of employees
continually increase and decrease as and when names are added or deleted.
Accordingly, we need to manage the memory space. This can be done effectively
using dynamic data structures in conjunction with dynamic memory management
techniques.
The advantage of dynamic data structures is that it provides flexibility in
adding, deleting or rearranging data items at run time. Dynamic memory
management techniques allow us to allocate additional memory space or release
unwanted space at run time, thus optimizing the use of storage space.
Dynamic memory allocation
A good example to illustrate the importance of dynamic memory allocation is
arrays. The number of elements in an array needs to be specified at compile
time, but this may not be possible at all times and even if it is possible we
usually allocate more space than required. If the size of the array is given
wrongly, it may cause failure of the program or more commonly, wastage of memory
space. Thus instead of specifying the size of the array at compile time, if we
could do it at run time when we are absolutely sure of the required size, the
program would be more efficient. The process of allocating memory at run time is
known as dynamic memory allocation. Although C does not inherently have this
facility, there are four library routines known as memory management functions
that can be used for allocating and freeing memory during program execution.
They are:
malloc: it allocates the requested size of bytes and returns a pointer
to the first byte of the allocated space.
calloc: it allocates space for an array of elements, initializes them to
zero and then returns a pointer to memory.
free: frees previously allocated space.
realloc: modifies the size of previously allocated space.
Allocating memory
The malloc function can be used to allocate a block of memory. It reserves a
block of memory of specified size and returns a pointer of type void. This means
that we can assign it to any type of pointer. Malloc allocates a block of
contiguous bytes of memory. It takes the following form:
ptr = (cast-type *)malloc(byte-size);
Here ptr is of type cast-type and malloc returns a pointer of cast-type to an
area of memory with size byte-size. For example:
x = (int *)malloc(100 * sizeof(int));
On execution of this statement, a memory space equivalent to 100 times the size
of int data type bytes is reserved and the address of the first byte of memory
allocated is assigned to the pointer x of type int. Similarly
y = (char *)malloc(10);
allocates 10 bytes of space for the pointer y of type char.
Note: the storage space allocated dynamically has no name and
therefore its contents can be accessed only through a pointer.
Malloc can also be used to allocate space for complex data types such as
structures. Example:
z = (struct store *)malloc(sizeof(struct store));
where z is a pointer of type struct store.
Lets take a look at a program that illustrates the use of pointers.
/* Program that uses a table of integers whose size will be specified
interactively at run time */
#include
#define NULL 0
main()
{
int *p, *table, size;
printf("\nEnter the size of the table :");
scanf("%d",&size);
if((table=(int *)malloc(size * sizeof(int)))==NULL) /* Memory allocation */
{
printf("\nNo space available");
exit(1);
}
printf("\n Address of the first byte is %u\n",table);
printf("\n Input the values of the table :");
for(p=table;p
{
scanf("%d",p);
}
for(p=table;p
{
printf("\n The number %d is stored at the memory location %u",*p,p);
}
}