目次
1. 소개
C 언어의 포인터와 함수 포인터는 효율적이고 유연한 프로그래밍을 위해 필수적인 요소입니다. 포인터는 메모리 주소를 직접 조작하는 수단을 제공하고, 함수 포인터는 함수의 주소를 저장하여 간접적인 함수 호출을 가능하게 합니다. 본 기사에서는 포인터와 함수 포인터의 기본부터 응용까지를 설명하고, 보안 및 실용 예제에 대해서도 다룹니다.2. 포인터의 기본
2.1 포인터란 무엇인가
포인터는 변수의 메모리 상 주소를 저장하는 특수한 변수입니다. 포인터를 사용하면 변수의 값에 간접적으로 접근할 수 있어 프로그램의 유연성이 향상됩니다. 예를 들어, 함수 간에 데이터를 공유하거나 큰 데이터 구조를 효율적으로 조작할 때 사용됩니다.2.2 포인터의 선언과 사용 방법
포인터 선언은 데이터 타입 앞에 별표(*
)를 붙입니다. 아래는 그 예시입니다.int x = 5;
int* p = &x; // x의 주소를 포인터 p에 저장
&
연산자는 변수의 주소를 얻고, *
연산자는 포인터가 가리키는 값을 참조합니다.printf("%d", *p); // 출력: 5
p
는 x
의 주소를 가리키며, *p
를 사용하면 x
의 값을 얻을 수 있습니다.3. 함수 포인터의 기본
3.1 함수 포인터의 정의와 선언
함수 포인터는 함수의 주소를 저장하기 위한 포인터이며, 동적으로 다른 함수를 호출할 때 유용합니다. 함수 포인터 선언에는 함수의 반환값 타입과 인자 정보가 포함됩니다。int (*funcPtr)(int);
이는 int
를 인자로 받고 int
를 반환하는 함수를 가리키는 포인터입니다。3.2 함수 포인터의 활용 방법
함수 포인터를 사용하여 함수를 호출하려면, 함수의 주소를 포인터에 할당하고 그 포인터를 호출합니다。int square(int x) {
return x * x;
}
int main() {
int (*funcPtr)(int) = square;
printf("%d", funcPtr(5)); // 출력: 25
return 0;
}
이 예에서는 funcPtr
에 square
함수의 주소를 할당하고, funcPtr(5)
로 square
함수를 호출하고 있습니다。4. 함수 포인터 활용 예
4.1 함수 포인터에 의한 함수 실행
함수 포인터는 함수 배열을 만들 때 특히 유용합니다. 실행 시 다른 함수를 선택함으로써 프로그램의 유연성을 높일 수 있습니다.void hello() {
printf("안녕");
}
void goodbye() {
printf("안녕히 가세요");
}
int main() {
void (*funcs[2])() = {hello, goodbye};
funcs[0](); // 출력: Hello
funcs[1](); // 출력: Goodbye
return 0;
}
이 예에서는 funcs
배열에 다른 함수를 저장하고 상황에 따라 실행할 수 있습니다.4.2 콜백 함수
콜백 함수는 특정 이벤트가 발생했을 때 호출할 함수를 지정하는 방법입니다. 이를 통해 프로그램의 일부 동작을 동적으로 변경할 수 있습니다.void executeCallback(void (*callback)()) {
callback();
}
void onEvent() {
printf("이벤트 발생!");
}
int main() {
executeCallback(onEvent); // 출력: Event occurred!
return 0;
}
executeCallback
함수에 동적으로 다른 함수를 전달할 수 있습니다.
5. 포인터와 구조체
5.1 구조체 포인터 사용법
구조체 포인터를 사용하면, 큰 데이터 구조를 효율적으로 조작할 수 있습니다. 구조체 포인터의 멤버에 접근할 때는 「->
」 연산자를 사용합니다。typedef struct {
int x;
int y;
} Point;
int main() {
Point p = {10, 20};
Point *pPtr = &p;
printf("%d, %d", pPtr-&;x, pPtr->y); // 출력: 10, 20
return 0;
}
pPtr->x
는 p
구조체의 멤버 x
에 접근하고 있습니다。5.2 구조체 포인터를 함수에 전달하기
구조체 포인터를 함수에 전달하면, 함수 내부에서 구조체의 멤버를 조작할 수 있습니다。void updatePoint(Point *p) {
p->x += 10;
p->y += 20;
}
int main() {
Point p = {10, 20};
updatePoint(&p);
printf("%d, %d", p.x, p.y); // 출력: 20, 40
return 0;
}
이 예에서는 updatePoint
함수에서 Point
구조체의 멤버를 직접 변경하고 있습니다。6. 함수 포인터의 장점과 주의점
6.1 장점
함수 포인터를 사용하면 프로그램의 확장성과 유연성이 향상됩니다. 예를 들어, 플러그인 시스템 구현이나 이벤트 기반 프로그래밍에서 동적으로 함수를 전환할 수 있습니다. 또한, 함수 포인터 배열을 사용하면 복잡한switch
문을 간단한 루프로 대체할 수 있습니다.6.2 주의점
함수 포인터를 사용할 때는 다음 사항에 주의해야 합니다.- 형식 일치: 함수 포인터의 형식이 정확하지 않을 경우, 예상치 못한 동작이 발생할 가능성이 있습니다. 함수의 프로토타입이 일치하는지 확인하십시오.
- 보안상의 위험: 잘못된 함수 포인터를 호출하면 세그멘테이션 폴트와 같은 오류가 발생할 수 있습니다. 포인터 초기화를 잊지 말고 수행하며, 필요에 따라
NULL
체크를 하세요. - 역참조 위험: 포인터가 유효한 주소를 가리키는지 확인하지 않고 역참조하면 프로그램이 크래시될 가능성이 있습니다.