In this article you will learn about dynamic memory allocation. Dynamic memory allocation is made using dynamic variables. The variables that we have created so far are static variables. Static variables are created during compile time. On the other hand, dynamic variables, which can be of any basic data type or structured data type, can be created or destroyed during runtime of a program. A dynamic variable is not referenced by a name, rather it is referenced through a pointer that contains the address in memory of the dynamic variable referenced. Thus every dynamic variable created has an associated pointer by which it is referenced.
Static Memory Allocation
Though arrays can be used for implementing a list of data items, they are of static structure. A static structure is one whose size is fixed at compile time. In other words, the programmer must know the size of the array or data while writing the programs. A static structure exists as long as the part of the program or block in which it is declared is executing.
But there are so many instances where we work with lists and we have no idea of the number of data items in such lists. The usual approach in this situation us to declare an array large enough to hold the maximum amount of data we could logically expect. For example, consider the following declaration:
int a[500];
In this you can store 500 integer values in memory. The moment you declare this, 1000 bytes are reserved for storing 500 integers in it. However it may so happen that when we actually run the program we might be wanted to storing only 100 integer values. Even in this case 1000 bytes would be reserved in memory and unfortunately you are using only 200 bytes and thus it would result in wastage of memory of 800 bytes.
Another possibility is that when you run the program you need to store more than 500 integer values, say 600. In this case, the array would fall short in size of 200 bytes. The ultimate conclusion is that when we use arrays static memory allocation takes place because there is no way to decrease or increase the array size during the program’s execution. This problem is overcome by dynamic memory allocation.
Dynamic Memory Allocation
When memory is allocated during runtime, it is called as dynamic memory allocation. C provides many built-in library functions, such as malloc(), calloc(), and realloc() that allocates memory dynamically. Since these functions allocate memory during the execution time, they are often known as “dynamic memory allocation functions” and the dynamic memory allocation is the process of allocating memory at the run time instead of allocation at the compilation time. Additionally C provides free() function for efficient dynamic memory deallocation. These functions are defined and declared in header files. Let us discuss these functions one by one.
malloc()
The declaration of malloc() function is:
(void *) malloc (size);
The malloc() function allocates a memory block of at least size bytes from the free memory space. If the size is 0, malloc() allocates a zero-length item. This function returns a pointer to the newly allocated memory block, of course if it successfully allocates a memory block; otherwise it returns a NULL value. The default return type of malloc() function is void *. In earlier article we have already studied that the NULL is defined in header file. Let us see a simple program that illustrates the use of malloc() function.
main()
{
int num, i;
int *ptr;
printf("\nHow many integer numbers you want to store? ");
scanf("%d", &num);
ptr = (int *)malloc(num*sizeof(int)); /* creating memory dynamically */
if (ptr==NULL)
{
printf("\nInsufficient memory space for dynamic memory allocation.");
exit(0);
}
printf("\nPlease enter %d integer values : \n", num);
for(i=0; i scanf("%d", ptr+i);
printf("\nYou have entered these integer values.\n");
for(i=0; i printf("\n%d", *(ptr+i));
free(ptr);
}
The output of this program is as….
How many integer numbers you want to store? 7
Please enter 7 integer values:
11
22
33
44
55
66
77
You have entered these integer values.
11
22
33
44
55
66
77
In this program, we must ask for the number of integers to be created during run time and then allocate only as much as memory is really needed to store these numbers. If there is sufficient memory space then the malloc() function returns the starting address of the memory block in an integer pointer ptr. Since we are creating memory space for integer values dynamically therefore it is necessary to typecast the address being returned, which is (int *) in this case. We know that the storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. That’s why to get a pointer to a type other than void, use a typecast on the return value.
calloc()
The C library provides another function calloc() to allocate memory space at runtime. The declaration of calloc() function is:
(void *) calloc (num, size);
Here num specifies the number of data items to allocate and size specifies the size of each data item. The calloc() function works exactly similar to malloc() function except for the fact that it needs two arguments rather than one as in malloc() function. But like malloc() function, calloc() function returns a pointer to the newly created block if there is sufficient amount of free memory and on failure it returns a NULL. Since it also returns a void pointer, therefore it should be typecast to an appropriate pointer type before dereferencing, like malloc(). The following program illustrates this fact.
main()
{
int num, i;
int *ptr;
printf("\nHow many integer numbers you want to store? ");
scanf("%d", &num);
ptr = (int *)calloc(num, sizeof(int));
if (ptr==NULL)
{
printf("\nInsufficient memory space for dynamic memory allocation.");
exit(0);
}
printf("\nPlease enter %d integer values : \n", num);
for(i=0; i scanf("%d", ptr+i);
printf("\nYou have entered these integer values.\n");
for(i=0; i printf("\n%d", *(ptr+i));
free(ptr);
}
The output of this program is similar to previous one.
Another main difference between malloc() and calloc() functions lies in the fact that where calloc() initializes the allocated space to zeros, malloc() does not provide any initialization. Therefore the space allocated by malloc() contains garbage initially. This program illustrates this difference.
main()
{
int num, i;
int *ptr1, *ptr2;
printf("\nHow many integer numbers you want to store? ");
scanf("%d", &num);
ptr1 = (int *)malloc(num*sizeof(int));
if (ptr1==NULL)
{
printf("\nInsufficient memory space for dynamic memory allocation.");
exit(0);
}
ptr2 = (int *)calloc(num, sizeof(int));
if (ptr2==NULL)
{
printf("\nInsufficient memory space for dynamic memory allocation.");
free(ptr1);
exit(0);
}
printf("\nDefault initial values in malloc() function are as....\n");
for(i=0; i printf("\n%d", *(ptr1+i));
printf("\n\nDefault initial values in calloc() function are as....\n");
for(i=0; i printf("\n%d", *(ptr2+i));
free(ptr1);
free(ptr2);
}
Here is the output of this program….
How many integer numbers you want to store? 5
Default initial values in malloc() function are as....
18
0
35
0
5036
Default initial values in calloc() function are as....
0
0
0
0
0
realloc()
For whatever reason, the memory that was previously dynamically allocated is increased or reduced by the function realloc(). The declaration of realloc() function is as:
(void *) realloc (ptr, size);
This function changes the size of an allocated block of memory pointed to by the pointer variable ptr to the block to size, copying the contents to a new location, if necessary. Here the ptr is the return value from the last call to malloc() or calloc() or realloc(). If pointer-variable is a null pointer, realloc() works just like malloc(). If there is sufficient free memory then the realloc() function returns the address of the reallocated block, which might be different from the address of the original block. Unfortunately it realloc() fails, it returns a NULL value. This program illustrates the use of realloc() function.
main()
{
int num1, num2, i;
int *ptr;
printf("\nHow many integer numbers you want to store? ");
scanf("%d", &num1);
ptr = (int *)malloc(num1*sizeof(int));
if (ptr==NULL)
{
printf("\nInsufficient memory space for dynamic memory allocation.");
exit(0);
}
printf("\nPlease enter %d integer values.\n", num1);
for(i=0; i scanf("\n%d", (ptr+i));
printf("\nYou have entered these values....\n");
for(i=0; i printf("\n%d", *(ptr+i));
printf("\nHow many integers you want more? ");
scanf("%d", &num2);
ptr = (int *)realloc(ptr, sizeof(num2));
if (ptr==NULL)
{
printf("\nInsufficient memory space for dynamic memory allocation.");
exit(0);
}
printf("\nPlease enter %d more integer values.\n", num2);
for(i=0; i scanf("\n%d", (ptr+num1+i));
printf("\nYou have entered these integer values....\n");
for(i=0; i printf("\n%d", *(ptr+i));
free(ptr);
}
The output of this program is as….
How many integer numbers you want to store? 4
Please enter 4 integer values.
11
33
55
77
You have entered these values....
11
33
55
77
How many integers you want more? 2
Please enter 2 more integer values.
99
111
You have entered these integer values....
11
33
55
77
99
111
free()
The free() function is used to deallocate a memory block previously allocated by malloc(), calloc() and realloc() functions. The declaration of free() function is as:
void free (void *ptr);
Once the memory has been released, it can not be reused. It can be reused as a subsequent call to malloc(). The ptr is the starting address of the previously allocated memory that has to be released. One main point to note is that you should never pass an uninitialized pointer or a pointer to a variable not allocated by malloc() or calloc() or realloc() functions. if you try to attempt so it would be very dangerous and disastrous. Now let us see some examples that illustrate the use of these functions:
Example-1: Write a program that arranges a set of numbers in ascending order using pointer notations.
main()
{
int *ptr;
int i, j, n, temp;
printf("\nHow many integer numbers you want to sort? ");
scanf("%d", &n);
printf("\nPlease enter any %d integer numbers.\n", n);
ptr = (int *)malloc(n*sizeof(int));
for(i=0; i scanf("%d", ptr+i);
printf("\nUnsorted array is : \n");
for(i=0; i printf("%d\n", *(ptr+i));
for(i=0; i {
for(j=i; j {
if (*(ptr+i) > *(ptr+j))
{
temp = *(ptr+i);
*(ptr+i) = *(ptr+j);
*(ptr+j) = temp;
}
}
}
printf("\nSorted array is : \n");
for(i=0; i printf("%d\n", *(ptr+i));
free(ptr);
}
Here is the output of this program….
How many integer numbers you want to sort? 5
Please enter any 5 integer numbers.
14
11
15
13
12
Unsorted array is :
14
11
15
13
12
Sorted array is :
11
12
13
14
15
Creating Strings Dynamically
You can also create strings of any length dynamically. However the syntax of creating a dynamic string is similar to creating a number of integers dynamically. For example, if you want to create a string of 40 characters then you will use the following statements:
char *cptr;
cptr = (char *) mallloc (40);
or
cptr = (char *) callloc (40, 1);
Similarly you can create a string of ‘n’ number of character. Let us see a simple program that illustrates this fact.
main()
{
char *str;
char name[20];
int len;
printf("\nEnter the string : ");
scanf("%s", name);
len = strlen(name);
str = (char *)malloc(sizeof(len));
strcpy(str, name);
printf("Duplicate string : %s", str);
free(str);
}
The output of this program is as….
Enter the string : Tendulkar
Duplicate string : Tendulkar
Creating Multi-Dimensional Arrays Dynamically
In earlier section, you have studied how to create a number of items dynamically at run time. In this section you will study how to create a two-dimensional array when the size is not known during the writing of a program. This can be achieved by allocating a single-dimensional array of pointers, where each pointer representing a row, and then allocating each row as a normal single dimensional array. For example, a matrix ‘num’ of size m*n of int variables is created dynamically as:
int **num;
num = (int **) malloc (m*sizeof(int *));
for (i=0; i num[i] = (int *) malloc (n*sizeof(int));
Accessing a data item in row ‘i’ and column ‘j’ is done as usual, using the expression mat[i][j]. This program illustrates dynamic allocation of a two-dimensional array.
main()
{
int i, j, row, col;
int **num;
printf("\nEnter the row numbers : ");
scanf("%d", &row);
printf("\nEnter the column numbers : ");
scanf("%d", &col);
num = (int **)malloc(row*sizeof(int *));
if (num==NULL)
{
printf("\nInsufficient memory space for dynamic memory allocation.");
exit(0);
}
for(i=0; i num[i] = (int *)malloc(col*sizeof(int));
printf("\nEnter the elements of a matrix (%d*%d) : \n", row, col);
for(i=0; i for(j=0; j scanf("%d", &num[i][j]);
printf("\nEnter the elements of a matrix (%d*%d) : \n", row, col);
for(i=0; i {
printf("\n");
for(j=0; j printf("%d\t", num[i][j]);
}
}
Here is the output of this program….
Enter the row numbers : 3
Enter the column numbers : 4
Enter the elements of a matrix (3*4) :
1 2 3 4
5 6 7 8
9 10 11 12
Elements of a matrix (3*4) :
1 2 3 4
5 6 7 8
9 10 11 12
Creating Structures Dynamically
Like arrays, you can also create structures dynamically. When you create a structure dynamically you have to use the structure data type in malloc() function. For example, let us have a following structure type:
struct Employee
{
char name[20];
int age;
char section;
};
Then you can create a structure of this type dynamically as:
struct Employee *eptr;
eptr = (struct Employee *) malloc (sizeof(struct Employee));
Now let us see a simple program that illustrates the use of creating a structure dynamically.
main()
{
struct Employee
{
char name[20];
int age;
float salary;
};
struct Employee *eptr;
float a=10, *b=&a;
eptr = (struct Employee *)malloc(sizeof(struct Employee));
printf("\nEnter Employee name, age and salary : ");
scanf("%s %d %f", eptr->name, &eptr->age, &eptr->salary);
printf("Employee name, age and salary : %s %d %f", eptr->name,
eptr->age, eptr->salary);
free(eptr);
}
Here is the output of this program….
Enter Employee name, age and sex : Aditya 35 10000.50
Employee name, age and salary : Aditya 35 10000.500000
Similarly you can create an array of ‘n’ structures as:
eptr = (struct Employee ) malloc (n * sizeof(struct Employee));
The following program creates array of structures dynamically.
main()
{
struct Employee
{
char name[20];
int age;
float salary;
};
struct Employee *eptr;
int i, n;
float a=10, *b=&a;
printf("\nHow many structures you want to create? ");
scanf("%d", &n);
eptr = (struct Employee *)malloc(sizeof(struct Employee)*n);
printf("\n");
for(i=0; i {
printf("Enter Employee #%d name, age and salary : ", i+1);
scanf("%s %d %f", (eptr+i)->name, &(eptr+i)->age, &(eptr+i)->salary);
}
for(i=0; i {
printf("\nEmployee #%d name, age and salary : %s %d %f", i+1,
(eptr+i)->name, (eptr+i)->age, (eptr+i)->salary);
}
free(eptr);
}
Here is the output of this program….
How many structures you want to create? 4
Enter Employee #1 name, age and salary : Mohit 20 4500.75
Enter Employee #2 name, age and salary : Rahul 24 5000.50
Enter Employee #3 name, age and salary : Aditya 30 8775.25
Enter Employee #4 name, age and salary : Amit 25 7500.00
Employee #1 name, age and salary : Mohit 20 4500.750000
Employee #2 name, age and salary : Rahul 24 5000.500000
Employee #3 name, age and salary : Aditya 30 8775.250000
Employee #4 name, age and salary : Amit 25 7500.000000
This property of creating dynamic structure variables is most used in dynamic data structures, such as singly linked lists, doubly linked lists, linked stacks and linked queues, trees and graphs.
Memory can be allocated either statically or dynamically. C uses runtime library functions, such as malloc(), calloc() and realloc(), for allocation of memory dynamically and free() function for releasing the memory dynamically. You can create memory space dynamically for one-dimensional arrays, two-dimensional arrays, strings and structures.