Во-первых, немного стандарт язык:
6.3.2.1 L-значения, массивы и обозначения функций
...
3 За исключением случаев, когда он является операндом оператора sizeof или унарного оператора &, или является строковым литералом, используемым для инициализации массива, выражение с типом «массив типа» преобразуется в выражение с типом «указатель на тип» это указывает на начальный элемент объекта массива и не является lvalue. Если объект массива имеет класс хранения регистров, поведение не определено.
С учетом декларации
int myarray[3][3];
тип из myarray
- это "3-элементный массив из 3-элементного массива int
". По правилу выше, когда пишешь
MyFunction(myarray, 3, 3);
выражение myarray
имеет свой тип, неявно преобразуемый ("распад") из "3-элементного массива из 3-элементного массива int
" в "указатель на 3-элементный массив из int
"или int (*)[3]
.
Таким образом, ваш прототип функции должен быть
int MyFunction(int (*array)[3], int row, int col)
Обратите внимание, что int **array
равно , а не так же, как int (*array)[3]
; арифметика указателей будет другой, поэтому ваши подписчики не будут указывать на правильные места. Помните, что индексирование массива определяется в терминах арифметики указателей: a[i]
== *(a+i)
, a[i][j] == *(*(a + i) + j)
. a+i
даст другое значение в зависимости от того, является a
int **
или int (*)[N]
.
В этом конкретном примере предполагается, что вы всегда передаете массив Nx3-элементов int
; не очень гибко, если вы хотите иметь дело с любым массивом размером NxM. Один из способов обойти это - явно передать адрес первого элемента в массиве, поэтому вы просто передаете простой указатель и затем вручную вычисляете правильное смещение:
void MyFunction(int *arr, int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
for (j = 0; j < col; j++)
printf("%d", a[i*col+j]);
}
int main(void)
{
int myarray[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
...
MyFunction(&myarray[0][0], 3, 3);
Поскольку мы передаем простой указатель на int
, мы не можем использовать двойной индекс в MyFunc
; результат arr[i]
является целым числом, а не указателем, поэтому мы должны вычислить полное смещение в массиве в одной операции индексации. Обратите внимание, что этот трюк будет работать только для действительно многомерных массивов.
Теперь **
может обозначать значения, которые организованы в двумерную структуру, но которая была построена другим способом. Например:
void AnotherFunc(int **arr, int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
for (j = 0; j < col; j++)
printf("%d", arr[i][j]);
}
int main(void)
{
int d0[3] = {1, 2, 3};
int d1[3] = {4, 5, 6};
int d2[3] = {7, 8, 9};
int *a[3] = {d0, d1, d2};
AnotherFunc(a, 3, 3);
...
}
Если следовать приведенному выше правилу, когда выражения d0
, d1
и d2
появляются в инициализаторе для a
, все их типы преобразуются из "3-элементного массива int
" в msgstr "указатель на int
". Точно так же, когда выражение a
появляется в вызове AnotherFunc
, его тип преобразуется из «3-элементного массива указателей в int
» в «указатель на указатель на int
».
Обратите внимание, что в AnotherFunc
мы добавляем оба измерения вместо вычисления смещения, как мы это делали в MyFunc
. Это потому, что a
является массивом указателей значений. Выражение arr[i]
возвращает нам i'th указатель значение смещения от местоположения arr
; затем мы находим j-е целочисленное значение смещения от этого значения указателя.
Может помочь следующая таблица - она показывает типы различных выражений массива и то, к чему они переходят, основываясь на их объявлениях (T (*)[N]
- это тип указателя, а не тип массива, поэтому он не затухает):
Declaration Expression Type Implicitly Converted (Decays) to
----------- ---------- ---- --------------------------------
T a[N] a T [N] T *
&a T (*)[N]
*a T
a[i] T
T a[M][N] a T [M][N] T (*)[N]
&a T (*)[M][N]
*a T [N] T *
a[i] T [N] T *
&a[i] T (*)[N]
*a[i] T
a[i][j] T
T a[L][M][N] a T [L][M][N] T (*)[M][N]
&a T (*)[L][M][N]
*a T [M][N] T (*)[N]
a[i] T [M][N] T (*)[N]
&a[i] T (*)[M][N]
*a[i] T [N] T *
a[i][j] T [N] T *
&a[i][j] T (*)[N]
*a[i][j] T
a[i][j][k] T
Шаблон для многомерных массивов должен быть четким.