initializing array of pointers to structs - c

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]

Related

Initialize a flexible array of arrays in a struct

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.
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);

What is the problem here in struct definition and compiler error?

When I type the following code:
struct student {
int* grades;
int num_grades;
};
int main()
{
struct student s1 = { { 100, **50**, 74}, 3 }, s2 = { {100, **90**, 80, 90, 90}, 5 }, s3 = { {85, **90**}, 2 };
struct student arr[3] = { s1, s2, s3 };
}
I get two errors error:
C2078 too many initializers
E0146 too many initializer values
I've marked the numbers with two bold asterisks to tell you where the Visual Studio puts red underline.
Does anyone know why the compiler tells me that error?
You cannot initialize a pointer (grades variable) by brace-enclosed initializer list. You need to make use of a compound literal.
Something like
struct student s1 = { (int []){ 100, 50 , 74}, 3 };
should do the job.

How can an array of structs be initialized using a const struct in global scope?

I want to use code similar to the following (but a lot more complex - this is a simplified example) to initialize an array of structures, but during compilation I get the error "expression must have a constant value".
typedef struct
{
int x;
int y;
} windowStruct_t;
static const windowStruct_t windowStructInit =
{
.x = 3,
.y = 5,
};
// These get defined differently at times. This is simplified for the example.
#define NUM_ARRAY_ELEMENTS (2)
#define REPEAT_NUM_ARRAY_ELEMENTS_TIMES(x) (x),(x)
// The following line causes the error "expression must have a constant value" twice.
windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ REPEAT_NUM_ARRAY_ELEMENTS_TIMES( windowStructInit ) };
void someFunction( void )
{
volatile int x = windowStruct[0].x;
}
void anotherFunction( void )
{
volatile int y = windowStruct[1].y;
}
Manually expanding the macro and replacing the line that causes the error with the following gives the same result:
windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ windowStructInit, windowStructInit };
But this compiles without error:
windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ { .x = 3, .y = 5 }, { .x = 3, .y = 5 } };
If I move the array declaration inside of function scope, it compiles without errors (I am ignoring the fact that someFunction() and anotherFunction() now access different arrays and that their lifetimes are different):
void someFunction( void )
{
windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ REPEAT_NUM_ARRAY_ELEMENTS_TIMES( windowStructInit ) };
volatile int x = windowStruct[0].x;
}
void anotherFunction( void )
{
windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ REPEAT_NUM_ARRAY_ELEMENTS_TIMES( windowStructInit ) };
volatile int y = windowStruct[1].y;
}
Leaving the array declarations inside of function scope, if they are declared to be "static", the error message comes back:
void someFunction( void )
{
static windowStruct_t windowStruct[ NUM_ARRAY_ELEMENTS ] =
{ REPEAT_NUM_ARRAY_ELEMENTS_TIMES( windowStructInit ) };
volatile int x = windowStruct[0].x;
}
So it seems that when the arrays are declared as automatic variables (on the stack) that they can be initialized in a way that isn't allowed when the memory allocation is static (whether inside function scope or in global scope where the allocation is static even without the "static" keyword). Is there a way to initialize the array in global scope using a const struct as in the original example?
I am using C, not C++. I don't want to use dynamic memory allocation. The compiler is TI's ARM compiler V16.6.0.STS as included in their Code Composer Studio environment.
A const object is not a C constant. Instead use constants which is required for non-automatic storage objects.
Define an initializer { .x = 3, .y = 5 }
typedef struct windowStruct_s {
int x;
int y;
} windowStruct_t;
#define windowStruct_t_default_initializer { .x = 3, .y = 5 }
#define NUM_ARRAY_ELEMENTS (2)
#define REPEAT_NUM_ARRAY_ELEMENTS_TIMES(x) x, x /* no () */
windowStruct_t windowStruct[NUM_ARRAY_ELEMENTS] = {
REPEAT_NUM_ARRAY_ELEMENTS_TIMES(windowStruct_t_default_initializer) };
int someFunction(void) {
volatile int x = windowStruct[0].x;
return x;
}
int anotherFunction(void) {
volatile int y = windowStruct[1].y;
return y;
}

How do I create an Array of Objects in C?

