Dynamic Memory Allocation in C

What is dynamic memory allocation?

dynamic memory allocation in c
  • Dynamic memory allocation in C allows programs to request and use memory at runtime, providing the flexibility to adapt to varying memory needs.
  • By allocating memory only when needed and deallocating it when no longer required, dynamic allocation ensures efficient use of system resources.
  • Pointers play a crucial role in managing dynamically allocated memory, as they hold the addresses of memory blocks.
  • Memory leaks (forgetting to deallocate memory) and dangling pointers (pointing to deallocated memory) are common errors that can lead to program crashes or unpredictable behavior.

Memory can be allocated to the variables in two different ways: static memory allocation and dynamic memory allocation.

Static Memory Allocation: 

The memory which is allocated to the variables before executing the program is called static memory allocation.

Advantages of static memory allocation:

  1. Static memory allocation offers simplicity and ease of use, as memory management is handled automatically by the compiler.
  2. Faster execution times are achieved due to the absence of runtime memory allocation overhead.
  3. Predictable memory usage prevents fragmentation and ensures efficient utilization of resources.
  4. The risk of memory leaks is eliminated, as memory is automatically deallocated when it’s no longer needed.
  5. Stack-based allocation promotes better cache utilization and potentially improved performance compared to heap-based dynamic allocation.

Disadvantages of static memory allocation:

  1. The memory size is fixed.
  2. We cannot increase or decrease the size of the variable.
  3. If it is not properly used, memory gets wasted.

Dynamic Memory Allocation: 

The memory that is allocated to the variables during the execution of the program is called dynamic memory allocation.

The memory is allocated from a region called heap memory to the variables at the time of program execution. 

When we use DMA functions we have to specify the header file stdlib.h, #include<stdlib.h>

The different dynamic memory allocation functions are mallac(), callac(), reallac(), free().

mallac(): 

It is used to allocate a single block of memory. This function returns a void pointer. So we must specify an explicit type of conversion to convert the void pointer into any one of the basic data type pointers

After allocating the memory, the pointer will be pointed to the first byte of the memory

The syntax is

pointer variable = (typecast x)mallac(size);

P=(intx)mallac(40);

P=(intx)mallac(size of (int));

P= (intx)mallac(n*size of(int));

C program using malloc()

#include <stdio.h>
#include <stdlib.h>
int main() {
    // Declare a pointer to an integer
    int *ptr;
    int n, i; // Variables for array size and loop counter
    // Get the number of elements for the dynamic array from the user
    printf("Enter number of elements: ");
    scanf("%d", &n);
    printf("Entered number of elements: %d\n", n); // Echo the input for clarity
    // Dynamic Memory Allocation using malloc()
    // Allocate a block of memory large enough to hold 'n' integers
    ptr = (int*)malloc(n * sizeof(int)); 
    // Error Handling: Check if memory allocation was successful
    if (ptr == NULL) {
        printf("Memory not allocated.\n"); // Indicate failure
        exit(0); // Terminate the program if allocation fails
    } else {
        // Memory allocation successful
        printf("Memory successfully allocated using malloc.\n"); // Success message
        // Initialize the elements of the dynamically allocated array
        // Store consecutive numbers starting from 1
        for (i = 0; i < n; ++i) {
            ptr[i] = i + 1; 
        }
        // Print the elements of the dynamic array
        printf("The elements of the array are: ");
        for (i = 0; i < n; ++i) {
            printf("%d, ", ptr[i]); // Access elements using pointer arithmetic
        }
        printf("\n"); // Newline for better formatting
    }
    // Note: The dynamically allocated memory is NOT explicitly freed in this example.
    // It's generally good practice to free memory with `free(ptr)` when done,
    // but in this simple case, the OS will reclaim it on program termination.
    return 0; // Successful program execution
}

Output:

Enter number of elements: 4
Entered number of elements: 4
Memory successfully allocated using malloc.
The elements of the array are: 1, 2, 3, 4,

Callac():  

This function is also used to allocate a continuous block of memory. All the blocks are arranged sequentially like an array. All the blocks are initialized with a value of 0.  

The syntax is

pointer variable = (typecast x)callac(n, size);

P=(intx)callac(10, size of (int));

C program using calloc()

