C 언어
C 언어 포인터의 핵심 개념을 메모리 주소부터 실전 예제, 흔한 함정까지 다룹니다. 실전 코드로 이해를 깊게 하고 싶은 개발자를 위해 작성되었습니다.
포인터는 효율적인 C 프로그래밍의 초석입니다. 포인터를 배우기 전에 C에서 메모리 주소가 어떻게 동작하는지 복습해 보겠습니다.
변수 var가 있다면, 표현식 &var는 var가 저장된 메모리 주소를 반환합니다.
주소 조작은 scanf()에서 자주 등장합니다:
scanf("%d", &var);
이는 사용자 입력을 var의 메모리 위치에 직접 저장합니다. 간단한 데모:
#include <stdio.h>
int main() {
int var = 5;
printf("var: %d\n", var);
printf("address of var: %p", &var);
return 0;
}
출력
var: 5 address of var: 0x7fffc1a2b1c8
참고: 주소는 실행할 때마다, 시스템마다 다릅니다.
포인터는 일반적인 값 대신 메모리 주소를 저장하는 변수입니다. 주소를 저장함으로써 포인터는 데이터에 간접적으로 접근할 수 있게 하여, 동적 메모리 관리, 효율적인 자료구조, 저수준 시스템 제어를 가능하게 합니다.
일반적인 선언 문법:
int *p;
다음 변형도 흔히 쓰입니다:
int *p1; int *p2;
별표 주변의 공백은 선언에 영향을 주지 않습니다. 하지만 쉼표로 여러 변수를 선언할 때는 주의해야 합니다:
int *p1, p2; /* p1은 포인터, p2는 int */
예제:
int *pc, c;
c = 5;
pc = &c;
여기서 c는 값 5를 받고, pc는 c의 주소를 저장합니다.
포인터가 가리키는 주소에 저장된 값에 접근하려면 역참조 연산자 *를 사용합니다:
int *pc, c;
c = 5;
pc = &c;
printf("%d", *pc); /* 5 출력 */
pc는 포인터이고, *pc는 그 포인터가 가리키는 값을 가져옵니다. *pc = &c;처럼 역참조된 포인터에 주소를 할당하려는 시도는 잘못된 것입니다.
* 연산자를 역참조 연산자라고 부릅니다.
포인터를 통해 원본 데이터를 변경할 수 있습니다:
int *pc, c;
c = 5;
pc = &c;
*pc = 1; /* c가 1이 됨 */
printf("%d", c); /* 1 출력 */
재할당을 통해 여러 변수가 같은 포인터를 공유할 수도 있습니다:
int *pc, c, d;
c = 5;
d = -15;
pc = &c;
printf("%d", *pc); /* 5 */
pc = &d;
printf("%d", *pc); /* -15 */
다음 전체 프로그램을 실행하여 포인터 값은 변하지 않지만 참조하는 데이터는 변경될 수 있음을 확인하세요:
#include <stdio.h>
int main() {
int *pc, c;
c = 22;
printf("Address of c: %p\n", &c);
printf("Value of c: %d\n\n", c);
pc = &c;
printf("Address of pointer pc: %p\n", pc);
printf("Content of pointer pc: %d\n\n", *pc);
c = 11;
printf("Address of pointer pc: %p\n", pc);
printf("Content of pointer pc: %d\n\n", *pc);
*pc = 2;
printf("Address of c: %p\n", &c);
printf("Value of c: %d\n\n", c);
return 0;
}
출력
Address of c: 0x7fffc1a2b1c8 Value of c: 22 Address of pointer pc: 0x7fffc1a2b1c8 Content of pointer pc: 22 Address of pointer pc: 0x7fffc1a2b1c8 Content of pointer pc: 11 Address of c: 0x7fffc1a2b1c8 Value of c: 2
int *pc, c; – 포인터 pc와 int c를 선언.c = 22; – c의 메모리에 22 저장.pc = &c; – pc가 c를 가리키게 함.c = 11; – 직접 접근으로 값 업데이트.*pc = 2; – 포인터를 통해 값 변경.대표적인 오류는 포인터와 값을 혼동하는 것입니다:
int c, *pc;
// 잘못된 예 – 포인터에 값을 할당
pc = c; // 에러
// 잘못된 예 – 역참조된 포인터에 주소 할당 시도
*pc = &c; // 에러
// 올바른 예 – 포인터에 주소 할당
pc = &c; // OK
// 올바른 예 – 포인터가 가리키는 위치에 값 할당
*pc = c; // OK
초보자에게 int *p = &c; 문법은 헷갈릴 수 있습니다. 이는 다음과 동일합니다:
int *p;
p = &c;
int* p = &c;로 쓰면 모호함이 줄어듭니다.
이제 포인터를 이해했으니, 다음 튜토리얼에서는 포인터와 배열의 관계를 탐구해 보겠습니다.
C 언어
함수 포인터는 C에서 강력한 기능을 열어줍니다. 값 복사 대신 메모리 주소를 통해 함수가 데이터를 직접 조작하게 하여, 제자리 스와핑, 동적 콜백, 고차 함수 같은 패턴을 가능하게 합니다. 함수 포인터 예제 배열 매개변수를 가진 함수 배열을 반환하는 함수 함수 포인터 함수 포인터 배열 void 포인터를 사용하는 함수 인수로 전달되는 함수 포인터 함수 포인터 예제 고전적인 스왑 루틴은 함수가 두 변수의 주소로 연산하여 값을 교환하는 방법을 보여줍니다. void swap (int *a, int *b); int main() {
프로그래밍 언어에는 코딩을 훨씬 쉽게 만드는 특정 개념이 있습니다. 예를 들어 C 프로그래밍 언어에서 void 포인터는 최종 사용자의 입력으로부터 특정 데이터 유형을 결정합니다. 이로 인해 C언어의 void 포인터에 대해 논의하게 되었습니다. 다른 포인터와 마찬가지로 void 포인터도 유연성을 위한 관련 기능을 가지고 있습니다. 하지만 코딩 시 시간을 절약하고 싶다면 void 포인터가 최적의 선택입니다. 이 포인터를 사용하면 서로 다른 객체 유형을 동시에 저장하고 검색할 수 있습니다. 이어서 C언어에서 void 포인터를 활용한 코