Understanding Dynamic Memory Allocations in C - BunksAllowed

BunksAllowed is an effort to facilitate Self Learning process through the provision of quality tutorials.

Community

Understanding Dynamic Memory Allocations in C

Share This


In C, dynamic memory allocation is a very important area, which you should know. Let us start with an example.

If you want to work with an array. You have to specify the size of the array at the time of declaration. Now, some users may work with a large number of data and some users may work with a very small number of data. So, as a developer, you should declare the array with such a size, which can be used by every user.

Here the problem is, that if the user works with a very small number of data, a huge volume of memory space is not in use. And using an array, memory is being allocated based on its size specified at the time of declaration. But if this memory can be allocated at run time, it will be beneficial.

Hence, using dynamic memory allocation, the chunk of memory can be allocated at run time.


In the C programming language, three functions (malloc, calloc and realloc) are used for dynamic memory allocation and one function (free) is used for de-allocation.

Please note that you have to include stdlib.h in order to use malloc or calloc or realloc or free


malloc It takes one argument which should be an unsigned integer value dictating the function of how many bytes of storage to allocate.

In general, this unsigned integer is placed as n*sizeof(datatype) format where n is the number of elements to be stored and sizeof (datatype) gives the memory requirement (in bytes) for the corresponding data type

Usage of sizeof ensures the correct memory requirement for a corresponding data type in changing operating systems, thereby maintaining the portability of the program.

It does not initialize the newly allocated memory. Function malloc returns a void * or generic pointer to its caller. This void * will actually point to the first location of the allocated memory.

As the memory pointed by void * can store any data type, hence the programmer has to cast it as per the requirement of the code.

For example, if malloc is being used to allocate memory space to store some integers, hence the call to malloc has to be cast properly as int * instead of void * and the returned pointer must be caught back by an int *

Let us consider that we want to store n (a dynamic value received from the user) number of integers in an array.

The following code snippet will do it

int *p;
p = (int *) malloc (n * sizeof(int));

It is noteworthy, that the memory allocated by malloc has necessarily to be in a chunk and monolithic. 
calloc Function calloc is also used to allocate memory dynamically. It takes two arguments, where the first argument should be an unsigned integer value dictating the function about the number of elements for which memory will be allocated and the second argument is the size of an element.

Hence the argument of the calloc is placed as n, sizeof(datatype).

The return type of calloc is the same void * as calloc and all the discussions related to the return type and its proper casting of malloc are equally true for calloc also.

Function calloc initializes the newly allocated memory by default value.

Function calloc differs a little from malloc while allocating the memory. First, it tries to allocate memory as a monolithic chunk as malloc, and if it fails to do so for the shortage of contiguous memory, then it allocates n number of smaller memories of size sizeof(datatype). So using calloc never guarantees allocated memory to be monolithic.  

Let us consider that we want to store the k (a dynamic value received from the user) number of floats in an array.

The following code snippet will do it

float *k;
k = (float *) calloc (n , sizeof(float));

realloc The realloc is a function that attempts to change the size of a previously allocated block of memory. The new size can be larger or smaller. If the block is made larger then the old contents remain unchanged and memory is added to the end of the block. If the size is made smaller then the remaining contents are unchanged.

It takes two arguments as void * and new memory requirement as an unsigned integer. The first argument void * points to the base address of the memory previously allocated.

There might be an interesting case while realloc tries to increase the memory and fails to find that much memory in place. In this situation, a whole new monolithic chunk of memory is discovered and the existing data is first copied and then the base address of the newly found monolithic memory is returned as void *.  This returned void * must be properly cast as per the data type of existing elements.

Even the trickier situation might so happen that realloc does not discover any monolithic chunk as per the memory requirement at all. In that case, realloc will fail and a NULL pointer would be returned.

Hence realloc ensures that the allocated memory would always be in a chunk.
free If we want to de-allocate memory from a pointer uses the free function. It takes the void * as an argument and this void *  actually points the memory to be de-allocated.

Example using malloc


#include <stdio.h> #include <stdlib.h> int main(void) { int i, n, *ptr, sum = 0; // take number of elements as input printf("How many elements do you want to store?"); scanf("%d", &n); ptr = (int *) malloc(n * sizeof(int)); // test default values of ptr for(i = 0; i < n; i++) printf(" %d ", ptr[i]); // take the elements as input printf("Enter the elements:"); for(i = 0; i < n; i++) scanf("%d", &ptr[i]); // calculate sum for(i = 0; i < n; i++) sum += ptr[i]; printf("\nSum is %d", sum); return 0; }

Example using calloc


#include <stdio.h> #include <stdlib.h> int main(void) { int i, n, *ptr, sum = 0; // take number of elements as input printf("How many elements do you want to store?"); scanf("%d", &n); ptr = (int *) calloc(n, sizeof(int)); // test default values of ptr for(i = 0; i < n; i++) printf(" %d ", ptr[i]); // take the elements as input printf("Enter the elements:"); for(i = 0; i < n; i++) scanf("%d", &ptr[i]); // calculate sum for(i = 0; i < n; i++) sum += ptr[i]; printf("\nSum is %d", sum); return 0; }

Example using realloc


The following program illustrates how the realloc function is used to change memory allocation at run-time.

In this program, first, a memory block is allocated for the variable str. Later we need to change the size of the memory block, thus we have to call the realloc function to increase the size of the memory block. This function performs reallocation without affecting previous data.

In this function, we are also using the free function to deallocate the memory which is pointed by variable str.

#include <stdio.h> #include <stdlib.h> int main(void) { int i, j, n, *ptr, sum = 0; // take number of elements as input printf("How many elements do you want to store? "); scanf("%d", &n); ptr = (int *) calloc(n, sizeof(int)); // test default values of ptr for(i = 0; i < n; i++) printf(" %d ", ptr[i]); printf("\n"); // take the elements as input printf("Enter the elements:"); for(i = 0; i < n; i++) scanf("%d", &ptr[i]); // calculate sum for(i = 0; i < n; i++) sum += ptr[i]; printf("\nSum is %d", sum); // take number of elements as input printf("\nIf you want to store more elements? \nEnter number of elements you want to store. "); scanf("%d", &n); ptr = (int *) realloc (ptr, n); // take the elements as input printf("Enter additional elements:"); for(j = i; j < n; j++) scanf("%d", &ptr[j]); // calculate sum for(j = i; j < n; j++) sum += ptr[j]; printf("\nSum is %d", sum); free(ptr); return 0; }

Dynamic memory allocation for 2D array.


#include <stdio.h> #include <stdlib.h> int main() { int i, j, m, n; int **arr; int *row; printf("Enter the order of matrix 1: "); scanf("%d %d", &m, &n); arr = (int **) malloc (m * sizeof(int *)); for(i = 0; i < m; i++) { row = (int *) malloc (n * sizeof(int)); arr[i] = row; } printf("Enter the values of matrix 1: \n"); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { scanf("%d", &arr[i][j]); } } printf("The given matrix is: \n"); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) { printf(" %d", arr[i][j]); } printf("\n"); } return 0; }

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.