Для любого массива или указателя arr
и индекса i
выражение *(arr + i)
точно равно arr[i]
.
Если мы сделаем этот перевод для *(*(arr+s1)+s2)
, это будет (arr[s1])[s2]
(или arr[s1][s2]
). Поскольку arr
не является указателем на указатель (или массив массивов), то arr[s1][s2]
не имеет смысла.
Вместо этого вы как бы эмулируете двумерный массив (массив массивов), используя массив (на первый элемент которого указывает arr
) и используйте arithmeti c для вычисления одного индекса в этом массиве.
Это очень распространено для динамически выделяемой памяти, где вместо использования неровный массив (с помощью указателей на указатели) вы используете одну смежную область или память.
Это может быть легче понять с помощью иллюстрации ...
Допустим, мы хочу 2d массив из 2 на 3 элемента. Мы можем создать его, используя динамическое выделение c в виде зубчатого массива:
int **arr;
arr = malloc(2 * sizeof *arr); // First dimension
for (size_t i = 0; i < 2; ++i)
arr[i] = malloc(3 * sizeof *arr[i]); // Second dimension
Поскольку у нас есть несколько распределений, в массиве нет местоположения, за arr[0][2]
может не следовать arr[1][0]
. Локальность и наличие смежного 2d-массива может быть полезно для некоторых алгоритмов и вариантов использования.
Непрерывный 2d-массив будет массивом массивов, таких как
int arr[2][3];
, но это сложнее обрабатывать динамически, поэтому вместо этого мы выделяем одну непрерывную область памяти из 2 * 3
элементов:
int *arr;
arr = malloc(2 * 3 * sizeof *arr);
К сожалению, это не может быть проиндексировано таким же интуитивно понятным способом, как зубчатый массив или массив массивов (т.е. arr[0][1]
не возможно). Но с некоторой умной арифметикой c это возможно: arr[row_index * row_length + column_index]
будет похоже на arr[row_index][column_index]
(для зубчатого массива или массива массивов).