An “aggregate” type is a structure, union, or array type. If an aggregate type contains members of aggregate types, the initialization rules apply recursively.
initializer :
{ initializer-list } /* For aggregate initialization */
{ initializer-list , }
initializer-list :
initializer
initializer-list , initializer
The initializer-list is a list of initializers separated by commas. Each initializer in the list is either a constant expression or an initializer list. Therefore, initializer lists can be nested. This form is useful for initializing aggregate members of an aggregate type, as shown in the examples in this section. However, if the initializer for an automatic identifier is a single expression, it need not be a constant expression; it merely needs to have appropriate type for assignment to the identifier.
For each initializer list, the values of the constant expressions are assigned, in order, to the corresponding members of the aggregate variable.
If initializer-list has fewer values than an aggregate type, the remaining members or elements of the aggregate type are initialized to 0 for external and static variables. The initial value of an automatic identifier not explicitly initialized is undefined. If initializer-list has more values than an aggregate type, an error results. These rules apply to each embedded initializer list, as well as to the aggregate as a whole.
A structure's initializer is either an expression of the same type, or a list of initializers for its members enclosed in curly braces ({ }). Unnamed bit-field members are not initialized.
When a union is initialized, initializer-list must be a single constant expression. The value of the constant expression is assigned to the first member of the union.
If an array has unknown size, the number of initializers determines the size of the array, and its type becomes complete. There is no way to specify repetition of an initializer in C, or to initialize an element in the middle of an array without providing all preceding values as well. If you need this operation in your program, write the routine in assembly language.
Note that the number of initializers can set the size of the array:
int x[ ] = { 0, 1, 2 }
If you specify the size and give the wrong number of initializers, however, the compiler generates an error.
The maximum size for an array is defined by size_t, an unsigned short on 16-bit computers, and has the range 0x0000 to 0xFFFF hexadecimal. Huge arrays can exceed this limit if they contain more than 65,535 elements or if the size of the element multiplied by the number of elements exceeds 65K. Arithmetic operations on huge arrays should therefore cast size_t and the results of arithmetic operations to unsigned long.
On 32-bit computers, sizeof is unsigned long.¨
This example shows initializers for an array.
int P[4][3] =
{
{ 1, 1, 1 },
{ 2, 2, 2 },
{ 3, 3, 3,},
{ 4, 4, 4,},
};
This statement declares P as a four-by-three array and initializes the elements of its first row to 1, the elements of its second row to 2, and so on through the fourth row. Note that the initializer list for the third and fourth rows contains commas after the last constant expression. The last initializer list ( {4, 4, 4,} ), is also followed by a comma. These extra commas are permitted but are not required; only commas that separate constant expressions from one another, and those that separate one initializer list from another, are required.
If there is no embedded initializer list for an aggregate member, values are simply assigned, in order, to each member of the subaggregate. Therefore, the initialization in the previous example is equivalent to the following:
int P[4][3] =
{
1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4
};
Braces can also appear around individual initializers in the list and would help to clarify the example above.
When you initialize an aggregate variable, you must be careful to use braces and initializer lists properly. The following example illustrates the compiler's interpretation of braces in more detail:
typedef struct
{
int n1, n2, n3;
} triplet;
triplet nlist[2][3] =
{
{ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }, /* Row 1 */
{ { 10,11,12 }, { 13,14,15 }, { 16,17,18 } } /* Row 2 */
};
In this example, nlist is declared as a 2-by-3 array of structures, each structure having three members. Line 1 of the initialization assigns values to the first row of nlist, as follows:
1.The first left brace on line 1 signals the compiler that initialization of the first aggregate member of nlist (that is, nlist[0] ) is beginning.
2.The second left brace indicates that initialization of the first aggregate member of nlist[0] (that is, the structure at nlist[0][0] ) is beginning.
3.The first right brace ends initialization of the structure nlist[0][0]; the next left brace starts initialization of nlist[0][1].
4.The process continues until the end of the line, where the closing right brace ends initialization of nlist[0].
Line 2 assigns values to the second row of nlist in a similar way. Note that the outer sets of braces enclosing the initializers on lines 1 and 2 are required. The following construction, which omits the outer braces, would cause an error:
triplet nlist[2][3] = /* THIS CAUSES AN ERROR */
{
{ 1, 2, 3 },{ 4, 5, 6 },{ 7, 8, 9 }, /* Line 1 */
{ 10,11,12 },{ 13,14,15 },{ 16,17,18 } /* Line 2 */
};
In this construction, the first left brace on line 1 starts the initialization of nlist[0], which is an array of three structures. The values 1, 2, and 3 are assigned to the three members of the first structure. When the next right brace is encountered (after the value 3), initialization of nlist[0] is complete, and the two remaining structures in the three-structure array are automatically initialized to 0. Similarly, { 4,5,6 } initializes the first structure in the second row of nlist. The remaining two structures of nlist[1] are set to 0. When the compiler encounters the next initializer list ( { 7,8,9 } ), it tries to initialize nlist[2]. Since nlist has only two rows, this attempt causes an error.
In this next example, the three int members of x are initialized to 1, 2, and 3, respectively.
struct list
{
int i, j, k;
float m[2][3];
} x = {
1,
2,
3,
{4.0, 4.0, 4.0}
};
In the list structure above, the three elements in the first row of m are initialized to 4.0; the elements of the remaining row of m are initialized to 0.0 by default.
union
{
char x[2][3];
int i, j, k;
} y = { {
{'1'},
{'4'}
}
};
The union variable y, in this example, is initialized. The first element of the union is an array, so the initializer is an aggregate initializer. The initializer list {'1'} assigns values to the first row of the array. Since only one value appears in the list, the element in the first column is initialized to the character 1, and the remaining two elements in the row are initialized to the value 0 by default. Similarly, the first element of the second row of x is initialized to the character 4, and the remaining two elements in the row are initialized to the value 0.