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.
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.