Однако у меня возникают проблемы с пониманием:
- Как вы будете получать доступ к элементам этой матрицы внутри функции. Можете ли вы по-прежнему использовать обозначение mat[i][j]?
- Как бы вы объявили и заполнили такую матрицу. Вы начинаете с чего-то вроде int **mat;? Я думаю, вам придется использовать malloc(), но мне трудно понять точное выражение объявления.
- Можно ли вообще использовать матрицы как указатели на такие указатели? Я читал, что они работают одинаково, но не совсем так же. Как вы решаете изложенную проблему в C89?
<сильный>1. mat[i][j]
В C89 вы правы, у вас нет поддержки VLA, если только это не предусмотрено нестандартным расширением компилятора (gcc делает это). Однако вы можете сделать то же самое в двух разных массивах.
Если вы знаете количество столбцов, которое будет у вас во время компиляции, и можете определить константу для этого значения, вы можете объявить указатель на массив [COLS]. Например, если вы знаете, что у вас будет 32 столбца и неизвестное количество строк, вы можете сделать:
#define COLS 32
...
int (*array)[COLS] = malloc (rows * sizeof *array);
Это выделит блок памяти в одном вызове, обеспечивая хранилище для rows
количества int[32]
массивов, что позволит вам получить доступ как array[i][j]
, как и раньше. Прелесть использования указатель-на-массив заключается в том, что у вас есть однократное выделение и однократное освобождение. Вы можете realloc
количество строк по мере необходимости.
(примечание: как указывает @PaulOgilvie, есть разница в том, как вы можете передать указатель на массив в функцию. Вы не можете передать как int array[][cols]
как с VLA, вы должны передать как int (*array)[cols]
- что вы также можете использовать с VLA, но обратное неверно)
Другой вариант — объявить указатель на указатель на type
(например, int **array;
). Обратите внимание, что здесь НЕ используется массив, это просто один указатель на указатель для ввода. Здесь распределение представляет собой двухэтапный процесс. Сначала вы выделяете память для некоторого количества указателей (количество строк указателей). Например:
int **array = malloc (rows * sizeof *array);
Выше вы выделяете блок памяти, способный хранить rows
количество указателей, на которые затем вы можете отдельно выделить и назначить блоки памяти для хранения любого количества целочисленных значений (нет необходимости, чтобы каждая строка указывала на блок с тем же количеством целочисленных значений — что делает возможным «зубчатый массив» из-за отсутствия лучших слов). Чтобы затем выделить хранилище для целочисленных значений (или любого другого типа, который вы используете), делать:
for (int i = 0; i < rows; i++)
array[i] = malloc (cols * sizeof *array[i]);
(примечание: вы должны проверять каждое выделение, которое было опущено для краткости. Также обратите внимание в обоих случаях над разыменованным указателем использовался для установки размера шрифта для выделения, например malloc (rows * sizeof *array)
, который мог бы быть malloc (rows * sizeof(int*)))
. Если вы всегда используете указатель разыменования для установки размера шрифта -- вы никогда не ошибетесь с размером шрифта)
На данный момент у вас есть указатель на блок памяти, хранящий rows
количество указателей, а затем вы назначили блок памяти, способный хранить cols
количество целочисленных значений, к которым вы можете получить доступ как array[i][j]
. Кроме того, здесь вы можете realloc
блок памяти предоставить rows
указателей для добавления строк в любое время, когда вам нужно, но вы также должны выделить память для целочисленных значений и назначить эти выделенные блоки вашим новым указателям строк, прежде чем пытаться хранить там значения.
Когда вы закончите с смоделированным 2D-массивом на основе указатель-указатель, у вас также будет 2 шага. Вы должны освободить выделенные блоки, хранящие целые числа, прежде чем вы сможете освободить блок, содержащий указатели ваших строк, например.
for (int i = 0; i < rows; i++)
free (array[i]); /* free storage for integers */
free (array); /* free pointers */
<сильный>2. Заполнение любого объекта
В любом случае, поскольку вы можете получить доступ к смоделированному 2D-массиву с помощью нотации array[i][j]
, теперь вы можете заполнять и получать доступ к значениям в array
так же, как вы делали это с 2D VLA в C99+.
<сильный>3. Можно ли использовать матрицы с указателями на указатели
Да, смоделированный 2D-массив обеспечивает ту же функциональность, что и описанная выше.
person
David C. Rankin
schedule
19.01.2020
malloc()
. 3: Да, при передаче в качестве аргумента матрица распадается на указатель на указатель, точно так же, как массив распадается на указатель. - person Marco Bonelli   schedule 19.01.2020for(size_t i = 0; i < rows; i++) {
for(size_t j = 0; j < cols; j++) {
scanf("%d", &mat[i][j]); /*using scanf as an example, could be anything*/
}
}
Полагаю, что в этом случае мне пришлось бы выделять новый элемент для каждого места в матрице? - person Samuele B.   schedule 19.01.2020