#include <stdio.h>
#include <stdlib.h>
int main() {
    // Declare a pointer to an integer
    int *ptr;
    int n, i; // Variables for array size and loop counter
    // Get the number of elements for the dynamic array from the user
    printf("Enter number of elements: ");
    scanf("%d", &n);
    printf("Entered number of elements: %d\n", n); // Echo the input
    // Dynamic Memory Allocation using calloc()
    // Allocate a block of memory for 'n' integers and initialize each element to 0
    ptr = (int*)calloc(n, sizeof(int)); 
    // Error Handling: Check if memory allocation was successful
    if (ptr == NULL) {
        printf("Memory not allocated.\n"); // Indicate failure
        exit(0); // Terminate the program if allocation fails
    } else {
        // Memory allocation successful
        printf("Memory successfully allocated using calloc.\n"); // Success message
        // Get elements of the dynamic array from the user
        // Note: calloc already initialized elements to 0, but we overwrite here
        printf("Enter elements:\n");
        for (i = 0; i < n; ++i) {
            scanf("%d", ptr + i); // Access elements using pointer arithmetic
        }
        // Print the elements of the dynamic array
        printf("The elements of the array are: ");
        for (i = 0; i < n; ++i) {
            printf("%d, ", ptr[i]);
        }
        printf("\n"); // Newline for formatting
    }
    // Free the dynamically allocated memory
    free(ptr); // It's crucial to free memory to prevent leaks
    return 0; // Successful program execution
}

Output:

Enter number of elements: 4
Entered number of elements: 4
Memory successfully allocated using calloc.
Enter elements:
20 10 90 50
The elements of the array are: 20, 10, 90, 50,

reallac(): 

This function is used for reallocating the memory. This function is used to increase/decrease the size of the memory. This function can be used after specifying the mallac/callac function.

The syntax is

Pointer variable=(typecast *)reallac(pointer variable, size);

P=(int *)reallac(P, 80);

P=(int *)reallac(P, 10);

C program using realloc()

#include <stdio.h>
#include <stdlib.h>
int main() {
    // Declare a pointer to an integer
    int *ptr;
    int n, i; // Variables for initial and updated array sizes
    // Get the initial number of elements
    printf("Enter the initial number of elements: ");
    scanf("%d", &n);
    printf("Entered initial number of elements: %d\n", n);
    // Dynamically allocate memory using malloc() for the initial size
    ptr = (int*)malloc(n * sizeof(int)); 
    // Error handling: Check if memory allocation was successful
    if (ptr == NULL) {
        printf("Memory not allocated.\n"); // Indicate failure
        exit(0); // Terminate the program if allocation fails
    } else {
        // Memory allocation successful
        printf("Memory successfully allocated using malloc.\n");
        // Get elements for the initial array
        printf("Enter elements:\n");
        for (i = 0; i < n; ++i) {
            scanf("%d", ptr + i); 
        }
        // Get the updated number of elements
        printf("Enter the new size of the array: ");
        scanf("%d", &n);
        printf("Entered new size: %d\n", n);
        // Dynamically reallocate memory using realloc()
        // Attempt to resize the existing block of memory
        ptr = (int*)realloc(ptr, n * sizeof(int));
        // Error handling: Check if memory reallocation was successful
        if (ptr == NULL) {
            printf("Memory reallocation failed.\n");
            free(ptr); // Free the original memory to prevent leaks
            exit(0);
        } else {
            // Memory reallocation successful
            printf("Memory successfully reallocated using realloc.\n");
            // If the new size is larger, get additional elements
            if (n > i) {
                printf("Enter the new elements:\n");
                for (; i < n; ++i) { // Continue from the previous index
                    scanf("%d", ptr + i);
                }
            }
            // Print the elements of the resized array
            printf("The elements of the array are: ");
            for (i = 0; i < n; ++i) {
                printf("%d, ", ptr[i]);
            }
            printf("\n");
        }
    }
    
    // Free the dynamically allocated memory
    free(ptr); // Free the memory after reallocation
    return 0; // Successful program execution
}

Output:

Enter the initial number of elements: 4
Entered initial number of elements: 4
Memory successfully allocated using malloc.
Enter elements:
50 40 30 10
Enter the new size of the array: 4
Entered new size: 4
Memory successfully reallocated using realloc.
The elements of the array are: 50, 40, 30, 10,

free(): 

This function is used to deallocate the memory.

The syntax is

free(pointer variable);

free(P);

C program using free()

