Назначение подмассива: ожидается инициализация с "{...}" для ошибки совокупного объекта - PullRequest
1 голос
/ 29 мая 2019

Чем можно объяснить ошибку в строке 1?

/* Line 0 */    int foo[10][10];
/* Line 1 */    int foo_alias_compile_error[] = foo[0];
/* Line 2 */    int foo_alias_also_errors[10] = foo[0];
/* Line 3 */    int * foo_alias_works = foo[0];

Ошибка в строке 2 на самом деле не беспокоит меня, потому что мне не нужно иметь возможность повторяться и повторно объявлять размер массива. Однако ошибка в строке 1 (инициализация с "{...}", ожидаемая для агрегатного объекта ), смущает меня. Я понимаю, что int foo_alias_compile_error[], вероятно, является "совокупным объектом". Я просто не понимаю, почему язык настроен так, чтобы он не работал. Я понимаю, почему 3-я строка работает, но она кажется нерепрезентативной - это массив, так что я бы лучше задокументировал его как массив.

Ответы [ 3 ]

0 голосов
/ 29 мая 2019

Можно подумать, что в строке 1 создается ссылка для 0-й записи в foo. Однако C ++ работает не так. Скорее, оператор присваивания (=) вызывает операцию копирования. Таким образом, C ++ интерпретирует строку 1 как директиву для копирования элементов foo[0] в новый массив с неправильным названием foo_alias_compile_error.

Это не то, что имелось в виду - кто-то хотел ссылку, а не копию. Итак, хорошо, что C ++ вызвал ошибку по несвязанной причине и спас ее от себя.

@ FrançoisAndrieux предлагает жизнеспособное решение. Вот более полный пример, показывающий, что ссылка (не копия) может быть сделана с помощью int (&foo_reference)[10] = foo[0];.

int foo[10][10];
for (int i = 0; i < 10; ++i) {
    for (int j = 0; j < 10; ++j) {
        foo[i][j] = i + j * 10;
    }
}
int (&foo_reference)[10] = foo[0];

for (int j = 0; j < 10; ++j) {
    foo_reference[j] = 100 + j;
}

for (int i = 0; i < 10; ++i) {
    printf("foo   [0][%i] is %i\n", i, foo[0][i]);
    printf("foo_refer[%i] is %i\n", i, foo_reference[i]);
}

Фрагмент вывода

foo   [0][0] is 100
foo_alias[0] is 100
foo   [0][1] is 101
foo_alias[1] is 101
foo   [0][2] is 102
foo_alias[2] is 102
foo   [0][3] is 103
foo_alias[3] is 103

Побочное примечание

Стоит отметить, что функции, которые принимают массивы в качестве аргументов, неявно преобразуют свои аргументы массива в указатели (как показано в строке 3). Итак, это одна из причин, почему кто-то может неправильно думать, что что-то вроде строки 1 должно работать.

Другими словами, следующий код

void barz(int arg[]) {
    arg[2] = 99999;
}

int another_array[] = {0, 1, 2, 3, 4};
barz(another_array);
printf("another_array[2] is %i\n", another_array[2]);

"Правильно" печатает 99999, а не 2.

0 голосов
/ 30 мая 2019

Инициализатор в определении массива (то есть массив в стиле C) должен быть скобочным списком.

Это правило распространяется как на строку 1, так и на строку 2, где выпредоставьте что-то, что не является заключенным в скобки списком, и, следовательно, код является неправильным.

Дополнительная информация: если вы предоставляете заключенный в скобки список, то каждый элемент списка берется в качестве инициализатора для an элемент массива.Как следствие, невозможно предоставить один инициализатор, который заставляет его устанавливать несколько элементов массива.

Это правило почти применяется рекурсивно;если у вас есть массив массивов, то инициализатор должен быть скобочным списком.Однако есть правило, что вложенные фигурные скобки могут быть опущены в некоторых случаях (и код будет вести себя так, как если бы была обеспечена полная привязка).Например, int x[2][2] = { 1, 2, 3, 4 }; разрешен и ведет себя как int x[2][2] = { {1, 2}, {3, 4} };.

0 голосов
/ 29 мая 2019

, если вы не указали размер массива (в строке 1).компилятор указывает это для вас.и для этого вы должны сделать это:

/* Line 0 */    int foo[10][10];
/* Line 1 */    int foo_alias_compile_error[] = {foo[0]};

, но это все еще имеет проблему.когда компилируете этот код:

 $ g++ error.cpp
 $ error.cpp:4:28: error: invalid conversion from ‘int*’ to ‘int’ [-fpermissive]
 $    4 |     int fooError[] = {foo[0]};
 $      |                       ~~~~~^
 $      |                            |
 $      |                            int*

, потому что foo[0] является указателем и указывает на первую строку вашей матрицы (в строке 1).Вы можете сделать это:

/* Line 0 */    int foo[10][10];
/* Line 1 */    int foo_alias_compile_error[] = {foo[0][0]};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...