Search code examples
carraysfreedynamic-memory-allocationrealloc

C Memory assignment, Segmentation Fault / Double Free In Array of Structs


From what I understand, Segmentation Fault is when you haven't assigned memory properly yet, and Double free is when you try to free memory that you already freed?

What would be the proper way to increase the size of an array of Structs, and where/which parts do you actually need to free?

I have a struct:

struct Data {
    // Some variables
} 

and I'm initializing the array of those structs with:

int curEntries = 100;
int counter = 0; 
struct Data *entries = (struct Data *)malloc(curEntries * sizeof(struct Data));

When I read data from a bin file into this array and populate each of the structs, the program works up until there are more than 100 structs needed. At that time, I have the following code to realloc the array:

if (counter == curEntries - 1) { // counter = current index, curEntries = size of the array
    entries = (struct Data *)realloc(entries, curEntries * 2 * sizeof(struct Data));
    // struct Data *temp = (struct Data *)realloc(entries, curEntries * 2 * sizeof(struct Data));
    // free(entries);
    // entries = temp;
    // free(temp);
}

The line I'm using now (entries = . . . ) works, but is obviously wrong because I'm not freeing anything, right?

But when I tried using the commented out code instead, I got a double Free error

Finally, (because there are a series of automatic tests), apparently I need to use malloc and so forth in other parts of my code as well. Where else should I/do I need to assign memory?


Solution

  • You get a double free error because your call to realloc() succeeds so the previous pointer has been freed and yet you call free(entries). The library can sometimes determine that a block has already been freed but this sanity check is not always effective. The C Standard does not provide any guarantee to this regard, passing a freed pointer to free() has undefined behavior.

    On a system with memory protection, a segmentation fault may occur when you try and read or write to a memory address that has not been assigned to your process, or that has been invalidated for the process. Dereferencing a pointer to a freed block may cause a segmentation fault before the library can determine that the block has already been freed.

    The scheme for your reallocating your array should be this:

    size_t curEntries = 100; // size of the array
    size_t counter = 0;      // current index
    
    ...
    
    if (counter == curEntries) {
        // array is full, try and reallocate to a larger size
        size_t newSize = curEntries * 2;
        struct Data *newArray = realloc(entries, newSize * sizeof(*newArray));
        if (newArray == NULL) {
            // cannot reallocate, out of memory.
            // handle this error, entries is still valid.
            abort();
        } else {
            // array was reallocated possibly to a different address
            // entries is no longer a valid pointer
            entries = newArray;     // update array pointer
            curEntries = newSize;   // update number of entries
        }
    }