IT이야기

2 차원 배열을 함수에 전달하는 올바른 방법

cyworld 2021. 4. 20. 21:42
반응형

2 차원 배열을 함수에 전달하는 올바른 방법


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*'

이것이 2 차원 배열을 함수에 전달하는 올바른 방법입니까? 그렇지 않은 경우 올바른 방법은 무엇입니까?


다음과 같이 함수를 선언해야합니다.

void display(int p[][numCols])

C FAQ 는 그 이유를 자세히 설명합니다. 요점은 배열이 포인터로 한 번 붕괴되고 재귀 적으로 발생하지 않는다는 것입니다. 배열의 배열은 포인터에 대한 포인터가 아니라 배열에 대한 포인터로 붕괴됩니다.


(귀하의 경우와 같이) 컴파일시 배열의 크기를 알고 있다면 void display(int p[][numCols]).

몇 가지 설명 : 함수에 배열을 전달할 때 실제로 첫 번째 멤버에 대한 포인터를 전달한다는 것을 알고있을 것입니다. C 언어에서 2D 배열은 배열의 배열입니다. 따라서 함수에 2D 배열의 첫 번째 하위 배열에 대한 포인터를 전달해야합니다. 따라서 자연스러운 방법은 int (*p)[numCols](즉, p는 numColsints 배열에 대한 포인터 임을 의미 합니다)라고 말하는 것 입니다. 함수 선언에서 "shortcut" p[]은 정확히 같은 의미입니다. (*p)(그러나 독자에게 하나의 변수가 아닌 배열의 시작에 대한 포인터를 전달한다고 알려줍니다)


당신은 잘못된 방식으로하고 있습니다. 배열에 대한 포인터를 사용하여 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);
}

이를 수행하는 몇 가지, 때로는 동등한 방법이 있습니다. 배열 선언 (참조 method_c()), 포인터 사용 (참조 method_b()) 또는 배열 배열에 대한 포인터 사용 (참조 method_a()). method_b()단일 포인터를 사용하는 경우 표준 배열 인덱싱을 사용하는 것이 쉽지 않으므로 포인터 산술을 사용하기 때문에 올바르게 가져 오기가 약간 더 어렵습니다. method_a()method_c()배열은 컴파일시 포인터에 비 재귀 적으로 부패하기 때문에 기본적으로 동일합니다. 다음은 세 가지 방법을 모두 보여주는 작은 프로그램입니다. 먼저 간단한 for 루프에서 2x4-array arr초기화 하고 인쇄합니다. 다음과 같이 표시됩니다.

arr:
0 1 2 3
0 1 2 3

그 후 세 가지 메서드를 모두 호출합니다. 모든 요소에 method_a()1을 method_b()더하고 2를 method_c()더하고 3을 더합니다. 호출 할 때마다 배열을 arr다시 인쇄 합니다. 함수가 올바르게 작동하면 출력에서 ​​쉽게 볼 수 있습니다. 크기는 임의적이며 두 개의 매크로 ROWCOL. 마지막 참고 사항 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;
        }
    }
}

간단하게 선언

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];

이 경우 차원은 함수의 시그니처에 표시되지 않지만 함수에는 여전히 차원에 대한 올바른 값이 있습니다.


다음과 같이 표시 방법의 서명을 변경할 수 있습니다.

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

여기에 p2D 배열의 행에 대한 포인터가 있습니다. 포인터는 배열의 열 수만 알면됩니다.

실제로 포인터는 각 행의 크기를 알아야합니다. 이것은 포인터 산술에 매우 중요합니다. 따라서 포인터를 증가시킬 때 포인터가 다음 행을 가리켜 야합니다.

여기서는 p일반 정수 포인터가 아닙니다. 메모리 크기에 대한 정수 포인터 integer_size x columns입니다.

기본적으로 아무것도 변경할 필요가 없습니다. display(arr)괜찮습니다.

참조 URL : https://stackoverflow.com/questions/9446707/correct-way-of-passing-2-dimensional-array-into-a-function

반응형