简体   繁体   中英

initializing array of pointers to structs

How do I initialize an array of structs without creating intermediate array of list of pointers to these structs? Consider the following example code:

snippets $ cat a2p.c 
struct shape {
    int     angles;
    char    shape_name[16];
};
typedef struct shape shape_t;
struct container {
    char            name[32];
    shape_t         **elements;
    int             num_elts;
};
typedef struct container container_t;

shape_t triangle = {
    .angles     = 3,
    .shape_name = {"Triangle"}
};
shape_t rectangle = {
    .angles     = 4,
    .shape_name = {"Rectangle"}
};

container_t c = {
    .name       = {"Case"},
    .elements   =  {
        &triangle,
        &rectangle
    },
    .num_elts   =2
};


int main(void) {

    return 0;   

}    

I need the .elements member to point to an array of pointers to shape_t sturcts, but this code does not compile:

 snippets $ gcc -c a2p.c
a2p.c:24:2: warning: braces around scalar initializer
  .elements = {
  ^
a2p.c:24:2: note: (near initialization for ‘c.elements’)
a2p.c:25:3: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
   &triangle,
   ^
a2p.c:25:3: note: (near initialization for ‘c.elements’)
a2p.c:26:3: warning: excess elements in scalar initializer
   &rectangle
   ^
a2p.c:26:3: note: (near initialization for ‘c.elements’)
 snippets $ 

However , if I add an intermediate array , like this:

shape_t *shapes[] = {
    &triangle,
    &rectangle
};
container_t c = {
    .name       = {"Case"},
    .elements   = shapes,
    .num_elts   =2
};

The code compiles ok. Can I avoid creating the shapes[] array as an intermediate step and directly initialize container_t with all data like on the first code snippet? What would be the correct initialization syntax then?

You are almost there; you just need to ensure that the elements initializer is a suitable pointer, like this:

struct shape {
    int     angles;
    char    shape_name[16];
};
typedef struct shape shape_t;
struct container {
    char            name[32];
    shape_t         **elements;
    int             num_elts;
};
typedef struct container container_t;

shape_t triangle = {
    .angles     = 3,
    .shape_name = { "Triangle" }
};
shape_t rectangle = {
    .angles     = 4,
    .shape_name = { "Rectangle" }
};

container_t c = {
    .name       = { "Case" },
    .elements   =  (shape_t *[]) {
        &triangle,
        &rectangle,
    },
    .num_elts   = 2,
};

int main(void) {
    return 0;
}

Note the use of a compound literal for the array of pointers to shape_t elements.

You have to do it exactly like you did it in your second snippet. The only way you can do it all in one initialization (as in your original code) is if you declare elements as an array of shape_t * , as in shape_t *elements[10] , but you probably don't want to have a fixed size array there.

If you move elements member to the END of the structure DEFINITION you can then use the following on C99, and later, compilers:

container_t c2 = {
    .name       = {"Case2"},
    .num_elts   =3,
    .elements   =  {
        &(shape_t){ 3, "Triangle" } ,
        &(shape_t){ 4, "Rectangle" },
        &(shape_t){ 2, "Line" }
    }
};

The variable size member must be the last member of the structure.

The part of me that hates places for easy bugs notes you can get rid of the need for a manually set element count by ending the list with a NULL pointers and dropping num_elts:

container_t c2 = {
    .name       = {"Case2"},
    .elements   =  {
        &(shape_t){ 3, "Triangle" } ,
        &(shape_t){ 4, "Rectangle" },
        &(shape_t){ 2, "Line" },
        NULL
    }
};

Now you just step through the list until NULL == container_list->elements[n]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM