Implementing realloc
Realloc with Data Preservation
realloc is deceptively complex. It must handle:
- Growing allocations (may need to move)
- Shrinking allocations (can stay in place)
- Edge cases: NULL pointer, zero size
Semantics
void *realloc(void *ptr, size_t new_size);
- If
ptris NULL: equivalent tomalloc(new_size) - If
new_sizeis 0: implementation-defined (we'll treat asfree(ptr)and return NULL) - If
new_size <= current_size: may shrink in place, return same pointer - If
new_size > current_size: allocate new block, copy data, free old block
Critical: If realloc fails (can't allocate new size), it returns NULL but the original block must remain valid and unchanged.
Your Task
// Reallocate a memory block to a new size
// Preserves data up to min(old_size, new_size)
void *my_realloc(void *ptr, size_t new_size);
// Helper: copy n bytes from src to dst
// You implement this - do not use memcpy
void my_memcpy(void *dst, const void *src, size_t n);
// Helper: get the size of an allocated block
size_t get_block_size(void *ptr);
Subtle Issues
Data Preservation
When growing, only copy the OLD size worth of data:
// If old block was 100 bytes, new request is 200 bytes
// Copy exactly 100 bytes, not 200!
my_memcpy(new_ptr, old_ptr, old_size);
The Return Value Contract
void *p = malloc(100);
fill_with_data(p);
void *q = realloc(p, 200);
if (q == NULL) {
// CRITICAL: p is still valid! Data is preserved!
// Many programs forget this and leak or corrupt here
}
// If q != NULL: p is now invalid, use only q
In-Place Shrinking
When shrinking, you don't need to allocate new memory:
if (new_size <= block->size) {
// Optionally update block->size to new_size
// Optionally split the remainder (covered in later problem)
return ptr; // Same pointer, less logical size
}
Overlap Safety
When copying, the old and new regions must not overlap (for realloc they won't - you allocate new then copy). But memcpy requires non-overlapping regions. Since realloc allocates fresh memory before copying, this is safe.
Edge Cases
realloc(NULL, 100)- just mallocrealloc(ptr, 0)- free and return NULLrealloc(ptr, same_size)- return same pointerrealloc(ptr, larger)- malloc new, copy, free oldrealloc(ptr, smaller)- may return same pointer
Memory Leak Trap
// WRONG - leaks if realloc fails
ptr = realloc(ptr, new_size); // If returns NULL, old ptr is lost!
// CORRECT
void *new_ptr = realloc(ptr, new_size);
if (new_ptr != NULL) {
ptr = new_ptr;
}
Run tests to see results
No issues detected