Realloc

From C

Jump to: navigation, search

It's very common for C beginners to use malloc and realloc excessively, either because they don't know of better alternatives, or simply because they have modest needs. This article aims to address the common issues and mistakes beginners tend to make while using them.


realloc can fail

If realloc fails it returns a null pointer and it won't free the pointer we passed to it. Which makes the following code sample a problem for us.

p = realloc(p, size);

If we assign the null pointer returned by realloc to our original pointer we can no longer free it, so we need to use a temporary pointer for handling the case of failure.

void *tmp = realloc(p, size);
if (tmp == NULL) {
    free(p);
    return -1;
}
p = tmp;


realloc can be expensive

Since realloc calls can be rather expensive, we should try to minimize the number of times we call it, even if that means allocating more storage than we currently need. For example, we can arbitrarily multiply the requested size by 2.


realloc might allocate a new object

realloc might allocate a new object, and because of that we should consider any pointer to the allocated object that has been created prior to the realloc call, to be an invalid pointer. Technically speaking, any object returned by realloc is considered to be a new object.

In the following code sample we allocate an object, we create a pointer into it, and then we call realloc. After the realloc call we no longer use the old pointer, but we assign it once again with a pointer based on the object returned by realloc.

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

int main(void) {
    char *s = malloc(6 + 1);
    if (s == NULL)
        return -1;
    
    strcpy(s, "abc123");
    printf("%s\n", s);
    
    char *s2 = s + 3;
    printf("%s\n", s2);
    
    char *tmp = realloc(s, 12 + 1);
    if (tmp == NULL) {
        free(s);
        return -1;
    }
    
    s = tmp;
    printf("%s\n", s);
    
    //The pointer 's2' shouldn't be used before it's re-assigned:
    s2 = s + 3;
    printf("%s\n", s2);
    
    
    free(s);
    return 0;
}


Diagnosing consistently

Since realloc doesn't have to allocate a new object each time it's called, it could make it rather difficult to diagnose or test our program for issues related to this behavior. By simulating realloc calls with a replacement function that always tries to allocate a new object, we can make potential issues more apparent and consistent. Unfortunately it's required to provide the replacement function with the size of the previous allocated object.

void *my_realloc(void *ptr, size_t size, size_t new_size) {
    void *p = malloc(new_size);
    if (p == NULL)
        return NULL;
    
    if (ptr != NULL) {
        if (size > new_size)
            size = new_size;
        
        memcpy(p, ptr, size);
        free(ptr);
    }
    
    return p;
}
Personal tools