JHB의 프로그래밍 삽질기

[C++] 2차원 배열의 포인터. 배열은 포인터 상수다. 본문

PROGRAMMING/Win/MFC

[C++] 2차원 배열의 포인터. 배열은 포인터 상수다.

roter 2011.03.24 18:04


배열과 포인터가 동치라는 것은 이미 알고 있다.
예를 들어서

a[3]은 *(a+3) 이 되는 것이다.

하지만 다른 점은 배열은 포인터 상수로 선언 된다는 점이다. 즉 * const 이다.
따라서
int a[3]; int b[3];
이 있을 때, a는 a[3]배열의 시작 주소를 나타내고 b 역시 b[3]배열의 시작 주소를 나타내지만
a = b; 는 할 수 없다. 왜냐면 const이기 때문에!!
해주고 싶다면 int a[3], int *b; 를 하고
b = a; 한다면 이것은 가능하겠다!!


자 이제...
2차원 배열의 포인터는 어떻게 선언할까?

그냥 대충 생각하면 꼭
int a[3][4];
int **p = a;
가 될 것 같이 생겼지만.. 되지 않는다. 왜일까?
int a[3][4];로 선언한 이차원 배열이 있을 경우

a[1][0]을 사용하였다면 이는 컴파일러에 의해서
*(*(a+1) + 0) 로 바뀌게 된다.

이제 여기 굵은 부분을 한 번 보자.
*(*(a+1) + 0)

어떤가. +1 이니까 (32bit cpu기준) 4바이트가 올라가고, +0 이니까.. 이 값은 시작 주소 a에서 4바이트 뒤로간,
a[0][1] 의 주소를 가리켜야 할 것 같지 않은가?

그렇지 않다!!

(a+1)과 같이 포인터 변수 옆에다가 +1을 해주면 올라가는 수치는 무엇에 의해 결정될까? 바로 자료형이다.

int n[5]; char s[5];
가 있을 경우
(n+2) 는 n에다가 8바이트를 더한 것이고
(s+3) 은 s에다가 3바이트를 더한 것이다.

그렇다면 다시 위쪽의 a[1][0]을 변형한 *(*(a+1) + 0) 는 몇바이트가 올라갈까?
답은 16바이트다. 어째서?

변수 a의 선언을 보면
int a[3][4]; 로 돼있다.

이걸 포인터 선언으로 변경해 보면 다음과 같다
int (*a)[4];
이것은.. a가 int에 대한 포인터가 아닌, int[4]에 대한 포인터라는 것을 의미한다!!
따라서 *(*(a+1) + 0) 이 식에서 a+1을 해주는 것은 int[4]에 대한 포인터값에 +1을 하는 것이기 때문에 16바이트가 올라간다!!
따라서 다차원 배열의 포인터를 선언할 때는 반드시 크기를 명시해 주어야 한다.
그렇기 때문에 int **p = a; 같은 것은 되지 않았던 것이다.

sizeof를 해보면 재밌는 사실이 나온다.
int a[3][4]일 경우 sizeof(a)를 하면 48이 나온다.(4*3*4)
int (*a)[4]일 경우 sizeof(a)를 하면 4가 나온다. 말그대로 걍 포인터일 뿐이다. int[4]의 포인터!!

함수 파라미터로 2차원 배열을 넘기는 경우를 생각해보자.

void func( int a[3][4] ) {}....
void func( int (*a)[4] ) {}....
void func( int a[][4] ) {}....
위의 경우가 모두 된다.
제일 아래의 경우 첫번째 []는 숫자를 비웠는데, 계산상 아무 상관이 없기 때문에 그냥 비워도 되는 것이다!!!

지금까지와 비슷한 맥락으로, 다차원 배열의 포인터는
int a[3][4][5];의 포인터로는
int (*p)[4][5]; 이렇게 해주면 된다.
저작자 표시 비영리 변경 금지
신고
5 Comments
댓글쓰기 폼