简体   繁体   中英

Is it standard-compliant to initialize a 2D array of unkown size by an 1D array initializer?

I recently came around this question where we got a 2D array definition like this one:

int x[][3] = { 0, 1, 2, 3, 4, 5 };

The first dimension is empty/size of the array is unknown. The array z is initialized by a 1D array initializer.

Now, this is what the C standard says (emphasize mine):

"If the aggregate or union contains elements or members that are aggregates or unions, these rules apply recursively to the subaggregates or contained unions. If the initializer of a subaggregate or contained union begins with a left brace, the initializers enclosed by that brace and its matching rightbrace 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; any remaining initializers are left to initialize the next element or member of the aggregate of which the current subaggregate or contained union is a part .

Source: ISO/IEC 9899:2018 (C18), §6.7.9/20.

This means it is well-defined to initialize a 2D array of known amount of elements with a 1D array initializer.

Thus, fe:

int y[2][3] = { 0, 1, 2, 3, 4, 5 };

should be equivalent to:

int y[2][3] = { { 0, 1, 2 } , { 3, 4, 5 } };

What I am worry about is this:

"If an array of unknown size is initialized, its size is determined by the largest indexed element with an explicit initializer . The array type is completed at the end of its initializer list."

Source: ISO/IEC 9899:2018 (C18), §6.7.9/22.

It means that if the size of the array/ the amounts of elements within it is unknown, it requires that the 2D array:

  1. Needs to have an largest indexed element, and
  2. This element needs to have an explicit initializer.

My questions:

  • Is that provided here?

  • Is it standard-compliant to initialize a two-dimensional array of unkown size by an one-dimensional array initializer?

IMHO and after my actual stand of knowledge, it shouldn't. But maybe I misunderstand something here.


I opened this question because the other question is tagged with C and C++, so it is not real language lawyer appropriate and not focuses on C, plus the question of other question is actually quite different.

Per C 2018 6.7.9 20:

  • x of int x[][3] is being initialized. It contains an element that is an aggregate, x[0] , which is an int [3] .
  • The first initializer for this subaggregate is 0 . It does not begin with a brace. So “only enough initializers from the list are taken to account for the elements or members of the subaggregate…”. Thus three initializers, 0 , 1 , and 2 , are taken to initialize x[0] .
  • Then “any remaining initializers are left to initialize the next element…”. So 4 and 5 are left to initialize x[1] .
  • Again, 4 does not begin with a brace, so 4 and 5 are taken to initialize x[1] . Per paragraph 21, since there are not enough initializers to initialize x[1] , “the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.”

4 and 5 are explicit initializers. They initialize x[1] . Therefore, x[1] has an explicit initializer. It is the largest indexed element of x that has an explicit initializer. Therefore it determines the size of x .

You are asking about this sentence from ISO/IEC 9899:2018 (C18), §6.7.9/22.

If an array of unknown size is initialized, its size is determined by the largest indexed element with an explicit initializer. The array type is completed at the end of its initializer list.

Consider this definition

int x[][3] = { 0, 1, 2, 3 };

The width is defined, so the compiler will initialise elements like this

x[0][0] = 0;
x[0][1] = 1;
x[0][2] = 2;
x[1][0] = 3;

This is from the explicit initialisation values defined. So now

  • The highest inner index is 2
  • The highest outer index is 1

So "the largest indexed element with an explicit initializer" is

x[0][2] = 2;    // "horizontally"
x[1][0] = 3;    // "vertically"

and the compiler creates the array

int x[2][3];

with the reminder of the last row implicitly initialised to 0 .

As you quoted from 6.7.9 Initialization :

[..] any remaining initializers are left to initialize the next element or member of the aggregate of which the current subaggregate or contained union is a part.

So

int x[][3] = { 0, 1, 2, 3, 4, 5 };

equivalent to

int x[][3] = { { 0, 1, 2}, {3, 4, 5} };

ie after initializing the first element of the array with {0, 1, 2} , the rest of the initializers are forming the next element. And the next element being int[3] here.

Similarly,

int x[][3] = { 0, 1, 2, 3, 4, 5, 6 };

is equivalent to:

int x[][3] = { {0, 1, 2}, {3, 4, 5}, {6} };

and is equivalent to:

int x[3][3] = { {0, 1, 2}, {3, 4, 5}, {6, 0, 0} };

ie all subobjects that are not initialized explicitly shall be initialized implicitly the same as objects that have static storage duration .

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