Статические многомерные массивы

Как я понял, элементы многомерного статического массива хранятся последовательно друг за другом в памяти. И если в таком массиве

int array[2][2]

я хочу обратиться к элементу array[1][1], то я могу это сделать так: *(*(array + 1) + 1). Почему я не могу написать просто *(array + 2 * 1 + 1)? Ведь элементы рядышком?


Ответы (3 шт):

Автор решения: HolyBlackCat

Почему я не могу написать просто *(array + 2 * 1 + 1)?

Потому что тип указателя не тот. *((int *)array + 2 * 1 + 1) сработало бы, хотя формально стандарт запрещает такие выкрутасы (это неопределенное поведение).

array[1][1] здесь сработает, и ведет себя точно так же, как *(*(array + 1) + 1).

У многомерных массивов нет каких-то особенных свойств - это просто массивы массивов.

Когда вы применяете + (или *, или еще много чего) к массиву, он преобразуется в указатель на свой первый элемент. Здесь тип элемента - int[2], соответственно, тип указателя - int (*)[2].

Когда к нему прибавляется первый индекс, указатель сдвигается на i * sizeof(int[2]) (т.е. i * 2 * sizeof(int)) (умножение на размер типа, на который он указывает), поэтому самому умножать на 2 не нужно.

Затем * возвращает int[2], и повторяется все то же самое. + преобразует его к int *, затем к нему прибавляется второй индекс, который умножается уже на sizeof(int), и результат разыменовывается в int.


А предложенный *(array + 2 * 1 + 1) (если не скастовать указатель) мало того, что возвращает int[2], а не int, так еще и выходит за границу массива.

→ Ссылка
Автор решения: DmitryK

Чтобы сделать так, как вы написали, вам нужно получить из указателя на указатель int **array просто одинарный указатель int*. Т.е. просто получить указатель на первый элемент массива в памяти. И далее работаете с двумерным массивом как с одномерным.

int array[2][2];
int *a = &array[0][0];
int b = *(a + 2 * 1 + 1);

По стандарту c++ все многомерные массивы располагаются в памяти последовательно. И это работает с любыми многомерными массивами, не только двумерными.

int arr[3][3][3]; // будет последовательный кусок в памяти размером 27 int-ов
int *a = &arr[0][0][0];
*(a) = 1;
*(a+26) = 27;
→ Ссылка
Автор решения: Supreme Machine

Потому что двумерный массив не совсем двумерный. Это скорее массив массивов. Создается указатель на указатели(т.е. массив, содержащий указатели как свои элементы ), которые в свою очередь указывают уже на одномерные массивы.

*(*(arr+1)+1) даст доступ к arr[1][1]. *(arr+1) дает второй элемент массива, но т.к. это массив указателей, то этот элемент-указатель. А потом уже он(назовем его р) смещается на +1 *(p+1) и получаем уже реальный элемент массива, который хотим. Как же это все хранится в памяти? Сначала идет массив из указателей, на начало которого указывает страшный указатель на указатели(он кстати и является именем массива, которое пишем). А потом, вовсе не обязательно подряд(во всяком случае с динамическими массивами точно, у вас же статический, в нем строки матрицы(двумерного массива) могут лежать друг за другом, но я не настолько опытен, чтобы сказать однозначно), лежат строки нашего двумерного массива в виде простых одномерных массивов и на них(каждый на свою) указывают те указатели, лежащие в массиве из указателей.

Вот generic картинка из интернета, которая наглядно показывает написанное выше. Надеюсь немного помог)

→ Ссылка