w3resource

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

C programming - Dynamic Memory Allocation

Overview:

Dynamic memory allocation is a powerful feature in C that allows you to allocate memory during runtime, which is especially useful when the amount of memory required cannot be determined before execution. The four key functions are malloc(), calloc(), realloc(), and free().

Key Topics:

Let’s discuss each function with practical examples and explanations.

malloc() - Memory Allocation

The malloc() (memory allocation) function dynamically allocates a block of memory of a specified size in bytes. The allocated memory is uninitialized, meaning it may contain arbitrary data (often referred to as garbage values). If the allocation is successful, malloc() returns a pointer to the allocated memory; otherwise, it returns NULL if the memory allocation fails.

Syntax:

void* malloc(size_t size);

The function takes a single parameter:

  • size: Here, size is the amount of memory in bytes that the malloc() function will allocate. Since size_t is an unsigned type, it cannot hold negative values, making it ideal for memory-related functions.

Example: Allocating memory for an array of integers

Code:

#include <stdio.h>
#include <stdlib.h>
int main() {
    int *arr; // Pointer to hold the base address of allocated memory
    int n = 5;
    // Allocate memory for n integers using malloc
    arr = (int*)malloc(n * sizeof(int));
    // Check if the memory allocation was successful
    if (arr == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }
    // Initialize the allocated memory with some values
    for (int i = 0; i < n; i++) {
        arr[i] = i + 1; // Assign values 1, 2, 3, 4, 5 to the array
    }
    // Print the values
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    // Free the allocated memory
    free(arr);
    return 0;
}

Output:

1 2 3 4 5

Explanation:

  • The program dynamically allocates memory for 5 integers using malloc().
  • The memory is initialized with values 1 to 5 and printed.
  • Finally, the allocated memory is freed using free().

Key Points of malloc() function:

  • malloc() allocates memory but does not initialize it.
  • Always check if malloc() returns NULL, which indicates memory allocation failure.
  • You must use free() to release the allocated memory.

calloc() - Contiguous Allocation

The calloc() function is similar to malloc() function, but it initializes the allocated memory to zero. Unlike malloc() function, it allocates memory for an array of elements, initializing all elements to zero.

Syntax:

void* calloc(size_t num, size_t size);

The function takes two parameters:

  • num: Represents the number of elements to allocate memory for. This is the count of elements you want to store.
  • size: Represents the size, in bytes, of each element. This is typically obtained using the sizeof() operator for the data type.

Example: Allocating memory for an array of integers using calloc()

Code:

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *arr;
    int n = 5;

    // Allocate memory for n integers using calloc
    arr = (int*)calloc(n, sizeof(int));

    // Check if the memory allocation was successful
    if (arr == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }
    // Print the values (they should all be 0 because of calloc)
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    // Free the allocated memory
    free(arr);
    return 0;
}

Output:

 0 0 0 0 0

Explanation:

  • The program allocates memory for 5 integers using calloc(), which ensures that the memory is initialized to zero.
  • The program prints the values, and as expected, they are all zero due to the zero-initialization provided by calloc().

Key Points of calloc() function:

  • calloc() initializes all allocated memory to zero, ensuring a clean start.
  • It's particularly useful when you need zero-initialized memory.
  • Like malloc(), if the memory allocation fails, calloc() returns NULL, so it's essential to check for this.

realloc() - Reallocation

The realloc() function is used to resize a previously allocated memory block without losing its contents. It can either shrink or expand the allocated memory.

Syntax:

void* realloc(void* ptr, size_t size);

The function takes two parameters:

  • ptr: A pointer to the memory block previously allocated using malloc(), calloc(), or realloc(). This points to the memory block you want to resize. If ptr is NULL, realloc() behaves like malloc() and allocates new memory.
  • size: The new size (in bytes) for the memory block. It can be larger or smaller than the original size. If size is zero, the memory is freed.

Example: Expanding a dynamically allocated array

Code:

