int (*a)[SIZE][SIZE]
объявляет a
как указатель на массив SIZE
от SIZE
из int
- при условии SIZE == 3
, вы получите что-то вроде этого:
+---+ +---+---+---+
a: | | -------> | | | |
+---+ +---+---+---+
| | | |
+---+---+---+
| | | |
+---+---+---+
(на самом деле макет был бы строго линейным, но мы пока пойдем с этим представлением).
Чтобы получить доступ к любому элементу массива с указанием, мы должны написать (*a)[i][j]
- нам нужно явно разыменовать a
, так как мы не хотим индексировать в a
, мы хотим индексировать в какие a
указывает на .
Помните, что a[i]
определяется как *(a + i)
- учитывая адрес a
, смещение i
элементов (не байтов!) От этого адреса и задерживает результат. Таким образом, (*a)[i][j]
эквивалентно a[0][i][j]
.
Теперь, если a
указывает на массив 3x3 int
, то a + 1
указывает на следующий массив 3x3 из int
:
+---+ +---+---+---+
a: | | -------> | | | |
+---+ +---+---+---+
| | | |
+---+---+---+
| | | |
+---+---+---+
a + 1: ---------> | | | |
+---+---+---+
| | | |
+---+---+---+
| | | |
+---+---+---+
, к которому мы будем обращаться как (*(a + 1))[i][j]
, или просто a[1][i][j]
.
Теперь, зачем вообще указатель на массив? В этом случае мы динамически распределяем массив, что мы будем делать, если а) мы не знаем, сколько SIZExSIZE
массивов нам понадобится до времени выполнения, или б) если результирующий массив будет слишком большим для размещения в виде переменная auto
, или c) если мы хотим увеличить или уменьшить количество массивов SIZExSIZE
по мере необходимости.
Как работает этот метод выделения многомерного массива? Начнем с выделения массива N
-элемента T
:
T *arr = malloc( sizeof *arr * N );
sizeof *arr
эквивалентно sizeof (T)
, поэтому мы выделяем пространство для N
объектов типа T
.
Теперь давайте заменим T
типом массива, R [M]
:
R (*arr)[M] = malloc( sizeof *arr * N );
sizeof *arr
эквивалентно sizeof (R [M])
, поэтому мы выделяем пространство для N
объектов типа R [M]
- IOW, N
M
-элементных массивов R
. Мы динамически создали эквивалент R a[M][N]
.
Мы могли бы также написать это как
R (*arr)[M] = malloc( sizeof (R) * M * N );
хотя я предпочитаю использовать sizeof *arr
; Вы поймете, почему через секунду.
Теперь мы можем заменить R
на еще одним типом массива, S [L]
:
S (*arr)[L][M] = malloc( sizeof *arr * N );
sizeof *arr
эквивалентно sizeof (S [L][M])
, поэтому мы выделяем достаточно места для N
объектов типа S [L][M]
или N
L
для M
массивов S
. Мы динамически создали эквивалент S arr[L][M][N]
.
Семантика для динамического выделения 1D, 2D и 3D массивов точно такая же - все, что изменилось, это тип. Используя sizeof *arr
каждый раз, мне нужно только отслеживать, сколько элементов мне нужно для этого типа.