Другие объяснили, что делает void foo(int **p)
, но не ответили на другую часть вашего вопроса: «когда параметр не должен быть двумерным массивом».
Ответом здесь является параметр int**p
, равный НИКОГДА 2D-массив. Даже если вы разыменуете его как p [row] [column], есть пара существенных отличий:
1) Память организована не как двумерный массив, а скорее как указатель на одномерный массив указателей «строк», каждый из которых указывает на отдельный одномерный массив целых чисел (индексируемых здесь как «столбец»).
2) «Строки» не обязательно должны быть смежными (т.е. вы не можете добавить ширину строки, чтобы получить следующую строку).
3) «Строки» не обязательно должны быть одинакового размера (они могут различаться по количеству доступных элементов)
Для передачи двумерного массива в функцию вы можете использовать различные сигнатуры функций. Самый простой - void foo(int p[25][15])
(где 25 и 15 - размер строки и столбца вашего массива).
Следующие сигнатуры функций для двумерных массивов генерируют один и тот же код при вызове: void foo(int (&p)[25][15])
и void foo(int (*p)[25][15])
и void foo(int p[][15])
. Последняя версия здесь p[][15]
позволяет обрабатывать двумерные массивы с фиксированной шириной столбца, но с различным количеством строк.
Если вы слишком умны, вы можете передать двумерный массив как void foo2(int *p)
, если передадите адрес первого элемента (или вы можете использовать int a[25][15]; foo2(a[0]);
). Однако в foo2 вам нужно будет использовать указатель math для доступа к строкам и столбцам 2D-массива, а также вам придется изменить способ вызова функции (чтобы передать int *, а не указатель массива). Эта «умная» техника иногда полезна в C, когда вам приходится работать с двумерными массивами разных размеров. В C ++ проще использовать шаблон с размерами массива в качестве параметров шаблона для обработки двумерных массивов различных размеров.