Question

I have a data structure that is defined as follows:

struct varr {
    int n; //length of data array
    double data[];
};

The data array is required to be initially of size 1 but allowing the possibility of increase.

When allocating space for a struct varr * I use

struct varr *p = malloc(sizeof(struct varr) + sizeof(double));

When reallocating space to increase the size of the data array I use

p = realloc(p, sizeof(struct varr) + p->n * sizeof(double));//p->n having already been set

My question is "how should I free the memory allocated for this structure?"

I've tried a simple free(p); but this causes memory leaks according to memcheck. Is there something fundamentally wrong with how I'm structuring my data for this purpose, or with how I'm allocating the memory?

==NOTE==

I've solved the problem by using a pointer instead of an explicitly declared array. I'd still be interested in a concise answer for why this doesn't work, however.

Was it helpful?

Solution

As you probably know, each call to malloc makes OS give you some memory and remember it's size and attributes. Thus if you call free, you can clear both an array or a pointer.

Examples:

char* array = malloc(16 * sizeof(char));
char* single = malloc(sizeof(char));

free(array);
free(single);

As you can see, you always get one free for one malloc. That is because the OS knows how many bytes you allocated, it doesn't care what type it is and how many instances of it were created. (note: this is why there is difference between delete and delete[] in C++ because the application needs to know what destructors to run, the control of cleanup is not left to the OS only...)

Taking from here, we can assume that if we allocated the struct as a one block using a single malloc, it can be freed using a single free call.

This example works for me without any leaks:

#include <stdlib.h>

typedef struct Array_t
{
    int Length;
    double Data[];
} Array;

Array* create_array(int length)
{
    Array* array = malloc(sizeof(Array) + length * sizeof(double));
    if (array != NULL)
        array->Length = length;

    return array;
}

void delete_array(Array* array)
{
    free(array);
}

int main()
{
    Array* array = create_array(100);
    if (array == NULL)
        return EXIT_FAILURE;

    for (int i = 0; i < array->Length; ++i)
    {
        array->Data[i] = 1.7 * (i + 3);
    }

    delete_array(array);

    return EXIT_SUCCESS;
}

Of course, if you get up to something more complex like John Findlay example with

struct SomeStruct
{
    int Size;
    int* ArrayOfPointers[];
}

you can still create this struct in one malloc, e.g.

// *s* contains an array of 14 int pointers (int*)
struct SomeStruct* s = malloc(sizeof(SomeStruct) + 14 * sizeof(int*));
s->Size = 14;

The core problem is though that int* ArrayOfPointers is an array of pointers, thus to initialize it properly, you also need to

// each of the *s*'s int pointers is actually a decayed array of 25 ints
for (int i = 0; i < s->Size; ++i)
    s->ArrayOfPointers[i] = malloc(25 * sizeof(int));

And when freeing:

for (int i = 0; i < s->Size; ++i)
    free(s->ArrayOfPointers[i]);

free(s);

But the point is that the structure with FAM is still freed in one free call. The loop is freeing the allocated pointer data, which is equivalent to freeing a dynamically allocated 2D array.

OTHER TIPS

That looks flat out wrong. I think it should go like this:

// step 1: Allocate n items:

struct varr * p = malloc(sizeof *p + n * sizeof(double));
if (p) { p->n = n; }

// step 2: Reallocate to hold m items:

struct varr * tmp = realloc(p, sizeof *tmp + m * sizeof(double));
if (tmp) { p = tmp;  p->n = m; }

When done, don't forget to say free(p);.

I ran into the same problem last night. After a couple of hours of googling I found this, pretty simple but clever answer in a tutorial:

void free_struct( THESTRUCT * ts )
{
// free all memory accoiated with our structure
if(ts){
    for(int i = 0; i<ts->count; i++)
        free(ts->str[i]);
    free(ts);
    }
}

http://www.johnfindlay.plus.com/lcc-win32/Tuts/FlexArrs.htm

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top