Language/C, C++

[C] 2차원 배열의 포인터

Phulasso 2020. 12. 30. 20:41
int arr2d[3][3];

위의 2차원 배열은 다음과 같은 모양을 갖는다.

[0][0] [0][1] [0][2]
[1][0] [1][1] [1][2]
[2][0] [2][1] [2][2]

2차원 배열의 경우 arr2d[0], arr2d[1], arr2d[2]도 각각 1행, 2행, 3행의 첫 번째 요소를 가리킨다.

또한 2차원 배열의 첫 번째 요소의 주소 값을 출력할 때는 다음 두 가지 형태로 동일하게 출력이 가능하다.

printf("%p\n", arr2d);
printf("%p\n", arr2d[0]);
#include <stdio.h>

int main(void)
{
    int arr2d[3][3];
     printf("%d\n", arr2d);
     printf("%d\n", arr2d[0]);
     printf("%d\n\n", &arr2d[0][0]);

    printf("%d\n", arr2d[1]);
    printf("%d\n\n",&arr2d[1][0]);

     printf("%d\n", arr2d[2]);
     printf("%d\n\n", &arr2d[2][0]);

     printf("sizeof(arr2d) : %d\n", sizeof(arr2d));
     printf("sizeof(arr2d[0]) : %d\n", sizeof(arr2d[0]));
     printf("sizeof(arr2d[1]) : %d\n", sizeof(arr2d[1]));
     printf("sizeof(arr2d[2]) : %d\n", sizeof(arr2d[2]));
    return 0;
}
/* output
 -272632624
 -272632624
 -272632624

 -272632612
 -272632612

 -272632600
 -272632600

 sizeof(arr2d) : 36
 sizeof(arr2d[0]) : 12
 sizeof(arr2d[1]) : 12
 sizeof(arr2d[2]) : 12
 */

 위 코드와 같이 arr2d는 첫 번째 요소를 가리키며, 배열 전체를 의미한다.  arr2d[0]은 첫 번째 요소를 가리키며 1행만을 의미한다. 그래서 sizeof 연산 결과 arr2d는 배열 전체의 크기인 36이 출력되었고, arr2d[0]은 첫 번째 행의 크기인 12가 출력되었다.

 

1차원 배열의 경우 다음 코드에서 iarr은 int형 포인터 이기 때문에 iarr+sizeof(int)의 계산 결과가 출력되고,  darr은 double형 포인터 이므로 darr+sizeof(double)이 출력된다.

int iarr[3];
double darr[7];

printf("%p\n", iarr+1);
printf("%p\n", darr+1);

또한 2차원 배열을 대상으로 증가 연산을 진행해보면 다음과 같다.

#include <stdio.h>

int main(void)
{
    int arr1[3][2];
    int arr2[2][3];

    printf("arr1 : %p\n", arr1);
    printf("arr1+1 : %p\n", arr1+1);
    printf("arr1+2 : %p\n\n", arr1+2);

    printf("arr2 : %p\n", arr2);
    printf("arr2+1 : %p\n", arr2+1);
    return 0;
}
/* output : 
@"arr1 : 0x7ffeefbff7c0\r\n"
@"arr1+1 : 0x7ffeefbff7c8\r\n"
@"arr1+2 : 0x7ffeefbff7d0\r\n"
@"\r\n"
@"arr2 : 0x7ffeefbff7a0\r\n"
@"arr2+1 : 0x7ffeefbff7ac\r\n"
*/

첫 번째 배열의 경우 1씩 증가시켰을 때 8이 증가하였고, 두 번째 배열의 경우 1을 증가시키면 12가 증가하였다. 2차원 배열 이름을 대상으로 증가 및 감소 연산을 할 경우 각 행의 첫번째 요소를 가리킨다. arr1은 1행의 첫번째 요소를 가리키며, arr1+1은 두번째 행의 첫번째 요소를 가리킨다. arr1은 가로가 한 행에 두 칸이기 때문에 8이 증가한 것이다. 2차원 배열의 포인터형은 가로의 길이에 따라서 달라진다.

2차원 배열은 포인트 연산시 sizeof(type) x 가로길이 만큼 값이 증가한다.

 

