Подтвердить что ты не робот

Правильный способ передачи 2-мерного массива в функцию

У меня есть двумерный массив, и я передаю его в функцию для выполнения определенных операций. Я хотел бы знать правильный способ сделать это...

#define numRows 3
#define numCols 7
#define TotalNum (numRows*numCols)
int arr[numRows][numCols] = {{0,1,2,3,4,5,6}, {7,8,9,10,11,12,13},{14,15,16,17,18,19,20}};

void display(int **p)
{
    printf("\n");
    for (int i = 0; i< numRows;i++)
    {
        for ( int j = 0;j< numCols;j++)
        {
            printf("%i\t",p[i][j]);
        }
        printf("\n");
    }
}

int main() {
    display(arr);
}

Появляется сообщение об ошибке:

'display': cannot convert parameter1 from 'int' to 'int*'

Является ли это правильным способом передачи двумерного массива в функцию? Если нет, то каков правильный путь?

4b9b3361

Ответ 1

Вы должны объявить свою функцию следующим образом:

void display(int p[][numCols])

Этот C FAQ полностью объясняет, почему. Суть его в том, что массивы распадаются на указатели один раз, это не происходит рекурсивно. Массив массивов распадается на указатель на массив, а не на указатель на указатель.

Ответ 2

Если (как в вашем случае), вы знаете размеры массива во время компиляции, вы можете написать только void display(int p[][numCols]).

Некоторое объяснение: вы, вероятно, знаете, что когда вы передаете массив функции, вы фактически передаете указатель на первый член. На языке C 2D-массив представляет собой массив массивов. Из-за этого вы должны передать функцию указателю на первый под-массив в 2D-массиве. Таким образом, естественным путем является int (*p)[numCols] (это означает, что p является указателем на массив из numCols ints). В объявлении функции у вас есть "shortcut" p[], что означает точно такую ​​же вещь, как (*p) (Но говорит читателю, что вы передаете указатель на начало массива, а не только на одну переменную)

Ответ 3

Вы делаете неправильно. Вы можете передать 2-й массив с помощью указателя на массив или просто передать массив или через одиночный указатель.

#define numRows 3
#define numCols 7
void display(int (*p)[numcols],int numRows,int numCols)//First method//
void display(int *p,int numRows,int numCols) //Second Method//
void display(int numRows,int numCols,int p[][numCols])  //Third Method
{
    printf("\n");
    for (int i = 0; i < numRows;i++)
    {
        for ( int j = 0; j < numCols;j++)
        {
            printf("%i\t",p[i][j]);
        }
        printf("\n");
    }
}

int main() {
    display(arr,numRows,numCols);
}

Ответ 4

Есть несколько, иногда эквивалентных способов сделать это. Объявляя массив (cf. method_c()), используя указатель (cf. method_b()) или используя указатель на массив массива (cf. method_a()). method_b(), используя один указатель, немного сложнее получить право, поскольку нелегко использовать стандартную индексацию массива и, следовательно, мы используем арифметику указателя. method_a() и method_c() в основном эквивалентны, поскольку массивы не рекурсивно распадаются на указатели во время компиляции. Вот небольшая программа, иллюстрирующая все три метода. Сначала мы инициализируем 2x4 -array arr в простом цикле и печатаем его. Он будет выглядеть следующим образом:

arr:
0 1 2 3
0 1 2 3

Затем мы вызываем все три метода. method_a() добавляет 1, method_b() добавляет 2 и method_c() добавляет 3 ко всем элементам. После каждого вызова мы снова выводим массив arr. Если функция работает правильно, вы легко увидите ее на выходе. Размер произвольный и может регулироваться с помощью двух макросов ROW и COL. В последнем примечании method_c() используется массив переменной длины, присутствующий с C99.

#include <stdio.h>
#include <stdlib.h>

#define ROW 2
#define COL 4

void method_a(int m, int n, int (*ptr_arr)[n]);
void method_b(int m, int n, int *ptr_arr);
void method_c(int m, int n, int arr[][n]);

