Home > Net >  Initialize a flexible array of arrays in a struct
Initialize a flexible array of arrays in a struct

Time:09-22

The title corresponds to my last attempt, I try to store color values ​​corresponding to walls, a bit like this:

#include <stdint.h>

typedef uint8_t RGB[3];
typedef RGB ColorArray[];

typedef struct {
    int wall_num;
    ColorArray wall_colors;
} Map;

int main(void)
{
    int wall_num = 3;

    ColorArray wall_colors = {
        *(RGB){ 255, 0, 0 },
        *(RGB){ 0, 255, 0 },
        *(RGB){ 0, 0, 255 }
    };

    Map my_map = {wall_num, wall_colors}; // error: non-static initialization of a flexible array member

    return 0;
}

But I get this:

error: non-static initialization of a flexible array member

I tried other ways with pointers but I quickly realized that it was pointing to anything and so I got any colors until a segfault...

Is there a way to do it like this ? Or is it just the wrong way to go and I have to start all over again ?

UPDATE - (SELF ANSWER):

So I decided to call malloc() because no alternative was satisfactory for my case, I share what I did if it can help someone:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

typedef uint8_t RGB[3];
typedef RGB RGB_Array[];

typedef struct {
    int wall_num;
    RGB_Array wall_colors;
} Map;

void print_map (Map *m) {
    printf("wall_num: %d\n", m->wall_num);
    for (int i = 0; i < m->wall_num;   i) {
        printf("wall_colors[%d]: (R:%d, G:%d, B:%d)\n", i,
               m->wall_colors[i][0],
               m->wall_colors[i][1],
               m->wall_colors[i][2]);
    }
}

int main(void)
{
    int wall_num = 3;

    RGB_Array color_arr = {
        {255,0,0},
        {0,255,0},
        {0,0,255}
    };

    Map* map = malloc(sizeof(Map)   sizeof(color_arr));

    map->wall_num = wall_num;

    memcpy(map->wall_colors, color_arr, sizeof(color_arr));

    print_map(map);

    free(map); // free is for example

    return 0;
}

Otherwise, jxh's answer is still interesting and perfectly does what was asked for, even if it doesn't suit me personally, I validate it anyway.

CodePudding user response:

You cannot use an array name to initialize an array variable anyway.

There is no memory associated with the flexible array member. It is a convenience to allow you to have a name for the end of the struct to refer to the array that you intend to allocate behind the struct.

Typically, you would use malloc() and add the size of the array to the size of the struct to get a single object to represent your structure with the flexible array.

However, you can do it off the "stack" by defining a new structure where the flexible array member is replaced with an array of the appropriate size, and then casting a pointer to this structure to your desired type.

Alternatively, you could use a union and avoid the casting.

Both techniques are illustrated below. First some helpers:

...
#define MAP_TEMPLATE(N) struct { \
    int wall_num; \
    RGB wall_colors[N]; \
}
...
void print_map (Map *m) {
    printf("wall_num: %d\n", m->wall_num);
    for (int i = 0; i < m->wall_num;   i) {
        printf("wall_colors[%d]: (R:%d, G:%d, B:%d)\n", i,
               m->wall_colors[i][0],
               m->wall_colors[i][1],
               m->wall_colors[i][2]);
    }
}

Then using a new structure:

    MAP_TEMPLATE(3) my_map1 = {
        wall_num,
        { { 155, 0, 0 },
          { 0, 155, 0 },
          { 0, 0, 155 },
        },
    };

    print_map((Map *)&my_map1);

And using a union:

    union {
        MAP_TEMPLATE(3) _;
        MAP_TEMPLATE();
    } my_map2 = {
        { wall_num,
          { { 255, 0, 0 },
            { 0, 255, 0 },
            { 0, 0, 255 },
          },
        },
    };

    print_map((Map *)&my_map2);
  •  Tags:  
  • c
  • Related