Search code examples
carraysmalloccallocflexible-array-member

Allocate memory for flexible array in structure


I am trying to allocate memory for a structure using a flexarray. I received it this way and I have to implement it like this.

The structure looks like:

struct _XPM {

    unsigned int width;
    unsigned int height;
    unsigned char cpp;
    unsigned int ncolors;
    Color *colta;
    unsigned int *data[];
}; //it's a typedef to XPM in the headder file

I have a function that initiates the structure. It is there where I have the problem. I really don't know: do I have to use malloc to allocate memory for the structure and that's it, or do I need to allocate memory to *data[] like a pointer to an array?

void initXPM(XPM *imagine,
        unsigned int width,
        unsigned int height,
        unsigned char cpp,
        unsigned int ncolors) {

imagine = ( XPM* ) malloc ( sizeof ( XPM ) + sizeof ( unsigned int* ) * width * height );
/* I think I need to allocate sizeof(unsigned int) *width * height because 
I have to work with an array of pixels  */ 

    if(!imagine) {
        perror( "Error allocating resources for XPM structure" );
         exit(EXIT_FAILURE);
    }

Then do I have to write the following code or not?

imagine -> data = ( unsigned int* ) calloc( width, sizeof( unsigned int ) );
    if( !imagine->data ) {
        perror( "Error allocating resources for XPM data width" );
        exit(EXIT_FAILURE);
    }

    for( i = 0; i < width; i++ ) {
        imagine -> data[i] = (unsigned int*) calloc ( height, sizeof(unsigned int) );
        if( !imagine -> data[i] ) {
            perror( "Error allocating resources for XPM data height" );
            exit(EXIT_FAILURE);
        }
    }

I hope my explanation was clear enough. If not, I can try to explain it again.

Thank you! :)


Solution

  • How long do you want imagine->data to be? It seems that you want it to be width elements long, so do this:

    imagine = ( XPM* ) malloc ( sizeof ( XPM ) + sizeof ( unsigned int* ) * width);
    

    Also, the cast (XPM*) is unnecessary in C, but that's not strictly important. It won't stop your code working.

    This is unnecessary and wrong:

    imagine -> data = ( unsigned int* ) calloc( width, sizeof( unsigned int ) );
    if( !imagine->data ) {
        perror( "Error allocating resources for XPM data width" );
        exit(EXIT_FAILURE);
    }
    

    You already allocated the memory for imagine->data at the same time as imagine itself. If you had declared unsigned int **data; instead of unsigned int *data[];, this would be correct. If you had chosen that way, you would need to allocate only sizeof(XPM) bytes for imagine, instead of sizeof(XPM) + sizeof(unsigned int*)*width, because the array imagine->data would be stored separately from the structure imagine.

    The rest of your code, which allocates an array for each row of pixels, is fine.