Quick Syntax
포인터는 객체의 주소를 저장합니다. &로 주소를 얻고 *로 유효한 대상에 접근합니다. 호출자 값을 바꿔야 할 때만 주소를 전달합니다.
int value = 10;
int *ptr = &value;
if (ptr != NULL) {
printf("%d\n", *ptr); /* 유효한 객체를 가리킬 때만 역참조 */
*ptr = 20;
}포인터를 선언했다고 유효한 객체가 생기는 것은 아닙니다. NULL, 해제된 주소, 수명이 끝난 지역 객체의 주소, 마지막 다음 위치는 모두 역참조할 수 없습니다.
문법
포인터 기본 문법은 보통 아래 네 가지를 같이 봐야 합니다.
T *p: 포인터 선언&x: 변수의 주소 얻기*p: 그 주소의 값을 읽거나 쓰기NULL: 아직 유효한 대상을 가리키지 않는 상태
int value = 10;
int *ptr = &value;
printf("%d\n", value);
printf("%d\n", *ptr);포인터가 필요한 가장 흔한 이유는 원본 공유와 원본 수정입니다.
void double_in_place(int *p) {
*p *= 2;
}
int score = 95;
double_in_place(&score);
printf("%d\n", score);값 복사로 넘기면 함수 안 변경은 밖으로 안 나가지만, 주소를 넘기면 같은 원본을 같이 보게 됩니다.
void change_value(int n) {
n = 0;
}
int count = 7;
change_value(count);
printf("%d\n", count); /* 7 */이 예시는 "값 복사"라서 호출자 원본이 안 바뀝니다. 포인터를 넘길 때와 가장 크게 갈리는 지점입니다.
기본 개념
포인터는 문법보다 역참조 시점의 유효성이 더 중요합니다.
int *ptr = NULL;
if (ptr != NULL) {
*ptr = 42;
}NULL은 "빈 포인터"에 가깝고, 아직 유효한 대상을 가리키지 않는 상태를 뜻합니다. C 포인터 버그의 대부분은 유효하지 않은 주소를 믿고 역참조하는 습관에서 시작합니다.
p != NULL은 null 여부만 확인합니다. 해제된 주소, 수명이 끝난 지역 변수 주소, 배열의 마지막 다음 위치, 초기화되지 않은 포인터가 유효한 객체를 가리키는지는 확인해 주지 않습니다. 역참조에는 null 검사 외에 수명·범위·정렬 계약이 필요합니다.
void reset_value(int *p) {
if (p != NULL) {
*p = 0;
}
}
int count = 7;
reset_value(&count);빠른 점검
T *p는 포인터 선언입니다.&x는 주소를 얻고,*p는 그 주소의 값을 읽거나 씁니다.- 값을 복사해도 되면 일반 인자를 쓰고, 호출자 원본을 바꿔야 하면 포인터를 넘깁니다.
- 아직 대상을 못 정한 포인터는
NULL로 시작하는 편이 안전합니다. - 포인터는 선언보다 역참조 시점의 유효성이 더 중요합니다.
주의할 점
초기화하지 않은 포인터나 이미 사라진 대상을 가리키는 포인터를 역참조하면, 크래시보다 먼저 데이터 손상이 일어날 수 있습니다.
int *p;
*p = 42;
int *dangerous(void) {
int local = 10;
return &local;
}- 초기화하지 않은 포인터는 쓰면 안 됩니다.
- 지역 변수 주소를 반환하면 함수가 끝난 뒤 무효한 주소를 넘기게 됩니다.
arr + n처럼 마지막 다음 위치는 비교에는 쓸 수 있어도 역참조하면 안 됩니다.- 유효한 대상 주소 또는
NULL만 포인터에 넣는 습관이 중요합니다.
참고 링크
2 sources