Инициализация массива в C

У меня есть сомнения относительно следующего фрагмента кода:

int main()
{
    int array1 = {1,2,3,4,5}; //error in c++ , warning in c
    int array2[] = {1,2,3,4,5};
    int array3[5] = {1,2,3,4,5};
}

Этот фрагмент кода дает ошибку в строке 3 в c++, но не в c?

Я знаю, что array1 на самом деле int и array2 и array3 являются массивами, поэтому почему компилятор c не показывает ошибку, а просто предупреждение: "лишние элементы в скалярной инициализации"

Используется ли такое определение и почему оно действует в c?

Ответ 1

Недействительно C. См. C11 6.7.9:

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

Я бы предположил, что вы используете gcc. Затем, если вы хотите, чтобы ваша программа вела себя как строгий стандарт C, скомпилируйте ее как таковую:

gcc -std=c11 -pedantic-errors

дает

ошибка: избыточные элементы в скалярном инициализаторе

Ответ 2

Это недействительно в C. У него меньше проверок кода. Это поведение Undefined.

От: C11 draft N1570; 6.7.9 Инициализация

Constraints
2 Ни один инициализатор не попытается предоставить значение для объекта, не содержащегося в инициализированном объекте.
3 Тип объекта, который должен быть инициализирован, должен быть массивом неизвестного размера или полным типом объекта, который не является массивом переменной длины.

Определенно прерывает ограничение 2. Является ли int полным типом объекта?

из приложения J.2 (поведение undefined):

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

дополнительно:
@James Kanze:

prog.c:4:12: error: expected identifier or ‘(’ before numeric constant
  int i = 1,2,3,4,5;
            ^

вы можете это сделать, но вам нужно сделать одно выражение:

int i = (1,2,3,4,5); //need parenthesis, evaluates to 5, values 1-4 thrown away.

Компиляция с int, инициализированная списком initalizer, порождает предупреждение (в gcc):

prog.c:5:2: warning: excess elements in scalar initializer [enabled by default]
  int j = {1,2,3,4,5};
  ^

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

Ответ 3

Он действителен в соответствии со спецификацией C.

Цитата из раздела C11 6.7.9 (Инициализация):

Синтаксис

1 initializer:
    assignment-expression
    { initializer-list }
    { initializer-list , }

Таким образом, инициализатор может быть либо прямым выражением (assignment-expression выше), либо списком инициализаторов в скобках. Ограничения в этом разделе стандарта не ограничивают это для "нормальных" (не массив или не указателей) переменных.

Это позволяет вам писать, например.

int a = { 1 };

Ответ 4

Как и все остальные, я предполагаю, что строка, о которой вы думаете, такова:

int array1 = {1,2,3,4,5};

В этом случае нет разницы между C и С++; линия, возможно, легальна на обоих языках, но это не значит, что вы думаете. В C и С++ существует утверждение о том, что если тип является скалярным типом (int is), то содержимое {...} должно быть единственным выражением. И 1,2,3,4,5 можно интерпретировать как одно выражение (с оператором запятой); что-то вроде:

int array1 = 1, 2, 3, 4, 5;

явно легален.

Это несколько неоднозначно, однако, поскольку на обоих языках грамматика для этого типа инициализации делает , пунктуацию, а не оператор. Так что это вопрос интерпретации; это утверждение о том, что содержимое должно быть единственным выражением - ограничение на грамматику (что приведет к тому, что запятая станет оператором) или ограничение на результаты оценки указанной грамматики. Мое интуитивное чувство состоит в том, что второе - это намерение, и это утверждение должно приводить к ошибке. Но разница не между C и С++, а между тем, как авторы компиляторов интерпретируют стандарт.

EDIT:

Перечитывая немного ближе: в стандарте С++ он явно говорит, что

Если T - скалярный тип, то объявление формы

    T x = { a };

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

    T x = a;

Который не оставляет много места для разборки: на С++ выражение кажется явно законным; это только в C, где есть некоторая двусмысленность.

Ответ 5

Правильный способ инициализации массива в C/С++:

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

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

Второй способ - определить массив и после него инициализировать его:

int array3[5];
int *array = new int[5];

В этом случае вам нужно сообщить компилятору, какой размер будет массивом. Кроме того, во втором случае вам нужно удалить память вручную.

Ответ 6

Как говорит ваш компилятор, это неверно и для C. Важно отметить, что в случае таких "нарушений ограничений" (официальный термин) компилятор может просто произвести диагностику (которую сделал ваш компилятор) и продолжить.

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

Ответ 7

C - разрешающий язык низкого уровня. Это позволяет влиять на указатель на int.

int array1 = {1,2,3,4,5};

ИЗМЕНИТЬ:

Я должен был протестировать его под разными компиляторами, прежде чем писать глупые вещи.

Это отклоняется как ошибка MSVC (2008).

Оба gcc и clang выдают предупреждение excess elements in scalar initializer и просто влияют 1 на a.