Соответствует ли стандарту инициализация 2D-массива неизвестного размера с помощью инициализатора одномерного массива? - PullRequest
1 голос
/ 21 июня 2020

Недавно я встретил этот вопрос где мы получили определение 2D-массива, подобное этому:

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

Первое измерение пусто / размер массива неизвестен. Массив z инициализируется инициализатором одномерного массива.

Вот что говорит стандарт C (подчеркните мой):

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

Источник: ISO / IEC 9899: 2018 (C18), §6.7. 9 / 20.

Это означает, что инициализация четко определена. 2D-массив известного количества элементов с инициализатором 1D-массива.

Таким образом, fe:

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

должно быть эквивалентно:

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

Меня беспокоит следующее:

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

Источник: ISO / IEC 9899: 2018 (C18), §6.7.9 /22.

Это означает, что если размер массива / количество элементов в нем неизвестны, требуется, чтобы 2D-массив:

  1. Требуется самый большой индексированный элемент и
  2. Этот элемент должен иметь явный инициализатор.

Мои вопросы:

  • Это предусмотрено здесь?

  • Соответствует ли стандарту инициализация двумерного массива неизвестного размера с помощью инициализатора одномерного массива?

ИМХО, и после моих фактических знаний этого не должно. Но, может быть, я здесь что-то неправильно понял.

Я открыл этот вопрос, потому что другой вопрос помечен тегами C и C ++, поэтому юрист не подходит для настоящего языка и не фокусируется на C, плюс вопрос другого вопроса на самом деле совсем другой.

Ответы [ 3 ]

2 голосов
/ 21 июня 2020

Согласно C 2018 6.7.9 20:

  • x из int x[][3] инициализируется. Он содержит элемент, который является агрегатом, x[0], который является int [3].
  • Первым инициализатором для этого подагрегата является 0. Это не начинается с бандажа. Таким образом, «только достаточное количество инициализаторов из списка учитывается для элементов или членов субагрегата…». Таким образом, три инициализатора, 0, 1 и 2, используются для инициализации x[0].
  • Затем «любые оставшиеся инициализаторы остаются для инициализации следующего элемента…». Итак, 4 и 5 остаются инициализировать x[1].
  • Опять же, 4 не начинается с фигурной скобки, поэтому 4 и 5 берутся для инициализации x[1]. Согласно параграфу 21, поскольку не хватает инициализаторов для инициализации x[1], «оставшаяся часть агрегата должна быть инициализирована неявно так же, как объекты, которые имеют продолжительность хранения c».

4 и 5 явные инициализаторы. Они инициализируют x[1]. Следовательно, x[1] имеет явный инициализатор. Это самый большой индексированный элемент x, имеющий явный инициализатор. Поэтому определяет размер x.

2 голосов
/ 21 июня 2020

Вы спрашиваете об этом предложении из ISO / IEC 9899: 2018 (C18), §6.7.9 / 22.

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

Учитывайте это определение

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

Ширина определена, поэтому компилятор инициализирует такие элементы, как этот

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

Это из явных значений инициализации, определенных. Итак, теперь

  • Наивысший внутренний индекс 2
  • Наивысший внешний индекс 1

Итак, «самый большой индексированный элемент с явный инициализатор "равен

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

, и компилятор создает массив

int x[2][3];

с напоминанием о последней строке, неявно инициализированный как 0.

1 голос
/ 21 июня 2020

Как вы процитировали из 6.7.9 Инициализация :

[..] любые оставшиеся инициализаторы остаются для инициализации следующего элемента или члена агрегата, из которых текущий субагрегат или содержащееся объединение является частью.

Итак,

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

эквивалентно

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

, т.е. после инициализации первого элемента массива с помощью {0, 1, 2}, остальные инициализаторы образуют следующий элемент. И следующий элемент здесь int[3].

Аналогично,

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

эквивалентно:

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

и эквивалентно :

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

т.е. все подобъекты, которые не инициализированы явно, должны быть инициализированы неявно так же, как объекты, которые имеют c продолжительность хранения .

...