보통 C언어를 사용하면서 포인터는 변수를 가리킬 때 사용하고는 한다.
그러나 포인터는 함수의 시작 주소도 나타낼 수 있다.
이를 우리는 '함수 포인터'라고 한다.
함수 포인터란?
함수 포인터에는, 3가지 부분으로 나뉜다.
type (*function_name) (arguments);
함수의 자료형
함수의 이름을 대신하여 호출할 수 있는 함수 포인터
매개변수
로 이루어진다.
#include <stdio.h>
int sum(int, int);
int main() {
int (*fp)(int, int);
fp = sum;
printf("%d\n", fp(10, 20)); //1
printf("%d\n", sum(10,20)); //2
printf("%d\n", (*sum)(10,20)); //3
return 0;
}
int sum(int a, int b) {
return (a + b);
}
위와 같은 예시로, fp라는 함수 포인터를 설정하여, sum이라는 함수와 동일한 역할을 수행할 수 있다. (//1)
당연하지만, 함수 포인터를 이용하지 않고도 함수 호출이 가능하다. (//2)
마지막은 함수 명을 간접 참조 연산자인 *을 이용해서 사용해본 예시인데, 함수명 또한 주소로 나타낼 수 있음을 증명한 바이다. (그래서 함수 포인터도 가능한 것) (//3)
그렇다면, 왜 2번처럼 함수를 나타내면 되는데, 굳이 1번처럼 함수 포인터를 사용하는 것일까?
함수 포인터를 사용하는 이유
'그냥 함수를 사용할 때 그대로 함수를 사용하면 되지, 왜 굳이 함수 포인터를 사용해야 하는가?' 라는 질문을 할 수도 있는데, 쉽게 설명하면 코드를 줄이려고 쓰는 것 같다.
Callback 함수를 이용할 때 요긴하게 사용된다.
callback함수는 다른 인수의 인자로서 사용될 때, 특정 상황에서 호출되어지는 함수를 의미한다.
예를 들면 (대부분의 책에서 사용되는 예시이다)
#include <stdio.h>
void func(void(*fp)());
void hi();
void hey();
int main() {
int num;
scanf("%d", &num);
switch (num) {
case 1:
func(hi);
break;
case 2:
func(hey);
break;
}
return 0;
}
void func(void (*fp)()){
fp();
}
void hi() {
printf("hi");
}
void hey() {
printf("hey");
}
사용자가 1을 입력하면, hi라는 함수를 실행하고,
사용자가 2를 입력하면, hey라는 함수를 실행한다.
func이라는 함수로 '인사'라는 기능을 사용하는 함수라고 정의할 수 있겠다.
hi나 hello 대신에 'ni hao'라는 기능을 추가하고 싶을 때,
ni hao라는 함수를 새로 만들어서
func(nihao)
만 실행하게 된다면 또 사용이 가능하다.
그만큼 함수 포인터를 사용하게 된다면,
용이하게 버전관리를 할 수 있다.