In C, the realloc function is used to resize a previously allocated block of memory, enabling you to increase or decrease its size during runtime. This is particularly useful when you need to expand or shrink the size of an existing memory allocation, without losing the original data.

1. realloc Function Overview

  • Declared in the <stdlib.h> header file.
  • Used to resize an already dynamically allocated memory block.
  • Can be used to extend or reduce the size of a previously allocated memory block.
  • If the resizing is successful, realloc returns a pointer to the newly allocated memory. If not, it returns NULL.

2. Syntax

void* realloc(void* ptr, size_t new_size);
  • ptr: A pointer to the memory previously allocated using malloc, calloc, or realloc. If ptr is NULL, realloc behaves like malloc.
  • new_size: The new size of the memory block in bytes.

3. How realloc Works

  • If ptr is NULL, realloc acts like malloc and allocates new_size bytes.
  • If new_size is 0 and ptr is not NULL, realloc behaves like free and releases the memory.
  • If the new memory block is larger, realloc copies the old content to the new block and may fill additional memory with undefined values.
  • The function may return a new memory address if the old memory block cannot be resized in place. In this case, the data is copied to the new location, and the old block is freed.

4. Usage Example

#include <stdio.h> #include <stdlib.h> int main() { int *arr; int n = 5; // Allocate initial memory for 5 integers arr = (int *)malloc(n * sizeof(int)); if (arr == NULL) { printf("Initial memory allocation failed!\n"); return 1; } // Assign values to the allocated memory for (int i = 0; i < n; i++) { arr[i] = i + 1; } // Print initial values printf("Initial array: "); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); // Resize the array to hold 10 integers n = 10; arr = (int *)realloc(arr, n * sizeof(int)); if (arr == NULL) { printf("Memory reallocation failed!\n"); return 1; } // Assign new values to the additional memory for (int i = 5; i < n; i++) { arr[i] = i + 1; } // Print the updated array printf("Resized array: "); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); // Free the allocated memory free(arr); return 0; }

Explanation:

  1. Initial Allocation: The array is allocated for 5 integers using malloc.
  2. Memory Reallocation: The array is resized using realloc to hold 10 integers.
  3. Using Additional Memory: New values are assigned to the extra memory locations.
  4. Free Memory: The entire block is freed using free.

Output Example:

Initial array: 1 2 3 4 5 Resized array: 1 2 3 4 5 6 7 8 9 10

5. Important Considerations

  1. Data Preservation:

    • realloc preserves the data in the original memory block when resizing, but if a new memory location is required, it moves the data to the new block.
    • Be careful, as the old pointer (ptr) may become invalid if realloc moves the memory to a new location.
  2. Memory Leaks:

    • If realloc returns NULL due to a failure (e.g., insufficient memory), the original block remains allocated, potentially leading to a memory leak if not handled properly.
    • Always assign the result of realloc to a temporary pointer first, then check for NULL.

    Example:

    int *temp = realloc(arr, new_size); if (temp == NULL) { // Handle allocation failure } else { arr = temp; // Update the pointer if allocation succeeded }
  3. Shrinking Memory:

    • If new_size is smaller than the original size, the extra memory is deallocated.
    • However, be careful with accessing memory beyond the new size, as this leads to undefined behavior.
  4. Freeing Memory:

    • Memory allocated or reallocated by realloc must eventually be freed using free to avoid memory leaks.

6. Example: Shrinking Memory

#include <stdio.h> #include <stdlib.h> int main() { int *arr; int n = 10; // Allocate memory for 10 integers arr = (int *)malloc(n * sizeof(int)); if (arr == NULL) { printf("Memory allocation failed!\n"); return 1; } // Assign values to the allocated memory for (int i = 0; i < n; i++) { arr[i] = i + 1; } // Shrink the memory to hold only 5 integers n = 5; arr = (int *)realloc(arr, n * sizeof(int)); if (arr == NULL) { printf("Memory reallocation failed!\n"); return 1; } // Print the resized array printf("Shrunk array: "); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); // Free the allocated memory free(arr); return 0; }

Output Example:

Shrunk array: 1 2 3 4 5

Summary

  • realloc is used to resize memory that has already been dynamically allocated.
  • It allows for both expanding and shrinking the allocated memory block.
  • Always check the return value of realloc to ensure memory allocation was successful.
  • Be careful to prevent memory leaks by properly handling failures (NULL return value).
  • If realloc moves the memory block, it automatically copies the contents of the old block to the new one, which might result in a new memory address.

Using realloc effectively helps manage dynamically changing memory needs in C, making it useful for dynamic data structures like dynamic arrays or linked lists, where the number of elements may vary during runtime.