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.