# 2차원 배열 이름의 포인터 형

# 2차원 배열 이름이 가리키는 것들

```c
#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): %lu\n", sizeof(arr2d));
    printf("sizeof(arr2d[0]): %lu\n", sizeof(arr2d[0]));
    printf("sizeof(arr2d[1]): %lu\n", sizeof(arr2d[1]));
    printf("sizeof(arr2d[2]): %lu\n", sizeof(arr2d[2]));
    return 0;
}

/* 결과
1795043140
1795043140
1795043140

1795043152
1795043152

1795043164
1795043164

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

배열 이름 arr2d를 대상으로 sizeof 연산을 하는 경우 배열 전체의 크기를 반환
arr2d[0], arr2d[1], arr2d[2]를 대상으로 sizeof 연산을 하는 경우 각 행의 크기를 반환

arr2d는 첫 번째 요소를 가리키면서 배열 전체를 의마한다. 하지만, arr2d[0]은 첫 번째 요소를 가리키되 1행만을 의미한다.
*/
```

## 배열 이름 기반의 포인터 연산: 배열 이름에 1을 더한 결과는?

### 두 포인터의 포인터 형이 같다면, 두 포인터를 대상으로 하는 증가 및 감소 연산의 결과로 증가 및 감소하는 값의 크기는 동일하다.

```c
#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", arr1+2);

    printf("arr2: %p\n", arr2);
    printf("arr2+1: %p\n", arr2+1);
    return 0;
}

/* 결과
arr1: 0x16db4ef50
arr1+1: 0x16db4ef58
arr1+2: 0x16db4ef60
arr2: 0x16db4ef38
arr2+1: 0x16db4ef44

2차원 배열 이름을 대상으로 증감 연산을 할 경우, 연산 결과는 각 행의 첫 번째 요소의 주소 값이 됌
때문에 자료형이 동일하더라도 배열의 가로길이가 다르다면, 포인터 형이 다르다.
*/
```

## 최종 결론! 2차원 배열 이름의 포인터 형

### 2차원 배열 이름의 포인터 형에는 두 가지 정보가 담겨야 함.

* 가리키는 대상은 무엇인가
    
* 배열 이름(포인터)를 대상으로 값을 1 증가 및 감소 시 실제로는 얼마가 증가 및 감소하는가
    

```c
int arr[3][4];
// arr은 가리키는 대상이 int형 변수이고, 포인터 연산 시 sizeof(int) x 4의 크기 단위로 증가 및 감소하는 포인터 형이다.
```

### 포인터 변수의 선언

```c
int (*ptr) [4];
/* 
int: int형 변수를 가리키는 포인터!
(*ptr): ptr은 포인터!
[4]: 포인터 연산 시 4칸 씩 건너뛰는 포인터!
이러한 변수는 2차원 배열을 가리키는 용도로만 사용되기 때문에 '배열 포인터 변수'라 한다.
*/
```

```c
#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]);
    return 0;
}

/* 결과
** Show 2,2 arr1 **
1 2
3 4
** Show 3,2 arr2 **
1 2
3 4
5 6
** Show 4,2 arr3 **
1 2
3 4
5 6
7 8
*/
```

---

# 2차원 배열 이름의 특성과 주의 사항

## 포인터 배열과 배열 포인터의 차이

```c
#include <stdio.h>

int main(void)
{
    int num1=10, num2=20, num3=30, num4=40;
    int arr2d[2][4]={1, 2, 3, 4, 5, 6, 7, 8};
    int i, j;

    int * whoA[4]={&num1, &num2, &num3, &num4};     // 포인터 배열
    int (*whoB)[4]=arr2d;       // 배열 포인터

    printf("%d %d %d %d\n", *whoA[0], *whoA[1], *whoA[2], *whoA[3]);
    for(i=0 ; i<2 ; i++)
    {
        for(j=0 ; j<4 ; j++)
            printf("%d ", whoB[i][j]);
        printf("\n");
    }
    return 0;
}

/* 결과
10 20 30 40
1 2 3 4 
5 6 7 8 
*/
```

## 2차원 배열을 함수의 인자로 전달하기

```c
int main(void)
{
    int arr1[2][7];
    double arr2[4][5];
    SimpleFunc(arr1, arr2);
    . . . .
}

/* 
arr1의 주소 값을 전달 받을 수 있는 매개 변수의 이름을 parr1,
arr2의 주소 값을 전달 받을 수 있는 매개 변수의 이름을 parr2
*/

int (*parr1)[7]
double (*parr2)[5]
// 따라서 SimpleFunc 함수가 void 형이라고 가정하면 아래처럼 선언
void SimpleFunc(int (*parr1)[7], double (*parr2)[5]) { . . . . }
```

```c
#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;
}

/* 결과
1 2 3 4 
5 6 7 8 

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

arr1의 합: 36
arr2의 합: 36

두 함수의 두 번째 매개변수를 배열의 세로길이를 전달받는다. 따라서 가로 길이가 4인 int형 2차원 배열이라면 세로 길이에 상관 없이 인자로 전달이 가능
sizeof(arr1) / sizeof(arr1[0])
sizeof(arr1) / sizeof(arr1[0])
배열의 전체 크기 / 배열의 가로 크기 = 배열의 세로 길이
*/
```

## 2차원 배열에서도 `arr[i]`와 `*(arr+i)`는 같다.

```c
// 1차원 배열
arr[i] == *(arr+i)  // arr[i]는 *(arr+i)와 같다.
// 이 식은 다차원 배열에서도 성립
```

```c
#include <stdio.h>

int main(void)
{
    int a[3][2]={{1, 2}, {3, 4}, {5, 6}};

    printf("a[0]: %p\n", a[0]);
    printf("*(a+0): %p\n", *(a+0));

    printf("a[1]: %p\n", a[1]);
    printf("*(a+1): %p\n", *(a+1));

    printf("a[2]: %p\n", a[2]);
    printf("*(a+2): %p\n", *(a+2));

    printf("%d, %d\n", a[2][1], (*(a+2))[1]);
    printf("%d, %d\n", a[2][1], *(a[2]+1));
    printf("%d, %d\n", a[2][1], *(*(a+2)+1));
    return 0;
}

/* 결과
Chapter18/"2DArrAccessType
a[0]: 0x16f092f40
*(a+0): 0x16f092f40
a[1]: 0x16f092f48
*(a+1): 0x16f092f48
a[2]: 0x16f092f50
*(a+2): 0x16f092f50
6, 6
6, 6
6, 6
*/
```
