程式在執行時,函式在記憶體中也佔有一個空間,將函式名稱作為指定來源時,函式名稱會自動轉為指標,型態由傳回值型態與參數列決定,若要將之指定給另一函式指標,型態的宣告方式如下:
傳回值型態 (*名稱)(參數列);
函式指標代表著一個函式,相同型態的函式可以指定給具有相同型態的指標,例如:
#include <stdio.h>
int foo(int);
int main() {
int (*fp)(int) = foo;
foo(10); // 顯示 10
fp(20); // 顯示 20
return 0;
}
int foo(int n) {
printf("n = %d\n", n);
return 0;
}
foo
指定給 fp
,等效於 &foo
指定給 fp
,在指定之後,fp
儲存了 foo
的位址,在呼叫時,fp(20)
等效於 (*fp)(20)
。
函式指標可以用來傳遞函式,例如,你想撰寫用於陣列的 sort 函式,希望大小順序可以由呼叫者指定,這就可以傳遞函式來指定,例如:
#include <stdio.h>
#include <stdbool.h>
void sort(int*, int, bool (*compare)(int, int));
bool ascending(int, int);
bool descending(int, int);
int main() {
int number[] = {3, 5, 1, 6, 9};
sort(number, 5, ascending);
// 顯示 1 3 5 6 9
for(int i = 0; i < 5; i++) {
printf("%d ", number[i]);
}
putchar('\n');
sort(number, 5, descending);
// 顯示 9 6 5 3 1
for(int i = 0; i < 5; i++) {
printf("%d ", number[i]);
}
putchar('\n');
return 0;
}
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
void sort(int* arr, int length, bool (*compare)(int, int)) {
for(int flag = 1, i = 0; i < length - 1 && flag == 1; i++) {
flag = 0;
for(int j = 0; j < length - i - 1; j++) {
if(compare(arr[j + 1], arr[j])) {
swap(&arr[j + 1], &arr[j]);
flag = 1;
}
}
}
}
bool ascending(int a, int b) {
return a < b;
}
bool descending(int a, int b) {
return a > b;
}
在這個例子中,sort
上的函式指標宣告有些難以閱讀,可以使用 typedef
,定義一個比較容易閱讀的名稱,例如:
#include <stdio.h>
#include <stdbool.h>
typedef bool (*CMP)(int, int);
void sort(int*, int, CMP compare);
...略
void sort(int* arr, int length, CMP compare) {
for(int flag = 1, i = 0; i < length - 1 && flag == 1; i++) {
flag = 0;
for(int j = 0; j < length - i - 1; j++) {
if(compare(arr[j + 1], arr[j])) {
swap(&arr[j + 1], &arr[j]);
flag = 1;
}
}
}
}
...略
也可以宣告函式指標陣列,例如:
bool (*compare[10])(int, int);
上面這個宣告產生具有 10 個元素的陣列,可以儲存 10 個 bool (*)(int, int)
函式型態的位址,不過這樣的宣告實在難以閱讀,可以使用 typedef
來改進:
typedef bool (*CMP)(int, int);
CMP compare[10];