malloc with Block Reuse
Lesson, slides, and applied problem sets.
View SlidesLesson
Advanced Operations
Beyond malloc and free, we need realloc and calloc.
realloc: Resizing Allocations
void *realloc(void *ptr, size_t new_size);
Cases to Handle
- ptr is NULL: Act like
malloc(new_size) - new_size is 0: Act like
free(ptr), return NULL - Shrinking: Can return same pointer
- Growing: May need to move data
Implementation
void *my_realloc(void *ptr, size_t new_size) {
// Case 1: NULL pointer
if (ptr == NULL) {
return my_malloc(new_size);
}
// Case 2: Zero size
if (new_size == 0) {
my_free(ptr);
return NULL;
}
block_header_t *block = payload_to_block(ptr);
size_t old_size = block->size;
// Case 3: Shrinking or same
if (new_size <= old_size) {
return ptr; // Keep same block
}
// Case 4: Growing
void *new_ptr = my_malloc(new_size);
if (new_ptr == NULL) {
return NULL; // OLD BLOCK STAYS VALID!
}
memcpy(new_ptr, ptr, old_size); // Copy OLD size
my_free(ptr);
return new_ptr;
}
Critical Detail: Failure Behavior
char *p = malloc(100);
fill_data(p);
char *q = realloc(p, 200);
if (q == NULL) {
// realloc failed, BUT:
// - p is still valid!
// - p's data is intact!
// Can continue using p
}
If realloc fails, the original pointer must remain valid. Never do:
p = realloc(p, new_size); // WRONG: loses p if realloc fails!
calloc: Zero-Initialized Memory
void *calloc(size_t count, size_t size);
Allocates count * size bytes, all initialized to zero.
void *my_calloc(size_t count, size_t size) {
size_t total = count * size;
// Check for overflow
if (count != 0 && total / count != size) {
return NULL; // Overflow!
}
void *ptr = my_malloc(total);
if (ptr != NULL) {
memset(ptr, 0, total);
}
return ptr;
}
Overflow Check
Why check for overflow?
calloc(SIZE_MAX, 2); // SIZE_MAX * 2 overflows!
Without the check, you'd allocate a tiny amount and return it, causing buffer overflows.
memcpy Implementation
You might need your own:
void my_memcpy(void *dst, const void *src, size_t n) {
char *d = dst;
const char *s = src;
for (size_t i = 0; i < n; i++) {
d[i] = s[i];
}
}
For realloc, src and dst don't overlap (new allocation), so simple copy is safe.