Dynamic memory allocation in C

by | Aug 20, 2022 | C

Home » C » Dynamic memory allocation in C

Introduction

The concept of Dynamic memory allocation in coding is very interesting. Although this part is not visible or written in code, the systematic way of allocating memory to the data is very important to understand. Let’s introduce this topic with an example.

Suppose you want to fill a bottle with milk, and you only have an approximate idea of the quantity of the milk. For that, you would either require a bottle whose size is equal to the quantity of milk you have, or a bottle with a larger quantity than the quantity of milk. Only then we can fill the bottle with milk. Otherwise, there will be wastage of the milk if the quantity of milk exceeds the size of the bottle.

Now relating the above example with our C language, we face a similar situation often while programming that is, whenever we want to input a string in the form of an array of characters but in the same time we are not sure about the number of characters in the array. Thus, we always make an approximate idea about the size of the array. But this hit and trial method doesn’t work efficiently every time.

How does memory allocation in C works?

While making the declaration for the array of characters, if we specify its size as smaller than the size of the input string, then the compiler will show an error because the space has already been allocated to the array in the memory equal to the size, we specified during declaration but later on when we enter a string of larger size. As a result, some portions of the string will not be allocated with memory. Thus, we will get an error. This is the same case as we were trying to fill the bottle with milk of a size lesser than its quantity, and it leads to an overflow.

Moreover, if we specify the size of the array greater than the actual size of the input string, then the array will be assigned a space in the memory which is much bigger than the size of the input string. Thus the memory blocks remain empty and unnecessarily consume more memory even when it is not needed. This is like filling a bottle with milk of a much larger size than the quantity of milk.

Dynamic memory allocation

The different cases discussed above are the approximation ways. But in C language, we are provided with a facility to change the size according to our needs.

The procedure in which we can change the size of the data structures like an array during the runtime is known as Dynamic memory allocation.

Let’s consider an array of length 5 with given values:

Value9590858075
Index01234

 

Case 1:

We want only three elements to be entered in the above array. In this case, the remaining two indices i.e., 3 and 4, are just wasting memory in this array. Thus, there is a requirement to lessen the array’s length from 5 to 3.

Case 2:

We have an array of size 5, and all the indices are filled. Now we need two more elements in this array. In this case, two indices are more required. Thus, the array’s length needs to be changed from 5 to 7.

To facilitate dynamic memory allocation in C programming, the C language had provided us 4 library functions that are defined under <stdlib.h> header file.

1. malloc()

2. calloc()

3. free()

4. realloc()

malloc()

malloc function is used when we don’t have an idea about the size of the array while writing the code. malloc function allocates memory at runtime.

The size will be taken by the malloc function in bytes and that much space in the memory will be allocated. The malloc(4) will allocate 4 bytes in the memory.

We didn’t specify datatype before the malloc function, therefore the return type of this function is void.

malloc function is always stored in a pointer because it returns a pointer.

It is defined in stdlib.h.

Try to understand all the points written above with the help of the code.

Program

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char name[20];
strcpy(name, "Dixon");


char *Address;
Address=(char*)malloc(50* sizeof (char));
strcpy(Address, "Vasant Vihar, Golden avenue, Chandigarh");


printf("Name: %s\n",name);
printf("Address: %s\n",Address);
return 0;
}

 

Output

The first two statements of the code are quite simple. An array ‘name’ of size 20 is declared and then the strcpy function is used to assign a string value to the variable ‘name’.

For address, we estimated that the size should be around 50. So, 50*sizeof(char) will be the size of the variable ‘address’.

char *Address; ‘Address’ is a pointer variable of type ‘char’ which is declared specifying its size. Thus, till now we don’t know how much memory is required. The declaration of the pointer is made to store the malloc function in this pointer.

Address=(char*)malloc(50* sizeof (char)); here, we assigned a memory of ‘50* sizeof (char)’ in the address. Thus, we give 50-byte memory to the malloc function. (char*) is used to typecast the pointer (which was of type void) returned by the malloc to the character since the address is of type char.

