Поделиться через


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

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

Синтаксис

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 }

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

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

Максимальный размер массива определяется size_t.

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

Примеры

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

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 имеет только две строки, эта попытка завершится с ошибкой.

В следующем примере три элемента x с типом int инициализируются значениями 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.

См. также

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