2차원 배열의 형태
우리가 2차원 배열과 포인터에 대한 상관관계를 파악하고 조작하기 위해서는 2차원 배열이 메모리에 어떻게 저장되는지 알아야 한다.
다음과 같은 배열이 존재한다고 가정해보자.
int arr[3][2] = {
{11, 22},
{33, 44},
{55, 66},
};
그럼 메모리에 다음과 같이 저장될 것이라는 그림을 많이 봐 왔다
하지만 정확이 말 한다면, 이 그림은 조금 이상하다.
2차원 배열이라 우리가 보기 쉽게 구분해놓은 것일 뿐이지 저렇게 2차원으로 저장되지 않는다.
메모리는 연속적인 특성 덕분에 1차원으로 보는 것이 더 올바르다
그럼 더 올바른 구조를 그려보자면 다음과 같다.
이렇게 먼저 머리에 메모리 구조를 이해하고 있어야 포인터와 2차원 배열의 상관관계에 대해서 알 수 있다.
2차원 배열은 연속적인 메모리에 할당된다고 해서 1차원 배열처럼 일열로 보여줬지만 아래에 나올 그림은 가독성을 위해서 2차원 구조로 메모리에 존재한다고 가정해보자.
2차원 배열의 포인터
포인터 변수에 2차원 배열을 할당하기 위해서는 int (*pointer)[행의 수];
형태로 정의해야 한다.
바로 코드로 확인해보자
#include <stdio.h>
int main() {
int arr[3][2] = {
{11, 22},
{33, 44},
{55, 66},
};
int (*pointer)[2]; // 행을 2로 하는 2차원 배열 포인터 하나 생성
pointer = arr;
return 0;
}
여기서 괄호의 역할이 많이 중요하다.
만약 괄호를 생략하고 *pointer[2]
라고 하면 이는 포인터 배열을 생성하겠다는 뜻으로, int 형 포인터 2개가 연속적으로 저장되는 배열이 생성되게 된다.
1차원 배열로 생각하기
2차원 배열을 포인터로 다루기 위해서 우선 1차원 배열이 연속적으로 존재한다고 가정해보자
그럼 위의 코드에서는 배열 size 가 2인 배열 3개가 연속적으로 존재한다고 이해할 수 있다.
그럼 2차원 배열에서도 역시 1차원 배열의 개념을 함께 이용할 수 있다.
2차원 배열 포인터로 배열 주소 접근하기
결국 포인터를 이용해서 이들 각각의 주소로 접근한다면 다음과 같은 방식으로 접근할 수 있다
arr[0]
:*pointer
- pointer 변수가 가리키는 주소
arr[1]
:*(pointer + 1)
- pointer 변수가 가리키는 주소 + 4 byte
arr[2]
:*(pointer + 2)
- pointer 변수가 가리키는 주소 + 8 byte
그럼 이 특성을 이용해서 배열의 모든 원소의 주소에 접근할 수 있다.
이렇게 포인터와 정수를 이용해서 byte 를 옮겨 모든 원소에 접근할 수 있게 되는데, 이게 조금 헷갈릴 수 있다.
arr[1][1] == *(pointer + 1) + 1
을 좀 더 분석해보자
이는 pointer 가 가리키는 주소 (arr)에 4 byte 를 더하고 +1 로 인해 또 4byte 를 더한 주소값이 되는 것이다.
이를 반증문을 통해서 증명해보자면,
#include <assert.h>
int main() {
int arr[3][2] = {
{11, 22},
{33, 44},
{55, 66},
};
int (*pointer)[2] = arr;
assert(&arr[0][0] == *pointer);
assert(&arr[0][1] == *pointer + 1);
assert(&arr[1][0] == *(pointer + 1));
assert(&arr[1][1] == *(pointer + 1) + 1);
assert(&arr[2][0] == *(pointer + 2));
assert(&arr[2][1] == *(pointer + 2) + 1);
return 0;
}
2차원 배열 포인터로 배열 원소의 값 가져오기
이제 모든 원소의 주소에 접근할 수 있게 되었다! 그럼 참조 연산을 이용해서 실제 값을 취할 수 있게 된다.
#include <stdio.h>
int main() {
int arr[3][2] = {
{11, 22},
{33, 44},
{55, 66},
};
int (*pointer)[2] = arr;
printf("%d\n", **pointer);
printf("%d\n", *(*pointer + 1));
printf("%d\n", *(*(pointer + 1) + 0)); // + 0 은 생략 가능
printf("%d\n", *(*(pointer + 1) + 1));
printf("%d\n", *(*(pointer + 2) + 0)); // + 0 은 생략 가능
printf("%d\n", *(*(pointer + 2) + 1));
return 0;
}
'🎛 Others... > - C' 카테고리의 다른 글
[C 언어] struct, 구조체의 기본과 사용 방법 (0) | 2021.07.04 |
---|---|
[C 언어] malloc 과 free 로 메모리 관리하기 (0) | 2021.07.04 |
[C 언어] 포인터로 1차원 배열 다루기 (주소 접근 및 원소 값 접근) (0) | 2021.07.03 |
[C 언어] 포인터와 포인터를 위한 여러 연산자 (0) | 2021.07.02 |
[C 언어] 1차원 배열의 기초 (0) | 2021.06.23 |
댓글2