strcpy(Address, “Vasant Vihar, Golden avenue, Chandigarh”); we assigned the address by writing this statement.

Note:

1. It is important to note that, malloc always returns a pointer of type void but we must typecast it into a pointer of any other form as we did in the above code.

2. In case, the space in the memory allocated by the malloc is insufficient, then the allocation fails and malloc returns a NULL pointer.

Program

#include<stdio.h>
#include<stdlib.h>
int main()
{
int n;
printf("Enter number of elements:");
scanf("%d",&n);


int *p;
p=(int*)malloc(n* sizeof(int));
if(p==NULL)
{
printf("\nMemory cannot be allocated\n");
}
else
{
printf("Enter elements of array:\n");
for(int i=0;i<n;i++)
{
scanf("%d",&*(p+i));
}
printf("Elements of array are:\n");
for(int i=0;i<n;i++)
{
printf("%d\n",*(p+i));
}
}


return 0;
}

 

Output

A pointer ‘p’ is declared first of type int.

p=(int*)malloc(n* sizeof(int)); since ‘p’ is an integer array containing ‘n’ elements. The memory of size n* sizeof(int) is assigned to the array to which the pointer ‘p’ is pointing to.

In this way, a memory space consisting of ‘n’ elements is allocated to the integer array.

When we enter the value of ‘n’ as 5, the malloc allocates 5-byte memory to the array. Thus the ‘else’ part is executed and we ask the user to enter the values of the array.

calloc()

Suppose you want to fill a box will balls. But you have only an approximate idea of the number of balls you have and the size of each. The problem is how to select a box of appropriate size so that the task of filling it with more than one ball is completed. One of the optimal solutions for this problem is to find a box of size equal to the sum of the sizes of all the balls.

In such a situation, we use the calloc function.

calloc function allocates memory at runtime.

It is defined in the stdlib.h.

Arrays and structures are allocated with memory using the calloc function.

The working of the calloc function is as follows:

Step 1: It takes the number of elements and the size of each element as input.

Step 2: Initializes each element to zero.

Step 3: Returns a void pointer to the memory.

Syntax:

void*calloc(n, S);

‘n’ is the total number of elements and ‘S’ is the size of each element.

Let’s write the same code written with the malloc function again, but this time with calloc.

Program

#include<stdio.h>
#include<stdlib.h>
int main()
{
int n;
printf("Enter number of elements:");
scanf("%d",&n);


int *p;
p=(int*)calloc(n, sizeof(int));
if(p==NULL)
{
printf("\nMemory cannot be allocated\n");
}
else
{
printf("Enter elements of array:\n");
for(int i=0;i<n;i++)
{
scanf("%d",&*(p+i));
}
printf("Elements of array are:\n");
for(int i=0;i<n;i++)
{
printf("%d\n",*(p+i));
}
}


return 0;
}

 

Output

The output we obtain from this code is exactly the same as the output of the malloc function with the difference of the number of elements and their values.

Moreover, there is a difference in the syntax because this time for the calloc function we write the statement p=(int*)calloc(n, sizeof(int));, where ‘n’ is the number of elements of the integer array (10 in this case) and ‘sizeof(int)’ is the size of each element.

Difference between malloc and calloc

The main difference between both the function is malloc never initializes the allocated memory with zero value whereas calloc function is the one that initializes the allocated memory with the zero value.

Let’s prove the statement written above with the help of programs.

Program

#include<stdio.h>
#include<stdlib.h>
int main()
{
int n;
printf("Enter number of elements:");
scanf("%d",&n);


int *p;
p=(int*)calloc(n, sizeof(int));
if(p==NULL)
{
printf("\nMemory cannot be allocated\n");
}
else
{
printf("Elements of array are:\n");
for(int i=0;i<n;i++)
{
printf("%d\n",*(p+i));
}
}


return 0;
}

 

Output

