Initializing Aggregate Types

An aggregate type is a structure, union, or array type. If an aggregate type contains members of aggregate types, the initialization rules apply recursively.

Syntax

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. 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, and 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 aren't 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's 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.

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.

Microsoft Specific

The maximum size for an array is defined by size_t.

END Microsoft Specific

Examples

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. 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 aren't required. Only commas that separate constant expressions from one another, and commas that separate one initializer list from another, are required.

If an aggregate member has no embedded initializer list, values are assigned, in order, to each member of the subaggregate. Therefore, the initialization in the previous example is equivalent to the following example:

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.

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. Row 1 of the initialization assigns values to the first row of nlist, as follows:

  1. The first left brace on row 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].

Row 2 assigns values to the second row of nlist in a similar way. The outer sets of braces enclosing the initializers on rows 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, 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.

See also

Initialization