Распад многомерных массивов как функциональных параметров

Я знаю это, например:

void foo(int a[])// or a[x]

будет рассмотрен компилятором следующим образом:

void foo(int *a)

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

Например:

void foo(int a[3][4])

Будет ли это что-то вроде этого?

void foo(int (*a)[4])

Или что-то вроде этого?

void foo(int **a)

Ответ 1

Когда массив распадается, он преобразуется в указатель на первый элемент. В случае int a[3][4] a является массивом int[4], поэтому указатель на элемент int [3][4] имеет тип int (*)[4].

Итак, это:

void foo(int a[3][4])

Такой же как:

void foo(int (*a)[4])

Ответ 2

Компилятор не может индексировать многомерный массив, переданный для правильной работы, не зная ни одного измерения, кроме самого внешнего.

Поэтому для 1D-массива длина не требуется:

void foo(int a[]);

а также

void foo(int a[3]);

равны, хотя и вводят в заблуждение, потому что C не обращает внимания на длину массива: это значит, что программист получает право.

Для 2D-массива внутренний размер должен быть правильным, или компилятор не знает, как его индексировать. Так

void foo(int a[][3]);

это хорошо, но

void foo(int a[][]);

не могут быть закодированы, и

void foo(int a[42][3]);

является хорошим, но ненужным, а не ограничительным, поскольку все потребности компилятора - это информация о том, как индексировать, а не сколько.

Ответ 3

Многомерные массивы часто являются источником проблем, особенно если вы хотите разрешить динамический размер.

В общем случае я бы предложил использовать

void foo(int* a, int size1, int size2);

или же

void foo(int* a, int numSizes, int* sizes);

Явно передавая ограничения размера, очень распространенные segfaults, которые вы получили из-за разложения указателя и отсутствия проверки. Использование типов массивов очень хрупкое и не рекомендуется в большинстве случаев.

Вы также можете указать метод индексирования, обычно a[size1*i+j] но вы можете захотеть чего-то другого.

Ответ 4

void foo(int a[3][4])

a - массив длиной 3, состоящий из 4-элементных int-массивов.

Так вот как это выглядит:

+---+---+---+---+
| 0 | 1 | 2 | 3 |
+---+---+---+---+
| 0 | 1 | 2 | 3 |
+---+---+---+---+
| 0 | 1 | 2 | 3 |
+---+---+---+---+

Вы можете добавлять строки, но вы не можете добавлять столбцы, потому что доступ к элементу k[3][4] выполняется, как a[3][2] = a[3*4 + 2]. Вот как найти поле диаграммы выше, используя информацию о строках и столбцах. Уравнение a[b][c] = a[b * row_number + c] не выполняется, когда матрица неквадратична. Сказать,

+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 |
+---+---+---+---+---+
| 0 | 1 | 2 | 3 |
+---+---+---+---+

Ты понимаешь это?

Посмотрите на первую таблицу выше. Его можно перечислить по-другому. Как насчет:

+---+---+----+----+
| 0 | 1 | 2  | 3  |
+---+---+----+----+
| 4 | 5 | 6  | 7  |
+---+---+----+----+
| 8 | 9 | 10 | 11 |
+---+---+----+----+

фактически (потому что это массив, а не таблица)

+---+---+---+---+---+---+---+---+---+---+----+----+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
+---+---+---+---+---+---+---+---+---+---+----+----+

См. В C, 2D-массив - это одномерный массив, только с разными индексами. Поэтому его можно было бы написать так:

void foo(int a[])

или же

void foo(int *a)

Как насчет

void foo(int **a)

Это массив ссылок на int массивы. Это не 2D-массив. Наоборот, это может пригодиться редко. Например, когда вы хотите иметь 2D-массив, что внутренние массивы (строки) имеют разную длину. Кроме того, это то, как Java обрабатывает 2D-массивы.