Как передать указатель на многомерный массив в C?

у меня есть двумерный массив, который работает с функцией:

bool matrix[rows][cols];
func(rows, cols, matrix);

void func(int rows, int cols, bool matrix[rows][cols]) {
    //...
}

однако, как только я попытаюсь иметь matrix в исходной функции модифицированные:

bool matrix[rows][cols];
func(rows, cols, &matrix);

void func(int rows, int cols, bool *matrix[rows][cols]) {
    //...
}

Я получаю несовместимую ошибку типа указателя. Я не знаю, почему.

4 ответов


bool matrix[rows][cols] представляет собой массив массивов типа bool

bool* matrix[rows][cols] представляет собой массив массивов типа указатель на bool или просто bool*.

таким образом, если вы определили функцию, чтобы взять массив массивов типа bool*, вам нужно пройти этот тип:

bool* m[row][col];
func( row , col , m );

если вы хотите иметь указатель на bool matrix[rows][cols], тогда ваш подход неверен.
Указатель на матрицу имеет вид: bool (*pmatrix)[rows][cols]. Поэтому определите свою функцию с этим типом и передайте адрес матричного массива:

func( rows , cols , &matrix );

@2501 уже ответил на ваш вопрос, но, поскольку вы хотите, чтобы измененный массив отражался на основной функции, вам на самом деле не нужен указатель на массив (что усложнит ситуацию)! Просто передайте массив непосредственно, как вы получите ожидаемые результаты!

почему, спросите вы?

короткий ответ: в C, массивы передаются по ссылке.

ответ:

всегда имейте в виду, что при использовании имени массива, он преобразуется в указатель на его первый элемент. Это обычно называют "распад массива".

возвращаясь к вашему коду, диаграмма bool matrix[rows][cols]; будет:

+---------------------+---------------------+---------------------+---------------------+---------------------+
|                     |                     |                     |                     |                     |
|     matrix[0][0]    |     matrix[0][1]    |     matrix[0][2]    |         ...         | matrix[0][cols - 1] |
|                     |                     |                     |                     |                     |
+---------------------+---------------------+---------------------+---------------------+---------------------+
|                     |                     |                     |                     |                     |
|     matrix[1][0]    |     matrix[1][1]    |     matrix[1][2]    |         ...         | matrix[1][cols - 1] |
|                     |                     |                     |                     |                     |
+---------------------+---------------------+---------------------+---------------------+---------------------+
|                     |                     |                     |                     |                     |
|         ...         |         ...         |         ...         |         ...         |         ...         |
|                     |                     |                     |                     |                     |
+---------------------+---------------------+---------------------+---------------------+---------------------+
|                     |                     |                     |                     |                     |
| matrix[rows - 1][0] | matrix[rows - 1][1] | matrix[rows - 1][2] |         ...         | matrix[rows - 1][cols - 1] |
|                     |                     |                     |                     |                     |
+---------------------+---------------------+---------------------+---------------------+---------------------+

из приведенной выше диаграммы ясно, что первый элемент

bool matrix[rows][cols];

является первым subarray matrix[0][0] to matrix[0][cols - 1]. Так что здесь происходит то, что адрес этого subarray передается функции. Это тип bool (*)[cols]. Это означало бы, что

void func(int rows, int cols, bool matrix[rows][cols])

будет работать так же, как

void func(int rows, int cols, bool (*matrix)[cols])

так, например, если вы хотите написать в третий слот второго поддиапазона matrix, вы можете использовать matrix[1][2] = WHATEVER; и изменения, внесенные из функции, также повлияют на вызывающего абонента, так как адрес был передан.


: есть несколько исключений, где массив "распад" не происходит. См.исключение для массива, не распадающегося на указатель?


указатель на одномерный массив, скажем int a[10] может выглядеть следующим образом:

int (*ptr)[10]
       |    |______________array of 10 integers(read type and number together)
       |______a pointer to ^

указатель на многомерный массив, скажем int a[10][10] может выглядеть, как показано ниже:

int (*ptr)[10][10]
      |    |     |_________________array of 10 integers(read type and number together)
      |    |______________array of ^ 
      |______a pointer to ^

предупреждение: ум скобках.

*matrix[rows][cols]) отличается от (*matrix)[rows][cols]). Разница указывается в ответе @2501.


можно использовать *** для матрицы.

char ***matrix = alloc_matrix(BUFFER_SIZE, BUFFER_SIZE);

char ***alloc_matrix(unsigned rows, unsigned columns) {
    char ***matrix = malloc(rows * sizeof(char **));
    if (!matrix) abort();

    for (unsigned row = 0; row < rows; row++) {
        matrix[row] = calloc(columns, sizeof(char *));
        if (!matrix[row]) abort();
        for (unsigned column = 0; column < columns; column++) {
            matrix[row][column] = NULL;
        }
    }
    return matrix;
}

вот пример, где мы используем malloc и pointers для создания матрицы.