Распад многомерных массивов как функциональных параметров
Я знаю это, например:
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-массивы.