이번 포스팅에서는 C언어에서 2차원 배열과 메모리 주소와의 관계에 대해 알아보고, &, *, + 같은 포인터 연산자가 어떻게 동작하는지 예제를 통해 자세히 뜯어보려고 한다.
포인터를 잘 이해하면 임베디드의 핵심인 메모리를 잘 다루는 데 도움이 된다고 하니 잘 익혀두는 것이 좋겠다.
우선 다음의 2행 3열의 배열의 각 요소들이 메모리에 어떤 순서로 저장되는지 살펴보자.
int main(void)
{
int a[2][3] = {{0, 1, 2}, {3, 4, 5}};
}
먼저, int a[2][3] = {{0, 1, 2}, {3, 4, 5}}; 배열의 메모리 구조를 이해하는 것이 중요하다.
C 언어에서 2차원 배열은 행(row) 우선으로 메모리에 연속적으로 저장된다.
int의 크기가 4바이트이므로, 각 요소의 주소는 4바이트씩 증가한다.

그러면 위 2차원 배열의 각각의 주소값은 다음과 같이 된다.
- a[0][0] (값 0): 0x1000
- a[0][1] (값 1): 0x1004
- a[0][2] (값 2): 0x1008
- a[1][0] (값 3): 0x100C
- a[1][1] (값 4): 0x1010
- a[1][2] (값 5): 0x1014
배열의 포인터 연산
그러면 이제 위 배열을 가지고 다음 6가지의 포인터 연산을 수행해보자.
1) &a = ?
&a는 전체 배열 a의 시작 주소를 의미한다.
a는 int (*)[2][3] 타입의 포인터로 배열 전체를 가리키며, 그 값은 배열의 첫 번째 요소인 a[0][0]의 주소와 동일한 0x1000이다.
2) &a+1 = ?
&a + 1는 전체 배열(&a)의 시작 주소에 1을 더하는 연산이다.
포인터 연산에서 1을 더한다는 것은 가리키는 대상의 크기만큼 주소를 이동시키는 것을 의미한다.
&a가 가리키는 대상은 전체 배열이므로, 배열 a의 전체 크기(2행 × 3열 × 4바이트 = 24바이트)만큼 주소가 이동하게 된다.
0x1000 + 24 = 0x1018
3) a+1 = ?
a + 1: 배열의 이름 a는 그 자체로 첫 번째 행을 가리키는 포인터로 취급된다(int (*)[3]).
이 포인터에 1을 더하면 한 행의 크기만큼 주소가 이동한다.
한 행은 3개의 int 요소로 이루어져 있으므로, 3 × 4바이트 = 12바이트만큼 이동하게 된다.
0x1000 + 12 = 0x100C
4) *a = ?
*a: *는 포인터가 가리키는 대상을 가져오는 연산이다.
배열 이름 a는 첫 번째 행인 a[0]를 가리키는 포인터이다.
따라서 *a는 a가 가리키는 대상, 즉 a[0]를 의미한다.
a[0]는 1차원 배열(int [3])이지만, *a의 결과로 사용될 때, a[0]는 다시 자신의 첫 번째 요소(a[0][0])를 가리키는 포인터(int*)로 변환된다.
따라서 a[0][0]의 주소는 배열의 시작 주소와 같은 0x1000이므로, a[0]가 변환된 포인터의 값도 0x1000이 된다.
5) *a+1 = ?
*a + 1: *a는 a[0][0]의 주소인 0x1000이다. 이 주소는 int 타입의 포인터(int*)이므로, 1을 더하면 int 하나의 크기인 4바이트만큼 주소가 이동한다.
0x1000 + 4 = 0x1004
6) **a = ?
2차원 배열은 '배열의 배열'이라는 구조를 가지므로, 이중 포인터 연산의 개념이 적용된다.
**a는 이중 역참조 연산으로 *(*a)와 같다.
- a는 배열의 첫 번째 행 a[0]을 가리키는 포인터.
- *a는 첫 번째 행의 첫 번째 요소 a[0][0]의 주소(0x1000)를 가리킨다.
- 여기에 다시 *를 적용하면 해당 주소에 저장된 값을 가져온다.
- 0x1000 주소에는 a[0][0]의 값인 0이 저장되어 있다.
- 따라서 최종 값은 0이다.
이처럼 C 언어의 포인터 연산은 가리키는 대상의 타입에 따라 이동하는 단위가 달라진다는 점을 기억하자.
배열의 이름이 단순히 주소만 가진 것이 아니라, 타입 정보까지 포함된 포인터라는 점을 이해하면 그리 복잡한 연산은 아닐 것이다.
'KNOU CS' 카테고리의 다른 글
| [자료구조] 스택(stack)을 이용하여 중위 표기식을 후위 표기식으로 변환해보자 (0) | 2025.09.12 |
|---|---|
| [DBS] 트랜잭션 - Part3. 타임스탬프 기반 트랜잭션 동기화 규약 (0) | 2025.06.10 |
| [운영체제] 가상메모리와 주소 변환 - Part4. 페이징/세그먼테이션 혼용기법 (0) | 2025.06.10 |
| [운영체제] 가상메모리와 주소 변환 - Part3. 연관/직접사상의 동적 주소변환 과정 (0) | 2025.06.10 |
| [운영체제] 가상메모리와 주소 변환 - Part2. 페이징 기법과 데이터 참조 과정 (0) | 2025.06.10 |