Инициализация агрегатных типов

Агрегатный тип — это тип структуры, объединения или массива. Если агрегатный тип содержит члены агрегатных типов, правила инициализации применяются рекурсивно.

Синтаксис

initializer:
    {initializer-List} /* для агрегатной инициализации */
    {initializer-list, }

initializer-list:
    initializer
    initializer-list,initializer

Параметр initializer-list содержит список инициализаторов, разделенных запятыми. Каждый инициализатор в списке является константным выражением или списком инициализаторов. Поэтому списки инициализаторов могут быть вложенными. Эта форма полезна для инициализации агрегатных членов агрегатного типа, как показано в примерах этого раздела. Однако если инициализатор для автоматического идентификатора является одним выражением, оно не обязательно должно быть константным; достаточно, чтобы выражение имело соответствующий тип для назначения идентификатору.

В каждом списке инициализаторов значения константных выражений присваиваются соответствующим членам агрегатной переменной по порядку.

Если initializer-list имеет меньше значений, чем агрегатный тип, оставшиеся члены или элементы агрегатного типа инициализируются значением 0. Начальное значение автоматического идентификатора, которое не инициализировано явно, не определено. Если initializer-list имеет больше значений, чем агрегатный тип, выдается ошибка. Эти правила применяются к каждому внедренному списку инициализаторов, а также к агрегату в целом.

Инициализатор структуры является выражением того же типа или списком инициализаторов для членов, заключенных в фигурные скобки ( { } ). Безымянные члены битового поля не инициализируются.

При инициализации объединения параметр initializer-list должен быть одним константным выражением. Значение константного выражения присваивается первому члену объединения.

Если размер массива неизвестен, количество инициализаторов определяет размер массива, а его тип становится полным. Не существует способа указать повторение инициализатора в C или инициализировать элемент в середине массива без предоставления всех предыдущих значений. Если этот оператор требуется в программе, напишите подпрограмму на языке ассемблера.

Обратите внимание, что количество инициализаторов может задать размер массива.

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

Если указать размер и присвоить неверное количество инициализаторов, компилятор выдаст ошибку.

Блок, относящийся только к системам Microsoft

Максимальный размер массива определяется параметром size_t. Определяется в файле заголовка STDDEF. H, size_t с диапазоном от 0x00000000 до 0x7CFFFFFF.

Завершение блока, относящегося только к системам Майкрософт

Примеры

В следующем примере представлены инициализаторы массива.

int P[4][3] =
{
    { 1, 1, 1 },
    { 2, 2, 2 },
    { 3, 3, 3,},
    { 4, 4, 4,},
};

Этот оператор объявляет P как массив, состоящий из трех строк и четырех столбцов, и инициализирует элементы первой строки значением 1, элементы второй строки — значением 2 и т. д. до четвертой строки. Обратите внимание, что список инициализаторов для третьей и четвертой строк содержит запятые после последнего константного выражения. За последним списком инициализаторов ({4, 4, 4,},) также следует запятая. Эти дополнительные запятые являются допустимыми, но не обязательными; обязательными являются только запятые, которые отделяют одно константное выражение от другого, и запятые, которые отделяют один список инициализаторов от другого.

Если агрегатный член не имеет встроенный список инициализаторов, значения присваиваются каждому члену подагрегата по порядку. Таким образом, инициализация в предыдущем примере эквивалентна следующему.

int P[4][3] =
{
   1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4
};

В фигурные скобки также можно заключать отдельные инициализаторы в списке, что могло бы пояснить пример выше.

При инициализации агрегатной переменной фигурные скобки и списки инициализаторов следует использовать с осторожностью. В следующем примере подробно показано то, как компилятор интерпретирует фигурные скобки.

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 */
};

В этом примере параметр nlist объявлен как массив структур, состоящий из двух строк и трех столбцов, где каждая структура имеет три члена. Строка 1 инициализации присваивает значения первой строке nlist следующим образом.

  1. Первая открывающая фигурная скобка в строке 1 сообщает компилятору, что начинается инициализация первого агрегатного члена nlist (то есть nlist[0]).

  2. Вторая открывающая фигурная скобка указывает, что начинается инициализация первого агрегатного члена nlist[0] (то есть структуры nlist[0][0]).

  3. Первая закрывающая фигурная скобка завершает инициализацию структуры nlist[0][0]. Следующая открывающая фигурная скобка начинает инициализацию nlist[0][1].

  4. Процесс будет продолжать до конца строки, где последняя закрывающая фигурная скобка завершит инициализацию nlist[0].

Строка 2 присваивает значения второй строке nlist аналогичным образом. Обратите внимание, что требуются внешние пары фигурных скобок, в которые будут заключены инициализаторы в строках 1 и 2. В следующей конструкции внешние фигурные скобки отсутствуют, и это привело бы к ошибке.

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 */
};

В этой конструкции первая открывающая фигурная скобка в строке 1 запускает инициализацию nlist[0], который является массивом из трех структур. Значения 1, 2 и 3 присваиваются трем членам первой структуры. При обнаружении следующей закрывающей фигурной скобки (после значения 3) инициализация nlist[0] завершается, и две оставшиеся структуры в массиве из трех структур автоматически инициализируются значением 0. Аналогичным образом { 4,5,6 } инициализирует первую структуру во второй строке nlist. Оставшимся двум структурам nlist[1] присваивается значение 0. Когда компилятор обнаруживает следующий список инициализаторов ({ 7,8,9 }), он выполняет попытку инициализировать nlist[2]. Поскольку nlist имеет только две строки, эта попытка завершится с ошибкой.

В следующем примере три члена intx инициализируются значениями 1, 2 и 3 соответственно.

struct list
{
    int i, j, k;
    float m[2][3];
} x = {
        1,
        2,
        3,
       {4.0, 4.0, 4.0}
      };

В структуре list выше три элемента в первой строке m инициализируются значением 4,0; элементы оставшейся части строки m инициализируются значением 0,0 по умолчанию.

union
{
    char x[2][3];
    int i, j, k;
} y = { {
            {'1'},
            {'4'}
        }
      };

В данном примере инициализируется переменная объединения y. Первый элемент объединения — это массив, поэтому инициализатор является агрегатным инициализатором. Список инициализаторов {'1'} присваивает значения первой строке массива. Поскольку только одно значение отображается в списке, элемент в первом столбце инициализируется символом 1, а оставшиеся два элемента в строке инициализируются значением 0 по умолчанию. Аналогичным образом, первый элемент второй строки x инициализируется символом 4, а оставшиеся два элемента в строке инициализируются значением 0.

См. также

Инициализация