In the above code, we use the calloc function but we only specified the number of elements without initializing them. So, as a result, calloc initializes each of the elements of the array with 0 and thus the value of all the 8 elements is printed 0.

This proves that calloc function initializes the allocated memory with 0 value.

This time writing the same code as written above with malloc function.

Program

#include<stdio.h>
#include<stdlib.h>
int main()
{
int n;
printf("Enter number of elements:");
scanf("%d",&n);


int *p;
p=(int*)malloc(n* sizeof(int));
if(p==NULL)
{
printf("\nMemory cannot be allocated\n");
}
else
{
printf("Elements of array are:\n");
for(int i=0;i<n;i++)
{
printf("%d\n",*(p+i));
}
}


return 0;
}

 

Output

Using the malloc function we compile the same code but didn’t get the same output. malloc function doesn’t initialize the elements to 0 rather it assigns some garbage value to each element of the array.

realloc()

realloc is used to re-allocate the memory again. It means if we allocate more or less memory than required, then we can change the size of the previously allocated memory space.

Syntax:

Void*realloc(pointer, new-size);

‘pointer’ is the pointer variable that is used to store the realloc function.

‘new-size’ is the changed value of size.

Program

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *p;
int x=10;
int y=20;
p=(char*)malloc(x);
strcpy(p,"Coding");


p=(char*)realloc(p,y);
strcat(p," Session");
printf("%s\n",p);


return 0;
}

 

Output

‘p’ is a pointer of type ‘char’ declared in the first statement. We will dynamically allocate memory space to ‘p’.

p=(char*)malloc(x); memory space of 10 bytes is assigned to which pointer ‘p’ is pointing to. Since ‘p’ is the pointer of type void, therefore (char*) is used to typecast the pointer returned by the malloc to the character.

strcpy(p,”Coding”); “Coding” is assigned as a string value to the memory to which ‘p’ is pointing to. Since we are just storing “Coding” in the memory blocks and for that size of 10 bytes is sufficient. But if we want to store a string value of size larger than 10 bytes, then we need to expand the size of the memory space, which can only be done by realloc.

p=(char*)realloc(p,y); realloc function increases the size of the memory space (whose address is stored in ‘p’) to 20 bytes which can easily store the string of a larger size.

strcat(p,” Session”); strcat is used to concatenate the string “Session” at the end of the string “coding” that is stored in the memory space pointed by the pointer ‘p’.

Thus, the memory space pointed by the pointer ‘p’ stores the string “Coding Session”.\

free()

It is advisable to free the dynamically allocated memory after the program finishes. This is helpful because it makes the memory available for future use; otherwise, the memory space used once for a particular program gets wasted after the completion of the program if we don’t deallocate it.

The free function is used to deallocate/free the memory space after the program finishes.

Syntax:

void free(pointer);

The free function of return type void with the ‘pointer’ as the pointer variable (pointing to that memory location from which we want to deallocate the memory space) is passed as an argument.

Program:

#include<stdio.h>
#include<stdlib.h>
int main()
{
int n;
printf("Enter number of elements:");
scanf("%d",&n);


int *p;
p=(int*)malloc(n* sizeof(int));
if(p==NULL)
{
printf("\nMemory cannot be allocated\n");
}
else
{
printf("Enter elements of array:\n");
for(int i=0;i<n;i++)
{
scanf("%d",&*(p+i));
}
printf("Elements of array are:\n");
for(int i=0;i<n;i++)
{
printf("%d\n",*(p+i));
}
}
free(p);
return 0;
}

 

Output:

The code is the same as the rest of the codes discussed above, just we add one more statement, i.e., free(p); at the end of the code, which means after the completion of our code, we are releasing/deallocating the memory space pointed by the pointer ‘p’ which was dynamically allocated using malloc.

Although this part of coding is not visible as output in the frontend, it happens at the backend, where the memory gets free. It reflects the good programing skills of a programmer when we use this free function to deallocate the memory space, which was allocated dynamically by malloc, calloc, realloc functions.

 

Author

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Author