The process of allocating memory to the variables during execution of the program or at run time is known as dynamic memory allocation. C language has four library routines which allow this function.
DYNAMIC
MEMORY ALLOCATION
The
process of allocating memory to the variables during execution of the program
or at run time is known as dynamic memory allocation. C language has four
library routines which allow this function.
Till
now whenever we needed an array we had declared a static array of fixed size,
say
int arr [100];
When
this statement is executed, consecutive space for 100 integers is allocated. It
is not uncommon that we may be using only 10% or 20% of the allocated space thereby
wasting rest of the space. To overcome this problem and to utilize the memory
efficiently c language provides a mechanism of dynamically allocating memory so
that only the amount of memory that is actually required is reserved. We
reserve space only at the run time for the variables that are actually
required. Dynamic memory allocation gives best performance in situations in
which we do not know memory requirements in advance.
C
provides four library routines to automatically allocate memory at the run
time. These routines are shown in Table 7.2.
When
we have to dynamically allocate memory for variables in our programs then
pointers are the only way to go. When we use malloc() for dynamic memory
allocation, then you need to manage the allocated for variables yourself.
In
computer science, the free memory region is called the heap. The size of heap
is not constant as it keeps changing when the program is executed. In the
course of program execution, some new variables are created and some variables
cease to exist when the block in which they were declared is exited. For this
reason it is not uncommon to encounter memory overflow problems during dynamic
allocation process. When an overflow condition occurs, the memory allocation
functions mentioned above will return a null pointer.cl
Let
us see how memory is allocated using the malloc(). malloc is declared in
<stdlib.h>, so we include this header file in any program that calls
malloc. The malloc function 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. The general syntax of the malloc()
is
ptr = (cast-type*) malloc
(byte-size);
where
ptr is a pointer of type cast-type. The malloc() returns a pointer (of cast
type) to an area of memory with size byte-size. For example,
arr= (int *)malloc (10* sizeof
(int));
This
statement is used to dynamically allocate memory equivalent to 10 times the
area of int bytes. On successful execution of the statement the space is
reserved and the address of the first byte of memory allocated is assigned to
the pointer arr of type int.
Programming Tip:
To
use dynamic memory allocation functions, you must include the header file
stdlib.h.
The
function Calloc() is another function that reserves memory at the run time. It
is normally used to request multiple blocks of storage each of the same size
and then sets all bytes to zero. Calloc() stands for contiguous memory
allocation and is primarily used to allocate memory for arrays. The syntax of
calloc() can be given as
ptr= (cast-type*) calloc (n,
elem-size);
The
above statement allocates contiguous space for n blocks each size of elements
size bytes. The only difference between malloc() and calloc() is that when we
use calloc(), all bytes are initialized to zero. Calloc() returns a pointer to
the first byte of the allocated region.
When
we allocate memory using malloc() calloc(), a null pointer will be returned if
there is not enough space in the system to allocate. A null pointer, points
definitely nowhere. It is a not a pointer marker; therefore, it is not a
pointer you can use. Thus, whenever you allocate memory using malloc() or
calloc(), you must check the returned pointer before using it. If the program
receives a null pointer, it should at the very least print an error message and
exit, or perhaps figure out some way of proceeding without the memory it asked
for. But in any case, the program cannot go on to use the null pointer it got
back from malloc ()/calloc().
A
call to malloc, with an error check, typically looks something like this:
int *ip = malloc (100 * sizeof
(int));
if (ip == NULL)
{
printf("\n Memory could not be
allocated");
return;
}
31. Write a program
to read and display values of an integer array. Allocate space dynamically for
the array.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
main ()
{
int i, n;
int *arr;
clrscr();
printf("\n Enter the number of
elements ");
scanf("%d", &n);
arr = (int *)malloc(n*
sizeof(int));
if (arr == NULL)
{
printf("\n Memory Allocation
Failed");
exit (0);
}
for (i=0;i<n;i++)
{
printf("\n Enter the value %d
of the array: ", i);
scanf("%d", &arr[i]);
}
printf("\n The array contains
\n");
yo for (i=0;i<n;i++)
printf("%d", arr[i]); //
another way is to write * (arr+i)
return 0;
}
Now
let us also see how we can allocate memory using the calloc function. The
calloc() function accepts two parametres-num and size, where num is the number
of elements to be allocated and size is the size of elements. The following
program demonstrates the use of calloc() to dynamically allocate space for an
integer array. #include <stdio.h>
#include <stdlib.h>
main ()
{
int i,n;
int *arr;
printf ("\n Enter the number
of elements: ");
scanf("%d", &n);
arr = (int *) calloc (n,
sizeof(int));
if (arr==NULL)
exit (1);
printf("\n Enter the %d values
to be stored in the array", n);
for (i = 0; i < n; i++)
scanf("%d", &arr[i]);
printf ("\n You have entered:
");
for(i = 0; i < n; i++)
printf ("%d", arr[i]);
free (arr);
return 0;
}
When
a variable is allocated space during the compile time, then the memory used by
that variable is automatically
released
by the system in accordance with its storage class. But when we dynamically
allocate memory then it is our responsibility to release the space when it is
not required. This is even more important when the storage space is limited.
Therefore, if we no longer need the data stored in a particular block of memory
and we do not intend to use that block for storing any other information, then
as a good programming practice we must release that block of memory for future
use, using the free function. The general syntax of the free () is,
free
(ptr);
where
ptr is a pointer that has been created by using malloc() or calloc(). When
memory is de-allocated using the free (), it is returned back to the free list
within the heap.
At
times the memory allocated by using calloc()
or malloc() might be insufficient or
in excess. In both the situations we can always use realloc() to change the memory size already allocated by calloc() and malloc(). This process is called reallocation of memory. The
general syntax for realloc() can be
given as
ptr = realloc (ptr, newsize);
The
function realloc() allocates new
memory space of size specified by newsize
to the pointer variable ptr. It
returns a pointer to the first byte of the memory block. The allocated new
block may be or may not be at the same region. Thus, we see that realloc() takes two arguments. The first
is the pointer referencing the memory and the second is the total number of
bytes you want to reallocate. If you pass zero as the second argument, it will
be equivalent to calling free (). Like malloc()
and calloc(), realloc returns a void pointer if successful, else a NULL pointer
is returned.
If
realloc() was able to make the old
block of memory bigger, it returns the same pointer. Otherwise, if realloc() has to go elsewhere to get
enough contiguous memory then it returns a pointer to the new memory, after
copying your old data there. However, if realloc()
can't find enough memory to satisfy the new request at all, it returns a null
pointer. So again you must check before using, that the pointer returned by the
realloc() is not a null pointer.
/*Example program for
reallocation*/
#include <stdio.h>
#include <stdlib.h>
#define NULL 0
main()
{
char *str;
/*Allocating memory*/
str = (char *)malloc(10);
if (str==NULL)
{
printf("\n Memory could not be
allocated");
exit (1);
}
strcpy(str, "Hi");
printf("\n STR = %s",
str);
/*Reallocation*/
str = (char *) realloc(str, 20);
if (str==NULL)
{
printf("\n Memory could not be
reallocated");
exit(1);
}
printf("\n STR size
modified.\n");
printf("\n STR = %s\n",
str);
strcpy(str., "Hi there");
printf("\n STR = %s",
str);
/*freeing memory*/
free (str);
return 0;
}
With
realloc(), you can allocate more
bytes without losing your data.
Dynamically Allocating a 2D Array
We
have seen how malloc() can be used to allocate a block of memory which can
simulate an array. Now we can extend our understanding further to do the same
to simulate multidimensional arrays.
If
we are not sure of the number of columns that the array will have, then we will
first allocate memory for each row by calling malloc. Each row will then be represented by a pointer. Look at the
code below which illustrates this concept.
#include <stdlib.h>
#include <stdio.h>
main()
{
int **arr, i, j, ROWS, COLS;
printf("\n Enter the number of
rows and columns in the array: ");
scanf("%d %d", ROWS,
COLS);
arr = (int **)malloc (ROWS *
sizeof(int *));
if (arr == NULL)
{
printf("\n Memory could not be
allocated");
exit (-1);
}
for (i=0; i<ROWS; i++)
{
arr[i] = (int *)malloc (COLS *
sizeof (int));
if (arr[i] == NULL)
{
printf("\n Memory Allocation
Failed");
exit (-1);
}
}
printf("\n Enter the values of
the array: ");
for (i=0; i < ROWS; i++)
{
for (j=0; j < COLS; j++)
scanf("%d", &arr[i]
[j]);
}
printf("\n The array is as
follows: ");
for (i=0; i < ROWS; i++)
{
for (j=0; j < COLS; j++)
printf("%d", arr[i] [j]);
}
for (i=0; i < ROWS; i++)
free (arr [i]);
free (arr);
return 0;
}
Here,
arr is a pointer-to-pointer-to-int: at the first level as it points to a block
of pointers, one for each row. We first allocate space for rows in the array.
The space allocated to each row is big enough to hold a pointer-to-int, or int *. If we successfully allocate it, then this
space will be filled with pointers to columns (number of ints). This can be
better understood from Figure 7.11.
Once
the memory is allocated for the two-dimensional array, we can use subscripts to
access its elements. When we write, arr
[i] [j], it means we are looking for the ith pointer pointed to
by arr, and then for the jth int pointed to by that inner pointer.
When
we have to pass such an array to a function, then the prototype of the function
will be written as
func (int **arr, int ROWS, int
COLS);
In
the above declaration, func accepts a
pointer- to-pointer-to-int and the
dimensions of the arrays as parametres, so that it will know how many rows and
columns there are.
Look
at the code given below which illustrates another way of dynamically allocating
space for a 2D array.
#include <stdlib.h>
#include <stdio.h>
main()
{
int *arr, i, j, ROWS, COLS;
printf("\n Enter the number of
rows and columns in the array: ");
scanf("%d %d", ROWS,
COLS);
arr = (int *)malloc (ROWS * COLS
*sizeof(int));
if (arr == NULL)
{
printf("\n Memory could not be
allocated");
exit (-1);
}
printf("\n Enter the values of
the array: ");
for(i = 0; i < ROWS; i++)
{
for (j = 0; j < COLS; j++)
scanf("%d", &arr[i]
[j]);
}
printf("\n The array is as
follows: ");
for (i 0; i < ROWS; i++)
{
for (j 0; j < COLS; j++)
printf("%d", arr[i] [j]);
}
for (i=0; i < ROWS; i++)
free (arr [i]);
free (arr);
return 0;
}
Note
To
dynamically allocate space for a 3-D array, arr[10][20] [30], perform the
following steps
1.
int ***arr;
2.
arr (int ***) malloc(10* sizeof(int ** ) ) ;
3.
for(i=0;i<10;i++) arr[i] (int **) malloc (20*sizeof(int *));
4.
for (i=0;i<10; i++) { for(j=0; j<20;j++) arr[i][j] (int
*)malloc(30*sizeof (int));
Programming in C: Unit III (b): Pointers : Tag: : with Example C Programs - Dynamic Memory Allocation
Programming in C
CS3251 2nd Semester CSE Dept 2021 | Regulation | 2nd Semester CSE Dept 2021 Regulation