[C언어] 2차원 배열을 포인터에 넣기

Hyejin Kim·2023년 5월 6일
0

C언어

목록 보기
4/7

1. 도입

1차원 배열은 단일 포인터에 넣을 수 있었습니다. 그러면 2차원 배열은 이중 포인터에 넣을 수 있지 않을까요?

int numArr[3][4] = {    // 세로 크기 3, 가로 크기 4인 int형 2차원 배열 선언
    { 11, 22, 33, 44 },
    { 55, 66, 77, 88 },
    { 99, 110, 121, 132 }
};

int **numPtr = numArr;    // 자료형이 다르다는 경고 발생

printf("%d\n", numPtr[0][0]);    // 실행 에러

하지만 컴파일을 해보면 다음과 같이 자료형이 다르다는 경고가 발생합니다.

array.c(11): warning C4047: '초기화 중': 'int **'의 간접 참조 수준이 'int (*)[4]'() 다릅니다.

2. 포인터 배열 선언방법

실행을 해보면 에러가 발생하여 numPtr[0][0]의 값은 출력되지 않습니다. 2차원 배열을 포인터에 담으려면 다음과 같이 특별한 방법이 필요합니다.

자료형 (*포인터이름)[가로크기];

즉, 포인터를 선언할 때 *과 포인터 이름을 괄호로 묶어준 뒤 [ ]에 가로 크기를 지정합니다.

int (*numPtr)[4];

풀어서 설명하면 가로 크기가 4인 배열을 가리키는 포인터라는 뜻입니다.

참고 | int *numPtr[4]

int (numPtr)[4]에서 괄호를 뺀 int numPtr[4]는 int형 포인터 4개를 담을 수 있는 배열이라는 뜻입니다. 즉, 괄호가 있으면 배열을 가리키는 배열 포인터, 괄호가 없으면 포인터를 여러 개 담는 포인터 배열입니다.

int num1, num2, num3, num4;
int *numPtr[4] = { &num1, &num2, &num3, &num4 };    // int형 포인터를 4개 담는 배열

int *numPtr[4] 로 배열을 선언할 경우 초기화는 다음과 같이 합니다.

int *numPtr[4] = numArr // 불가능, numPtr와 numArr의 메모리 주소가 다릅니다. 
numPtr[0] = numArr[0]
numPtr[1] = numArr[1]
numPtr[1] = numArr[1]

이 경우 numPtr는 numArr와 동일하게 사용할 수 있습니다.
다만, numPtr와 numArr의 메모리 주소는 다릅니다. numPtr를 numArr로 초기화 하지 못했기 때문에 numPtr의 주소는 다른 곳에 저장됩니다.

printf("%p", numPtr); // 서로 다른 값 출력
printf("%p", numArr); // 서로 다른 값 출력

3. 사용예시

이제 2차원 배열을 포인터에 할당해서 사용해보겠습니다.

코드

#include <stdio.h>

int main()
{
    int numArr[3][4] = {    // 세로 3, 가로 4 크기의 int형 2차원 배열 선언
        { 11, 22, 33, 44 },
        { 55, 66, 77, 88 },
        { 99, 110, 121, 132 }
    };

    int (*numPtr)[4] = numArr;

    printf("%p\n", *numPtr); // 002BFE5C: 2차원 배열 포인터를 역참조하면 세로 첫 번째의 주소가 나옴
                             // 컴퓨터마다, 실행할 때마다 달라짐

    printf("%p\n", *numArr); // 002BFE5C: 2차원 배열을 역참조하면 세로 첫 번째의 주소가 나옴
                             // 컴퓨터마다, 실행할 때마다 달라짐

    printf("%d\n", numPtr[2][1]);    // 110: 2차원 배열 포인터는 인덱스로 접근할 수 있음

    printf("%d\n", sizeof(numArr));  // 48: sizeof로 2차원 배열의 크기를 구하면 배열이 메모리에 
                                     // 차지하는 공간이 출력됨

    printf("%d\n", sizeof(numPtr));  // 4 : sizeof로 2차원 배열 포인터의 크기를 
                                     // 구하면 포인터의 크기가 출력됨(64비트라면 8)

    return 0;
}

실행결과

002BFE5C
002BFE5C
110
48
4

int (*numPtr)[4] = numArr;와 같이 2차원 배열을 포인터에 바로 할당할 수 있습니다. 단, 자료형과 가로 크기가 일치해야 합니다.

2차원 배열을 포인터에 할당한 뒤 포인터를 역참조해보면 배열의 세로 첫 번째 주솟값이 나옵니다. 즉, 배열이 시작하는 주소입니다. 마찬가지로 2차원 배열 자체도 역참조해보면 배열의 세로 첫 번째 주솟값이 나옵니다.

printf("%p\n", *numPtr); // 002BFE5C: 2차원 배열 포인터를 역참조하면 세로 첫 번째의 주소가 나옴
                         // 컴퓨터마다, 실행할 때마다 달라짐

printf("%p\n", *numArr); // 002BFE5C: 2차원 배열을 역참조하면 세로 첫 번째의 주소가 나옴
                         // 컴퓨터마다, 실행할 때마다 달라짐

2차원 배열 포인터는 [ ]를 두 번 사용하여 배열의 요소에 접근할 수 있습니다.

printf("%d\n", numPtr[2][1]);    // 110: 2차원 배열 포인터는 인덱스로 접근할 수 있음

배열과 포인터가 다른 점은 sizeof로 크기를 계산했을 때입니다. sizeof로 배열의 크기를 구해보면 배열이 메모리에 차지하는 공간이 출력되지만 sizeof로 배열의 주소가 들어있는 포인터의 크기를 구해보면 그냥 포인터의 크기만 나옵니다(32비트라면 4, 64비트라면 8).

printf("%d\n", sizeof(numArr));   // 48: sizeof로 2차원 배열의 크기를 구하면 배열이 메모리에 
                                  // 차지하는 공간이 출력됨

printf("%d\n", sizeof(numPtr));   // 4 : sizeof로 2차원 배열 포인터의 크기를 
                                  // 구하면 포인터의 크기가 출력됨(64비트라면 8)

4. 3차원 배열

아래 출처페이지를 참고하세요.

출처

코딩도장

profile
Hello. I am a developer who is still developing.

0개의 댓글