#include <stdio.h>
#include <stdlib.h>
int main() {
    int *arr;
    int n = 5, new_n = 8;

    // Allocate memory for n integers using malloc
    arr = (int*)malloc(n * sizeof(int));

    // Check if memory allocation was successful
    if (arr == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }
    // Initialize the allocated memory with values
    for (int i = 0; i < n; i++) {
        arr[i] = i + 1;
    }

    // Resize the allocated memory to hold 8 integers
    arr = (int*)realloc(arr, new_n * sizeof(int));

    // Check if reallocation was successful
    if (arr == NULL) {
        printf("Memory reallocation failed!\n");
        return 1;
    }

    // Initialize new elements (index 5 to 7)
    for (int i = n; i < new_n; i++) {
        arr[i] = i + 1;
    }

    // Print the updated values
    for (int i = 0; i < new_n; i++) {
        printf("%d ", arr[i]);
    }

    // Free the allocated memory
    free(arr);
    return 0;
}

Output:

 1 2 3 4 5 6 7 8

Explanation:

  • Initially, the program allocates memory for 5 integers using malloc().
  • The memory is then resized using realloc() to hold 8 integers.
  • The newly allocated memory (indices 5 to 7) is initialized with new values, and all values are printed.

Key Points of realloc() function:

  • realloc() retains the original data in the memory block and resizes it as specified.
  • If the new size is larger, the additional memory is uninitialized (unless calloc() was used for the original allocation).
  • If realloc() fails, it returns NULL, so always check for this to prevent memory-related errors or leaks.
  • If size is set to zero, the memory is freed, behaving like a call to free().

free() - Freeing Allocated Memory

Syntax:

void free(void* ptr);

The function takes a single parameter:

  • ptr: This is a pointer to the memory block that needs to be freed. If ptr is NULL, the function does nothing. After calling free(), the memory pointed to by ptr becomes available for future allocations.

Code:

#include <stdio.h>
#include <stdlib.h>
int main() {
    int *arr;
    int n = 5;

    // Allocate memory for n integers
    arr = (int*)malloc(n * sizeof(int));

    // Check if memory allocation was successful
    if (arr == NULL) {
        printf("Memory allocation failed!\n");
        return 1;
    }

    // Use the allocated memory (e.g., initialize it)
    for (int i = 0; i < n; i++) {
        arr[i] = i + 1;
    }

    // Free the allocated memory
    free(arr);

    // Now arr is a dangling pointer; we should set it to NULL
    arr = NULL;

    return 0;
}

Explanation:

  • The program allocates memory for n integers using malloc() function.
  • The allocated memory is used and then freed using free(), which releases the memory back to the system.
  • After freeing the memory, the pointer arr is set to NULL to avoid accessing a dangling pointer, which could lead to undefined behavior.

Key Points of free() function:

  • Always call free() to release memory when it is no longer needed to prevent memory leaks.
  • Accessing memory after it has been freed leads to undefined behavior.
  • Setting the pointer to NULL after freeing the memory helps prevent accidental use of a dangling pointer.

When to use each function malloc(), calloc(), realloc(), and free()

malloc():

  • Use when you need to allocate a specific amount of uninitialized memory during runtime.
  • Ideal for single-block allocations where memory initialization isn't required.
  • Note: malloc() returns NULL if the memory allocation fails.

calloc():

  • Use when you need to allocate memory for an array of elements and want the memory to be zero-initialized.
  • Preferred when you require the memory to be pre-set to zero.
  • Note: calloc() returns NULL if the memory allocation fails.

realloc():

  • Use when you need to resize a previously allocated memory block without losing its content.
  • Ideal for dynamically resizing arrays or buffers as more memory is needed.

free():

  • Use to release previously allocated memory when it is no longer needed.
  • Prevents memory leaks by deallocating dynamically allocated memory.


Become a Patron!

Follow us on Facebook and Twitter for latest update.

It will be nice if you may share this link in any developer community or anywhere else, from where other developers may find this content. Thanks.

https://w3resource.com/c-programming/c-dynamic-memory-allocation.php