Search code examples
cflexible-array-member

the difference between struct with flexible arrays members and struct with pointer members


I'm quit confused with the difference between flexible arrays and pointer as struct members. Someone suggested, struct with pointers need malloc twice. However, consider the following code:

    struct Vector {
        size_t size;
        double *data;
    };
    int len = 20;
    struct Vector* newVector = malloc(sizeof *newVector + len * sizeof*newVector->data);
    printf("%p\n",newVector->data);//print 0x0
    newVector->data =(double*)((char*)newVector + sizeof*newVector);
    // do sth
    free(newVector);

I find a difference is that the address of data member of Vector is not defined. The programmer need to convert to "find" the exactly address. However, if defined Vector as:

    struct Vector {
        size_t size;
        double data[];
    };

Then the address of data is defined.

I am wondering whether it is safe and able to malloc struct with pointers like this, and what is the exactly reason programmers malloc twice when using struct with pointers.


Solution

  • The difference is how the struct is stored. In the first example you over-allocate memory but that doesn't magically mean that the data pointer gets set to point at that memory. Its value after malloc is in fact indeterminate, so you can't reliably print it.

    Sure, you can set that pointer to point beyond the part allocated by the struct itself, but that means potentially slower access since you need to go through the pointer each time. Also you allocate the pointer itself as extra space (and potentially extra padding because of it), whereas in a flexible array member sizeof doesn't count the flexible array member. Your first design is overall much more cumbersome than the flexible version, but other than that well-defined.

    The reason why people malloc twice when using a struct with pointers could either be that they aren't aware of flexible array members or using C90, or alternatively that the code isn't performance-critical and they just don't care about the overhead caused by fragmented allocation.