int main(int argc, char *argv[]) {

    int arr[ROW][COL];

    int i;
    int j;
    for(i = 0; i < ROW; i++) {
        for(j = 0; j < COL; j++) {
            arr[i][j] = j;
        }
    }

    printf("Original array:\n");
    for (i = 0; i < ROW; i++) {
        for(j = 0; j < COL; j++) {
            printf("%d\t", arr[i][j]);
        }
        printf("\n");
    }

    printf("\n\n");

    method_a(ROW, COL, arr);

    printf("method_a() array:\n");
    for (i = 0; i < ROW; i++) {
        for(j = 0; j < COL; j++) {
            printf("%d\t", arr[i][j]);
        }
        printf("\n");
    }

    printf("\n\n");

    printf("method_b() array:\n");
    method_b(ROW, COL, (int *)arr);

    for (i = 0; i < ROW; i++) {
        for(j = 0; j < COL; j++) {
            printf("%d\t", arr[i][j]);
        }
        printf("\n");
    }

    printf("\n\n");

    method_c(ROW, COL, arr);

    printf("method_c() array:\n");
    for (i = 0; i < ROW; i++) {
        for(j = 0; j < COL; j++) {
            printf("%d\t", arr[i][j]);
        }
        printf("\n");
    }

    printf("\n\n");

    return EXIT_SUCCESS;
}

void method_a(int m, int n, int (*ptr_arr)[n])
{
    int i, j;
    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            ptr_arr[i][j] = j + 1;
        }
    }
}

void method_b(int m, int n, int *ptr_arr)
{
    int i, j;
    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            /* We need to use pointer arithmetic when indexing. */
            *((ptr_arr + i * n) + j) = j + 2;
        }
    }
    /* The whole function could have also been defined a bit different by taking
     * the i index out of the pointer arithmetic. n alone will then provide our
     * correct offset to the right. This may be a bit easier to understand. Our
     * for-loop would then look like this:
     * for (i = 0; i < m; i++)
     * {
     *     for (j = 0; j < n; j++)
     *     {
     *         *((ptr_arr + n) + j) = j + 2;
     *     }
     *     ptr_arr++;
     * }*/
}

void method_c(int m, int n, int arr[][n])
{
    int i, j;
    for (i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++)
        {
            arr[i][j] = j + 3;
        }
    }
}

Ответ 5

Объявите это просто

void display(int (*p)[numCols][numRows]);

Таким образом, ваш указатель p передает всю необходимую информацию, и вы можете извлечь из него все измерения без повторения numCols и numRows снова и снова.

void display(int (*p)[numCols][numRows])
{
   size_t i, j;

   printf("sizeof array=%zu\n", sizeof *p);
   printf("sizeof array[]=%zu\n", sizeof **p);
   printf("sizeof array[][]=%zu\n", sizeof ***p);

   size_t dim_y = sizeof *p / sizeof **p;
   printf("dim_y = %zu\n", dim_y);

   size_t dim_x = sizeof **p / sizeof ***p;
   printf("dim_x = %zu\n", dim_x);

   for(i=0; i<dim_y; i++) {
      puts("");
      for(j=0; j<dim_x; j++)
         printf(" %6d", (*p)[i][j]);
   }
}

Это особенно интересно, если вы используете typedefs (который мне не нравится btw)

 typedef int matrix[5][6];

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

Ответ 6

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

void display(int (*p)[numCols])

Здесь p является указателем на строку двумерного массива. Указателю нужно знать только количество столбцов в массиве.

На самом деле указатель должен знать размер каждой строки. Это очень важно для арифметики указателя. Чтобы при указании указателя указатель указывал на следующую строку.

Обратите внимание, что p не является нормальным целым указателем. Это целочисленный указатель на размер памяти, равный integer_size x columns.

В основном вам ничего не нужно менять. display(arr) просто отлично.

Ответ 7

Для большинства ответов выше вам нужно знать, по крайней мере, нет. столбцов в 2-мерном массиве. И даже если вы пройдете "нет". столбцов в самой функции или объявить no. столбцов в глобальном масштабе, некоторые компиляторы могут показать некоторые ошибки, и это может не сработать. Таким образом, вы можете вызвать функцию, например

func((int **)a,r,c);

где a - это 2-мерный массив, а r и c - нет. строк и столбцов соответственно. Вы можете поймать эти данные в функции как

void func(int **a,int r,int c);

И вы можете пересечь его с помощью указателей, где *((a+r*i)+j) даст вам значение a[i][j].