I'm new to C, coming from a language like javascript the amount of types, keywords etc. in the language are painfully confusing.
In javascript I can create an array of objects like so.
arrayOfObjectsInsideJavascript = [
{ s:"ejf09j290fj390j2f09", f=0 },
{ s:"dj320992209920209dj", f=0 }
]
From what I've read it seems that I'll need to be using typedefand orstructs.
I've tried:
typedef struct[] = {
{ s:"ejf09j290fj390j2f09", f=0 },
{ s:"dj320992209920209dj", f=0 }
}
struct[] = {
{ s:"ejf09j290fj390j2f09", f=0 },
{ s:"dj320992209920209dj", f=0 }
}
typedef struct {
char[] s = "ejf09j290fj390j2f09";
int f = 0;
} objectLikeClassThingy;
What's the best way to create the object I need?
like this ?
struct {
const char *s;
double f;
} obj[] = {
{ .s = "ejf09j290fj390j2f09", .f = 0 },
{ .s = "dj320992209920209dj", .f = 0 }
};
Where JavaScript has dynamic "properties", C has static "tags". A struct type is defined as a sequence of tags, which each have a type.
For the type inside your example array
arrayOfObjectsInsideJavascript = [
{ s:"ejf09j290fj390j2f09", f=0 },
{ s:"dj320992209920209dj", f=0 }
]
your last solution started off almost correctly:
struct element {
char s[256];
int f;
};
You have two options for the type of s:
If you want to store the string inside the object, you use some array type, such as char s[256]. 256 is the length of the array, so when you use zero-terminated strings, the maximum allowed string length is 255 (which is 256, minus one for the '\0' character).
If you want to store the string outside the object, you use some pointer type. Since you want to use string literals, you should declare the tag as const char *s. Changing a string literal causes undefined behaviour, so it's best to prevent yourself from doing so.
For this answer, I'll use the first option in the examples.
If you want to define one struct, you could now write something like
struct element {
char s[256];
int f;
} one_object = {
.s = "ejf09j290fj390j2f09",
.f = 0,
};
or
struct element {
char s[256];
int f;
};
/* ... later, in a scope where `struct element` is visible ... */
struct element one_object = {
.s = "ejf09j290fj390j2f09",
.f = 0,
};
or, with a typedef,
typedef struct {
char s[256];
int f;
} your_element_type;
/* ... later, in a scope where `your_element_type` is visible ... */
your_element_type one_object = {
.s = "ejf09j290fj390j2f09",
.f = 0,
};
Note that this doesn't necessarily work with older compilers that don't support the C99 standard. In the older days, you'd have to initialise fields in order:
your_element_type one_object = { "ejf09j290fj390j2f09", 0 };
Also note that, if you're never going to refer to the type name struct element again, you don't have to name it:
struct {
char s[256];
int f;
} one_object = {
.s = "ejf09j290fj390j2f09",
.f = 0,
};
Arrays are initialised similarly (you've actually already initialised an array, namely s, with a string):
struct element {
char s[256];
int f;
} so_many_objects[] = {
{ .s = "ejf09j290fj390j2f09", .f = 0 },
{ .s = "dj320992209920209dj", .f = 0 },
};
or
struct element {
char s[256];
int f;
};
/* ... later, in a scope where `struct element` is visible ... */
struct element so_many_objects[] = {
{ .s = "ejf09j290fj390j2f09", .f = 0 },
{ .s = "dj320992209920209dj", .f = 0 },
};
or, with a typedef again,
typedef struct {
char s[256];
int f;
} your_element_type;
/* ... later, in a scope where `your_element_type` is visible ... */
your_element_type so_many_objects[] = {
{ .s = "ejf09j290fj390j2f09", .f = 0 },
{ .s = "dj320992209920209dj", .f = 0 },
};
By the way, note that we are using an incomplete type for so_many_objects; this is only possible because the compiler can see how big the array should be. In these examples, the compiler would treat your code as if you'd have written struct element so_many_objects[2]. If you think you'll have to extend the array with more objects, you'd better specify how many elements the array has (at maximum), or learn about dynamic allocation.

Syntax for assigning to a struct in a struct

I have a struct Entity that is made up of Limbs and an enum, Limbs is also a struct with two items e.g.
typedef enum{ALIVE, DEAD} state;
typedef struct Limb{
int is_connected;
int is_wounded;
} Limb;
typedef struct Entity{
Limb limb_1;
Limb limb_2;
state is_alive;
} Entity;
Now lets say I have a function that's designed to assign entity particular values, what is the proper syntax to use here? My current guess is this:
void assign_entity(Entity *entity){
*entity = {
.limb_1 = { 1, 0 },
.limb_2 = { 1, 0 },
.is_alive = ALIVE
};
}
But I get an error (expected expression) when I use this syntax, what am I doing wrong here? What is the proper syntax for assigning to a struct inside a struct.
You're trying to use a compound literal but omitting the proper syntax.
It should be:
void assign_entity(Entity *entity){
*entity = ((Entity) {
.limb_1 = { 1, 0 },
.limb_2 = { 1, 0 },
.is_alive = ALIVE
});
}
Note that this requires C99 (or a suitably extended compiler, of course).
Probably too verbose for someone the code below:
void assign_entity(Entity *entity)
{
entity->limp_1.is_connected = 1;
entity->limp_1.is_wounded= 0;
entity->limp_2.is_connected = 1;
entity->limp_2.is_wounded= 0;
entity->is_alive = ALIVE;
}
If you have already allocated memory at the address pointed to by entity and all you're trying to do is "assign particular values", then you would do it as follows:
void assign_entity(Entity *entity)
{
entity->limb_1 = ( 1, 0 );
entity->limb_2 = ( 1, 0 );
entity->is_alive = ALIVE;
}
Or, if you want to roll it all up into one line:
void assign_entity(Entity *entity)
{
*entity = ((1, 0), (1, 0), ALIVE);
}
Designated initializer syntax can only be used in an initialization.
One way to do what you want would be:
Entity const new = {
.limb_1 = { 1, 0 },
.limb_2 = { 1, 0 },
.is_alive = ALIVE
};
*entity = new;

Resources