[C/C++] C언어 포인터 완전 정복
C언어를 공부하면서 가장 많이 막히는 부분은 단연 포인터이다.
특히 배열, 구조체, 이중 포인터가 함께 등장하면 코드 해석이 어려워진다.
1. 포인터란?
포인터는 변수의 주소를 저장하는 변수
int a = 10;
int* p = &a
의미
- a: 값 10을 저장
- &a: a의 주소
- p = a의 주소를 저장하는 포인터
2. 포인터 기본 연산
*p
포인터가 가리키는 주소의 값을 의미한다
즉
*p == a
3. 배열과 포인터의 관계
C언어에서 배열 이름은 첫 번째 요소의 주소
int arr[3] = {1,2,3};
int* p = arr;
위 코드의 의미는 다음과 같다
p == &arr[0]
※ 배열처럼 사용하는 포인터
p[1] == arr[1]
내부적으로는 이렇게 동작한다
*(p + 1)
4. 구조체와 포인터
구조체도 배열과 동일하게 포인터로 접근할 수 있다.
(1) 단일 구조체 + 포인터
struct dat {
int x;
int y;
};
struct dat d = {10, 20};
struct dat* p = &d;
의미
- d: 구조체 변수
- p: d의 주소를 저장하는 포인터
※ 구조체 포인터 접근 방법
구조체 포인터는 다음과 같은 두 가지 방식으로 접근할 수 있다
(*p).x // 방법 1
p->x // 방법 2 (더 많이 사용)
(2) 구조체 배열 + 포인터
struct dat arr[3] = { {1,2}, {3,4}, {5,6} };
struct dat* p = arr;
위 코드의 의미는 다음과 같다
p == &arr[0]
또한 배열처럼 접근도 가능한데
p[1].x == arr[1].x
위 코드가 *(p + 1) 이 코드랑 같은 의미로 쓰인다
※ 정리 ※
정리하자면 아래와 같다
- p -> 첫 번째 구조체를 가리킴
- p[i] -> i 번째 구조체
- p[i].x -> 해당 구조체의 멤버 접근
5. 이중 포인터
이중 포인터는 포인터의 주소를 저장하는 변수이다
int* p;
int** pp = &p;
변수 p가 어떤 값을 가리키고 있을 때 pp는 변수 p의 주소를 가리킨다
*pp == p
※이중 포인터에서도 배열처럼 접근이 가능한데 다음 코드를 보면
(*pp)[1]
*pp는 p를 가리키고 있으니
p[1] 즉 배열의 두 번째 요소를 가리키고 있는 것과 같다
예제코드
이제 위 개념을 바탕으로 다음 코드를 해석해보자
#include <stdio.h>
struct dat {
int x;
int y;
};
int main() {
struct dat a[] = { {1,2},{3,4},{5,6} };
struct dat* ptr = a;
struct dat** pptr = &ptr;
(*pptr)[1] = (*pptr)[2];
printf("%d 그리고 %d", a[1].x, a[1].y);
return 0;
}
1. 구조체 정의
struct dat {
int x;
int y;
};
x,y를 가지는 구조체
2. 배열 초기화
struct dat a[] = { {1,2},{3,4},{5,6} };
배열 상태
| 인덱스 | 값 |
| a[0] | {1,2} |
| a[1] | {3,4} |
| a[2] | {5,6} |
3. 포인터 구조
struct dat* ptr = a;
- ptr -> 배열의 첫번째 요소를 가리킴
즉 , ptr = &a[0]을 의미한다
struct dat** pptr = &ptr;
- pptr -> ptr의 주소
즉, 이중 포인터이다
4. 코드 해석
(*pptr)[1] = (*pptr)[2];
*pptr == ptr 이다
그럼 ptr[1] == a[1] 이고
위 코드는
a[1] = a[2]; 와 같다
a[0] = {1,2}
a[1] = {5,6}
a[2] = {5,6}
즉 위 코드 실행 후에는 이렇게 변화된다
5. 출력
printf("%d 그리고 %d", a[1].x, a[1].y);
답
5 그리고 6