함수 역시 함수의 주소 값을 저장할 수 있는 포인터 변수를 선언할 수 있다. 그렇다면 어떻게 선언해야 할까? 먼저 다음의 예시를 살펴보자.
<소스코드>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> int SimpleFunc(int num) { return num; } int main(void) { int num; scanf("%d", &num); printf("%d을 입력받았습니다.\n", SimpleFunc(num)); return 0; } | cs |
위의 SimpleFunc 함수를 보면 다음의 사실들을 알 수 있다.
함수의 반환형 : int형
함수의 매개변수 : int형 1개
즉 우리는 함수의 포인터를 선언하기 위해서 함수 포인터의 변수에는 반환형 정보와, 매개변수 선언의 정보를 모두 표시해야 한다. 따라서 함수 포인터 변수는 다음과 같다. int (*fptr) (int) 여기서 fptr은 포인터, 앞의 int는 반환형, 뒤의 int는 매개변수의 형과 그 개수를 의미한다. 이를 예시로 확인해보면 int TwoSimpleFunc(int num1, int num2) 인 경우 위의 규칙을 적용하면 함수의 포인터 변수는 다음과 같다.
int (*fptr) (int, int);
이 포인터 변수에 TwoSimpleFunc의 주소 값을 저장하는 대입연산은 다음과 같다.
fptr = TwoSimpleFunc;
또한 이 포인터 변수 fptr을 이용해서 fptr(1, 2); 의 형태로도 함수를 호출할 수 있다. -> TwoSimpleFunc(1, 2);와 같은 결과. 예시를 통해 알아보자.
<소스코드>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> void TwoAdderFunc(int num1, int num2) { int result = 0; result = num1 + num2; printf("%d 와 %d 의 합은 %d 입니다.\n", num1, num2, result); } void ShowString(const char* str) { printf("%s", str); } int main(void) { int n1, n2; scanf("%d %d", &n1, &n2); const char* str = "함수 포인터"; void (*fptr1)(int, int) = TwoAdderFunc; // TwoAdderFunc 함수 포인터 void (*fptr2) (const char*) = ShowString; // ShowString 함수 포인터 // 함수 포인터를 통한 호출 fptr1(n1, n2); fptr2(str); return 0; } | cs |
<실행결과>
매개변수의 선언으로도 함수 포인터가 올 수 있다. 먼저 이를 예시로 알아보자.
<소스코드>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include <stdio.h> int WhoIsFirst(int age1, int age2, int (*fptr) (int n1, int n2)) { // 매개변수로 함수 포인터가 있음 return fptr(age1, age2); // 함수 포인터로 함수 호출 } int OlderFirst(int age1, int age2) { // 나이가 많은 사람 먼저 하는 함수 if (age1 > age2) return age1; else if (age1 < age2) return age2; else return 0; } int YongerFirst(int age1, int age2) { // 나이가 적은 사람 먼저 하는 함수 if (age1 < age2) return age1; else if (age1 > age2) return age2; else return 0; } int main(void) { int age1 = 10, age2 = 20; int first; printf("입장방법 : OlderFirst \n"); first = WhoIsFirst(age1, age2, OlderFirst); // WhoIsFirst 함수 호출 매개변수로 OlderFirst 함수 넘김 printf("%d세와 %d세 중 %d세가 먼저 입장! \n\n", age1, age2, first); printf("입장방법 : YongerFirst\n"); first = WhoIsFirst(age1, age2, YongerFirst); // WhoIsFirst 함수 호출 매개변수로 YongerFirst 함수 넘김 printf("%d세와 %d세 중 %d세가 먼저 입장! \n\n", age1, age2, first); return 0; } | cs |
<실행결과>
void 포인터
void * ptr; 의 경우 void형 이므로 형이 정해지지 않은 즉 어떤 형태의 주소 값이든 저장할 수 있는 포인터 변수이다.
이를 다음의 예시를 통해 알아보자.
<소스코드>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <stdio.h> void Func(void) { printf("그냥 함수"); } int main(void) { void* ptr; // void형 포인터 int num = 20; ptr = # // void형 포인터에 int형 주소 값 저장 printf("%p \n", ptr); ptr = Func; // void형 포인터에 Func함수 주소 값 저장 printf("%p \n", ptr); return 0; } | cs |
<실행결과>
이렇듯 void 형 포인터의 경우 어떤 형의 주소 값이든 담을 수 있다는 장점이 있지만 연산, 변경, 참조를 할 수 없다는 단점이 존재한다.
(위 포스팅은 윤성우 님의 열혈 C를 인용하였습니다.)