위와 같은 유형의 포인트 변수 선언은 int형이며, sizeof(int)x4의 크기 단위로 증가 및 감소하는 포인터 변수 선언은 다음과 같다.

int (*ptr)[4];

 

#include <stdio.h>

int main(void)
{
    int arr1[2][2] = {
        {1,2}, {3,4}
    };
    int arr2[3][2] = {
        {1,2}, {3,4}, {5,6}
    };
    int arr3[4][2] = {
        {1,2}, {3,4}, {5,6}, {7,8}
    };

    int (*ptr)[2];
    int i;

    ptr = arr1;
    printf("** Show 2,2 arr1 **\n");
    for(i = 0; i < 2; i++)
        printf("%d %d\n", ptr[i][0], ptr[i][1]);

    ptr = arr2;
    printf("** Show 3,2 arr2 **\n");
    for(i = 0; i < 3; i++)
        printf("%d %d\n", ptr[i][0], ptr[i][1]);
    
    ptr = arr3;
    printf("** Show 4,2 arr3 **\n");
    for(i = 0; i < 4; i++)
        printf("%d %d\n", ptr[i][0], ptr[i][1]);
      
}
/* output : 
@"1 2\r\n"
@"3 4\r\n"
@"** Show 3,2 arr2 **\r\n"
@"1 2\r\n"
@"3 4\r\n"
@"5 6\r\n"
@"** Show 4,2 arr3 **\r\n"
@"1 2\r\n"
@"3 4\r\n"
@"5 6\r\n"
@"7 8\r\n"
*/

위 코드와 같이 포인터 변수를 선언하여 2차원 배열에 접근할 수 있다.

 

2차원 배열의 주소 값을 인자로 전달 받는 함수를 정의할 때 매개 변수는 다음과 같이 선언할 수 있다.

void Function(int (*parr1)[7], double (*parr2)[5]) {...}
void Function(int parr[][7], double parr[][5]) {...}

위 두 방식의 매개변수 선언은 동일한 방식이다.

#include <stdio.h>

void ShowArr2DStyle(int (*arr)[4], int column)
{
    int i,j;
    for(i=0; i<column; i++){
        for(j=0; j<4; j++)
            printf("%d ", arr[i][j]);
        printf("\n");
    }
    printf("\n");
}

int Sum2DArr(int arr[][4], int column)
{
    int i, j, sum=0;
    for(i=0; i<column; i++)
        for(j=0; j<4; j++)
            sum+=arr[i][j];
    return sum;
}

int main(void)
{
    int arr1[2][4] = {1,2,3,4,5,6,7,8};
    int arr2[3][4] = {1,1,1,1,3,3,3,3,5,5,5,5};

    ShowArr2DStyle(arr1, sizeof(arr1)/sizeof(arr1[0]));
    ShowArr2DStyle(arr2, sizeof(arr2)/sizeof(arr2[0]));
    printf("arr1의 합 : %d\n", Sum2DArr(arr1, sizeof(arr1)/sizeof(arr1[0])));
    printf("arr2의 합 : %d\n", Sum2DArr(arr2, sizeof(arr2)/sizeof(arr2[0])));
    return 0;
}
/* output : 
1 2 3 4 
5 6 7 8 

1 1 1 1 
3 3 3 3 
5 5 5 5 

arr1의 합 : 36
arr2의 합 : 36
*/

위 코드의 다음과 같은 연산은 배열의 세로길이를 계산하는 것이다.

sizeof(arr1) / sizeof(arr1[0])
sizeof(arr2) / sizeof(arr2[0])

sizeof(arr1)은 배열의 전체 크기를 나타내고, sizeof(arr1[0])은 배열의 가로의 크기를 나타내기 때문에 위 코드는 배열의 세로 길이를 의미한다.

 

int arr[3][2] = { {1,2}, {3,4}, {5,6} };

2차원 배열이 위와 같이 선언되어 있을 때, 인덱스 [2][1]의 위치의 값을 4로 변경하려면 다음의 코드들을 이용할 수 있다.

arr[2][1] = 4;
(*(arr+2))[1] = 4;
*(arr[2]+1) = 4;
*(*(arr+2)+1) = 4;