Industrial manufacturing
Industrial Internet of Things | Industrial materials | Equipment Maintenance and Repair | Industrial programming |
home  MfgRobots >> Industrial manufacturing >  >> Industrial programming >> C Language

Dynamic Memory Allocation in C: Mastering malloc, calloc, realloc, and free

Before diving into dynamic memory allocation in C, it’s essential to understand how memory is managed in the language.

How Memory Management Works in C

When you declare a variable with a primitive type, the compiler allocates space for it on the stack automatically. For example, a float typically occupies 4 bytes (platform‑dependent). You can confirm this with the sizeof operator:

#include <stdio.h>
int main() { float x; printf("The size of float is %d bytes", sizeof(x)); return 0; }

The output will be:

The size of float is 4 bytes

An array of a specified size is also allocated contiguously on the stack, with each element occupying the size of its type:

#include <stdio.h>
int main() { float arr[10]; printf("The size of the float array with 10 elements is %d", sizeof(arr)); return 0; }

The result is:

The size of the float array with 10 elements is 40

While stack allocation is automatic, many programs require memory whose size is not known until runtime. This need is addressed by dynamic memory allocation, which uses the heap instead of the stack.

Dynamic Memory Allocation in C

Dynamic allocation involves manually requesting and releasing memory as needed, with pointers tracking the allocated blocks on the heap. The C standard library provides several functions for this purpose:

Let’s explore each function in detail.

malloc() Function

The malloc() function stands for “memory allocation.” It reserves a block of memory of a specified size and returns a pointer to it. The pointer is typically cast to the desired type:

ptr = (cast_type *) malloc(byte_size);

Example:

#include <stdlib.h>
int main(){
    int *ptr;
    ptr = malloc(15 * sizeof(*ptr)); /* 15 integers */
    if (ptr != NULL) {
        *(ptr + 5) = 480; /* sixth element */
        printf("Value of the 6th integer is %d", *(ptr + 5));
    }
}

Output:

Value of the 6th integer is 480

Key points:

  1. Use sizeof(*ptr) to make the code robust against type changes.
  2. Check for a NULL return value to detect allocation failure.
  3. Allocated memory is contiguous; treat it as an array and use pointer arithmetic.

Dynamic allocation is not limited to primitive types; it works with structures, character arrays, and more.

free() Function

Memory allocated with malloc(), calloc(), or realloc() must be released explicitly to avoid leaks. The free() function performs this task:

#include <stdio.h>
int main() {
    int* ptr = malloc(10 * sizeof(*ptr));
    if (ptr != NULL){
        *(ptr + 2) = 50;
        printf("Value of the 2nd integer is %d", *(ptr + 2));
    }
    free(ptr);
}

Output:

 Value of the 2nd integer is 50

calloc() Function

calloc() allocates multiple blocks of equal size and initializes every byte to zero, making it ideal for arrays and structures that require zeroed memory:

ptr = (cast_type *) calloc(n, size);

Example – summing an arithmetic sequence:

#include <stdio.h>
int main() {
    int i, *ptr, sum = 0;
    ptr = calloc(10, sizeof(int));
    if (ptr == NULL) {
        printf("Error! memory not allocated.");
        exit(0);
    }
    for (i = 0; i < 10; ++i) {
        *(ptr + i) = i;
        sum += *(ptr + i);
    }
    printf("Sum = %d", sum);
    free(ptr);
    return 0;
}

Result:

Sum = 45

calloc() vs. malloc()

Key differences:

realloc() Function

The realloc() function changes the size of an existing allocation while preserving its contents:

ptr = realloc(ptr, newsize);

Example – extending a string buffer:

#include <stdio.h>
int main () {
    char *ptr = malloc(10);
    strcpy(ptr, "Programming");
    ptr = realloc(ptr, 20); // enlarge
    strcat(ptr, " In 'C'");
    printf("%s, Address = %u", ptr, ptr);
    free(ptr);
    return 0;
}

If reallocation fails, realloc() returns NULL and the original block remains valid.

Dynamic Arrays

Dynamic arrays allow the number of elements to grow during execution, a common pattern in algorithms and data structures:

#include <stdio.h>
int main() {
    int *arr_dynamic = NULL;
    int elements = 2, i;
    arr_dynamic = calloc(elements, sizeof(int));
    for (i = 0; i < elements; i++) arr_dynamic[i] = i;
    for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
    elements = 4;
    arr_dynamic = realloc(arr_dynamic, elements * sizeof(int));
    printf("After realloc\n");
    for (i = 2; i < elements; i++) arr_dynamic[i] = i;
    for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]);
    free(arr_dynamic);
}

Result:

arr_dynamic[0]=0
arr_dynamic[1]=1
After realloc
arr_dynamic[0]=0
arr_dynamic[1]=1
arr_dynamic[2]=2
arr_dynamic[3]=3

Summary

C Language

  1. Mastering C# Using Statements: Imports, Aliases, and Static Directives
  2. Mastering C++ Functions: From Basics to Advanced Usage
  3. Mastering C Functions: User-Defined and Standard Library Basics
  4. Dynamic Memory Allocation in C: Mastering malloc, calloc, realloc, and free
  5. Master C++ Dynamic Array Allocation: A Practical Guide with Code Examples
  6. malloc vs calloc: Key Differences Explained with Practical Examples
  7. calloc() in C: Zero‑Initialized Memory Allocation and a Practical Example
  8. Java Stack vs. Heap: A Practical Memory Allocation Guide
  9. Mastering C++ Dynamic Memory: Stack vs. Heap Explained
  10. Java 10 Enhancements: Allocate Heap on NV‑DIMM with -XX:AllocateHeapAt