- If the pointer passed to realloc is NULL , it behaves like malloc and allocates a new memory block of the given size.
- If the size passed to realloc is zero , it behaves like free and deallocates the memory block pointed to by the pointer.
- If the size passed to realloc is greater than the size of the previously allocated memory block, it will try to extend the existing memory block. Suppose the memory block cannot be expanded due to the system's lack of memory. It will allocate a new memory block of the specified size, copy the contents of the old block to the new block, release the old block, and return a reference to the new block.
- If the size passed to realloc is less than or equal to the size of the previously allocated memory block, it will try to shrink the existing memory block. If the memory block can be shrunk, it will return a pointer to the same memory block. It will allocate a new block of memory of the specified size, copy the contents of the old block to the new block, release the old block, and return a pointer to the new block if the memory block can't be shrunk.
It is crucial to understand that realloc has the capability to relocate the memory block to a different location if it is unable to expand or reduce the current block in its original place. Consequently, any pointers or references pointing to the previous block will no longer be valid following the realloc function call.
Example code showing the usage of "realloc":
#include <stdio.h>
#include <stdlib.h>
int main() {
int *ptr = (int*) malloc(3 * sizeof(int));
ptr[0] = 1;
ptr[1] = 2;
ptr[2] = 3;
// resize the memory block to hold 5 integers
ptr = (int*) realloc(ptr, 5 * sizeof(int));
ptr[3] = 4;
ptr[4] = 5;
for (int i = 0; i< 5; i++) {
printf("%d ", ptr[i]);
}
// free the memory block
free(ptr);
return 0;
}
Output
1 2 3 4 5
Explanation:
In this instance, we initially reserve a memory block to store 3 integers utilizing malloc. Subsequently, we assign values to the integers and display them. Following this, we utilize realloc to adjust the size of the memory block to accommodate 5 integers. We assign values to the additional integers and display them. Ultimately, we release the memory block by implementing free.
Features of realloc
There are various features of realloc . Some important features of realloc are as follows:
- It is important to check the return value of realloc for errors. If realloc returns NULL , the memory allocation has failed, and the old memory block is still valid. In this case, the program should handle the error and possibly exit or return an error code.
- When resizing a memory block with realloc , the contents of the old memory block may be preserved or moved to a new location. It is not guaranteed which will happen, so you should always assume that the old memory block may be moved and update any pointers or references to the block accordingly.
- In most cases, "Realloc" is more effective than creating a new memory block and transferring the information from the old block to the new block. It is because realloc can take advantage of any unused memory space adjacent to the old block, whereas allocating a new block requires finding a new contiguous block of memory and copying the data.
- When shrinking a memory block with realloc , any data beyond the new size will be lost. It is important to be careful when using realloc to avoid unintentionally losing data.
- realloc is a relatively low-level function that can be error-prone if used incorrectly. It is often better to use higher-level data structures or libraries that handle memory management automatically, such as std::vector in C++ or ArrayList in Java .
Syntax of realloc
The syntax of realloc is as follows:
void realloc(void ptr, size_t size);
When ptr points to the memory block previously reserved using malloc, calloc, or realloc, and size indicates the updated size of the memory block in bytes, the function will return a pointer to the adjusted memory block if the allocation is successful. Otherwise, it will return NULL.
Additional code snippets demonstrating the application of the 'realloc' function in the C programming language:
Implementing a dynamic stack
One typical scenario where 'realloc' is frequently applied is in developing a flexible stack data structure. Below is a demonstration:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int* arr;
int top;
int size;
} Stack;
Stack* create_stack(int size) {
Stack* stack = (Stack*)malloc(sizeof(Stack));
if (stack == NULL) {
printf("Failed to allocate memory\n");
return NULL;
}
stack->arr = (int*)malloc(size * sizeof(int));
if (stack->arr == NULL) {
printf("Failed to allocate memory\n");
free(stack);
return NULL;
}
stack->top = -1;
stack->size = size;
return stack;
}
void push(Stack* stack, int x) {
if (stack->top == stack->size - 1) {
// stack is full, resize it
int new_size = 2 * stack->size;
int* new_arr = (int*)realloc(stack->arr, new_size * sizeof(int));
if (new_arr == NULL) {
printf("Failed to reallocate memory\n");
return;
}
stack->arr = new_arr;
stack->size = new_size;
}
stack->top++;
stack->arr[stack->top] = x;
}
int pop(Stack* stack) {
if (stack->top == -1) {
printf("Stack is empty\n");
return -1;
}
int x = stack->arr[stack->top];
stack->top--;
return x;
}
void free_stack(Stack* stack) {
free(stack->arr);
free(stack);
}
int main() {
Stack* stack = create_stack(3);
if (stack == NULL) {
return 1;
}
push(stack, 1);
push(stack, 2);
push(stack, 3);
push(stack, 4);
push(stack, 5);
printf("%d\n", pop(stack));
printf("%d\n", pop(stack));
printf("%d\n", pop(stack));
printf("%d\n", pop(stack));
printf("%d\n", pop(stack));
free_stack(stack);
return 0;
}
Output
5
4
3
2
1
Explanation:
In this implementation, we use malloc to allocate memory for the stack and its array of size. We use realloc in the push function to resize the array if it becomes full. We also implement a pop function to remove and return the top element of the stack, and a free_stack function to free the memory allocated for the stack and its array.
- The size argument to realloc can be zero. In this case, realloc behaves like free and deallocates the memory block pointed to by ptr .
- Realloc returns NULL if it is unable to allocate memory, leaving the initial memory block unaltered. In this case, it is important to avoid overwriting the original pointer, as it will cause a memory leak.
- It is important to note that the memory block pointed to by ptr must have been allocated using malloc, calloc , or realloc .
- When resizing a block of memory using realloc , the contents of the original block are preserved up to the smaller of the old and new sizes. The extra memory is uninitialized if the new size is more than the old size.
- It is generally a good idea to use a temporary variable to store the result of realloc, in case it returns NULL . It allows you to avoid overwriting the original pointer and causing a memory leak.
- When resizing an array, the new size should be specified in terms of the desired number of elements, not the total number of bytes. It is because realloc works with pointer types , not byte types . For example, if you want to resize an array of integers to have 10 elements , you should pass 10 * sizeof(int) as the second argument to realloc .
- It's important to use the appropriate size when copying the elements from the old array to the new array when resizing an array. If you use the wrong size, you may end up copying too much or too little data, leading to memory corruption or other errors. For example, if you are resizing an array of integers and you copy the elements using memcpy , you should use sizeof(int) as the size argument.
- If you are resizing an array of structs , keep in mind that the memory layout of the struct may change if you add or remove It can cause problems if you're relying on the old memory layout to access the fields of the struct. In this case, you may need to manually copy the fields to the new array using a loop, rather than relying on memcpy .
- When resizing an array, keep in mind that realloc may need to move the memory block to a new location if there isn't enough contiguous memory available. It can be slow if the array is very large since realloc needs to copy all the elements to the new location. If you are working with very large arrays, it may be more efficient to allocate a new array using malloc and copy the elements manually using a loop .
int* new_ptr = (int*)realloc(ptr, new_size);
if (new_ptr == NULL) {
// realloc failed, do something
}
=ptr = new_ptr;