#include <stdio.h>
#include <stdlib.h>
int main() {
    // Declare a pointer to an integer
    int *ptr;
    int n, i; // Variables for initial and updated array sizes
    // Get the initial number of elements
    printf("Enter the initial number of elements: ");
    scanf("%d", &n);
    printf("Entered initial number of elements: %d\n", n);
    // Dynamically allocate memory using malloc() for the initial size
    ptr = (int*)malloc(n * sizeof(int)); 
    // Error handling: Check if memory allocation was successful
    if (ptr == NULL) {
        printf("Memory not allocated.\n"); // Indicate failure
        exit(0); // Terminate the program if allocation fails
    } else {
        // Memory allocation successful
        printf("Memory successfully allocated using malloc.\n");
        // Get elements for the initial array
        printf("Enter elements:\n");
        for (i = 0; i < n; ++i) {
            scanf("%d", ptr + i); 
        }
        // Process and use the elements (e.g., calculate sum, find max, etc.)
        // ... (Your code to work with the array would go here) ...
        int sum = 0;
        for (i = 0; i < n; ++i) {
            sum += ptr[i];
        }
        printf("Sum of elements: %d\n", sum);
        // Free the dynamically allocated memory
        free(ptr);
        printf("Memory successfully freed.\n"); // Indicate successful deallocation
        // Now, ptr is a dangling pointer (pointing to invalid memory)
        // Get the updated number of elements
        printf("Enter the new size of the array: ");
        scanf("%d", &n);
        printf("Entered new size: %d\n", n);
        // Dynamically allocate memory using malloc() for the new size
        ptr = (int*)malloc(n * sizeof(int)); // Allocate new memory
        // Error handling: Check if memory allocation was successful
        if (ptr == NULL) {
            printf("Memory not allocated.\n"); // Indicate failure
            exit(0); // Terminate the program if allocation fails
        } else {
            // Memory allocation successful
            printf("Memory successfully allocated (again) using malloc.\n");
            // Get new elements for the resized array
            printf("Enter new elements:\n");
            for (i = 0; i < n; ++i) {
                scanf("%d", ptr + i);
            }
        }
    }
    // Free the dynamically allocated memory again (for the second allocation)
    free(ptr); 
    printf("Memory successfully freed (again).\n");
    return 0; // Successful program execution
}

Output:

Enter the initial number of elements: 4
Entered initial number of elements: 4
Memory successfully allocated using malloc.
Enter elements:
80 30 50 10
Sum of elements: 170
Memory successfully freed.
Enter the new size of the array: 4
Entered new size: 4
Memory successfully allocated (again) using malloc.
Enter new elements:
80 15 26 9
Memory successfully freed (again).

Difference Between malloc and calloc in C

Featuremalloc()calloc()
PurposeAllocates a single block of memoryAllocates multiple blocks of memory, each of the same size, and initializes them to zero
ArgumentsTakes one argument: the size of the memory block in bytesTakes two arguments: the number of blocks to allocate and the size of each block in bytes
Return ValueReturns a void pointer to the allocated memory block. If the allocation fails, it returns NULLReturns a void pointer to the allocated memory block. If the allocation fails, it returns NULL
Memory InitializationDoes not initialize the allocated memory. The contents of the memory block are undefinedInitializes all bytes of the allocated memory to zero
Use CaseWhen you need to allocate a single block of memory and don’t need to initialize it to zeroWhen you need to allocate multiple blocks of memory of the same size and want them to be initialized to zero (e.g., arrays)
EfficiencyGenerally more efficient than calloc() for allocating a single block, as it doesn’t perform initializationLess efficient than malloc() for allocating a single block due to the overhead of initialization

FAQs of dynamic memory allocation in C

  1. What are the differences between malloc() and calloc()?

Both functions allocate memory dynamically, but calloc() initializes all allocated bytes to zero while malloc() leaves them uninitialized. calloc() also takes two arguments (number of elements and size of each element) compared to malloc()’s single argument (total size in bytes).

  1. How do I prevent memory leaks in dynamic memory allocation?

Memory leaks occur when you forget to free dynamically allocated memory using free(). 

Always ensure that for every malloc(), calloc(), or realloc(), there’s a corresponding free() when the memory is no longer needed.

  1. What happens if malloc(), calloc(), or realloc() fail to allocate memory?

These functions return a NULL pointer if memory allocation fails. It’s essential to check the returned pointer for NULL and handle the error appropriately, such as terminating the program or trying to allocate a smaller block of memory.

  1. What’s the purpose of realloc() and when should I use it?

realloc() is used to resize an existing block of dynamically allocated memory. It’s useful when you need to expand or shrink the size of an array or other data structure during runtime.

  1. What are dangling pointers and how can I avoid them?

Dangling pointers are pointers that point to memory that has been freed. To avoid dangling pointers, always set the pointer to NULL after calling free() on it, and avoid using a pointer after the memory it points to has been deallocated.

Scroll to Top