Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialization of an array of structure initializes all member of a single element, why?

Why would someone do this? Better yet how does this even work? I would have assumed this would somehow create an array of three structures with only the first member defined. I realize a pointer points to the first element of the array, and I see how this could work but how this is defined is throwing me off! (gcc 4.8.4)

void do_something(const void *);

typedef struct{

int a;
char b;
int c;

} the_data_t;

int main(int argc, char *argv[])
{
   the_data_t my_data[] = {10, 'a', 30};
   do_something((const void *)my_data);
}

void do_something(const void *data)
{
   printf("data a: %d\ndata b: %c\ndata c: %d\n", ((the_data_t*)data)->a,
      ((the_data_t*)data)->b, ((the_data_t*)data)->c);
}

Output

data a: 10
data b: a
data c: 30

Regardless, I changed it to this..

int main(int argc, char *argv[])
{
   the_data_t my_data = {10, 'a', 30};
   do_something(&my_data);
}
like image 394
atomSmasher Avatar asked Aug 11 '16 15:08

atomSmasher


4 Answers

I would have assumed this would somehow create an array of three structures with only the first member defined

No, it's not that way. Basically it creates an array of one element, with all the members intialized.

Quoting C11, chapter §6.7.9

Each brace-enclosed initializer list has an associated current object. When no designations are present, subobjects of the current object are initialized in order according to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union. [...]

and

Each designator list begins its description with the current object associated with the closest surrounding brace pair. Each item in the designator list (in order) specifies a particular member of its current object and changes the current object for the next designator (if any) to be that member.150) The current object that results at the end of the designator list is the subobject to be initialized by the following initializer.

and

[...] If the initializer of a subaggregate or contained union begins with a left brace, the initializers enclosed by that brace and its matching right brace initialize the elements or members of the subaggregate or the contained union. Otherwise, only enough initializers from the list are taken to account for the elements or members of the subaggregate or the first member of the contained union; [...]

Basically, your code should ideally look like

the_data_t my_data[] = {{10, 'a', 30}}; 

to visualize initializing one element.

OTOH, what you expected may be achieved by

 the_data_t my_data[] = {{10}, {'a'}, {30}};

where it creates an array of 3 elements, all having the member variable a initialized.


That said,

 the_data_t my_data[] = {{10, 'a', 30}};

is equivalent to writing

 the_data_t my_data = {10, 'a', 30};

except the part, my_data will not be an array anymore (but what good is an one element array, in general, either?).

like image 191
Sourav Ghosh Avatar answered Oct 19 '22 09:10

Sourav Ghosh


Compiler will treat

the_data_t my_data[] = {10, 'a', 30};   

as

the_data_t my_data[1] = {{ 10, 'a', 30 }}; // Though it will raise warning.  

So, my_data is an array of one the_data_t type.

This is similar to when a two dimensional array is declared like this

int a[][3] = { 1, 2, 3 }; 

then compiler will treat it as

int a[1][3] = { { 1, 2, 3 } }; 

Print the size of a and you will get 12 (if size of int is 4 on that machine).

like image 20
haccks Avatar answered Oct 19 '22 09:10

haccks


It's not proper. GCC will give you a warning for this:

warning: missing braces around initializer
warning: (near initialization for ‘my_data[0]’)

What it will do is create a 1 element array.

like image 44
dbush Avatar answered Oct 19 '22 09:10

dbush


gcc will give you warning about this issue, if you use the warning switch.

$ gcc -Wall test.c 
test.c: In function ‘main’:
test.c:14:25: warning: missing braces around initializer [-Wmissing-braces]
 the_data_t my_data[] = {10, 'a', 30};
                        ^
test.c:14:25: note: (near initialization for ‘my_data’)
$ 

To fix this either you can properly initialize the array as:

the_data_t my_data[] = {{10, 'a', 30}};

Or, as you showed in the post, you can change my_data to a struct variable.

the_data_t my_data = {10, 'a', 30}; // And call do_something as
do_something((const void *)&my_data);
like image 36
sps Avatar answered Oct 19 '22 09:10

sps