程式在執行時,函式本身在記憶體中也佔有一個空間,而函式名稱本身也就是指向該空間位址的參考名稱,當呼叫函式名稱時,程式就會去執行該函式名稱所指向的
記憶體空間中之指令。
您可以宣告函式指標,並讓它與某個函式指向相同的空間,函式指標的宣告方式如下所示:
傳
回值型態
(*指標名稱)(傳遞參數);
一個函式型態由傳回值型態與參數列決定,不包括函式名稱,一個函式指標可指向具有相同型態的函式,也就是具有相同傳回值型態和參數列的函式。
下面這個程式是個簡單的示範,它以函式指標ptr來取得函式foo()的位址,使用它來呼叫函式,將與使用foo()來呼叫函式具有相同的作用,程式以整
數方式顯示兩個的記憶體空間是相同的:
#include <stdio.h>
int foo(void);
int main(void) { int (*ptr)() = 0;
ptr = foo;
foo(); ptr();
printf("address of foo:%X\n", (int) foo); printf("address of foo:%X\n", (int) ptr); return 0; }
int foo(void) { puts("function point");
return 0; }
執行結果:
function point
function point
address of foo:40136C
address of foo:40136C
|
如果函式帶有參數,則函式指標本身的宣告也必須指定相同的參數型態與個數,下面這個程式作為示範:
#include <stdio.h>
int foo1(int, int); char foo2(int, char);
int main(void) { int (*ptr1)(int, int) = 0; char (*ptr2)(int, char) = 0;
ptr1 = foo1; // get address of foo(int, int) ptr2 = foo2; // get address of foo(int, char)
ptr1(1, 2); ptr2(3, 'c');
printf("address of foo1(int, int): %X\n", (int) ptr1); printf("address of foo2(int, char): %X\n", (int) ptr2); return 0; }
int foo1(int n1, int n2) { printf("foo1(int, int): %d\t%d\n", n1, n2); return 0; }
char foo2(int n, char c) { printf("foo2(int, char): %d\t%c\n", n, c);
return c; }
執行結果:
foo1(int, int): 1 2
foo2(int, char): 3 c
address of foo1(int, int): 401397
address of foo2(int, char): 4013BE
|
由於在宣告函式指標時已指定了參數列的資料型態與個數,所以雖然在指定ptr1與ptr2時都使用foo函式名稱,但程式仍可以自動判別出我們是要指定哪
個過載函式的位址。
來看看一個應用的例子,假設您要撰寫一個排序sort()函式,您希望排序時可以由大至小,也可以由小至大,比較簡單的作法是在sort()上加上一個額
外的參數,可以傳入常數或列舉,例如如果指定1的話就由大至小,指定0的話就由小至大,這需要在函式中加上額外的判斷,為了簡化sort()的撰寫,可以
傳入一個函式位址,函式中就無需額外的判斷,例如:
void swap(int*, int*); int larger(int a, int b); int smaller(int a, int b); void sort(int*, int, int (*compare)(int, int));
#include "sort.h"
void swap(int *a, int *b) { int t = *a; *a = *b; *b = t; }
int larger(int a, int b) { return a > b; }
int smaller(int a, int b) { return a < b; }
void sort(int* arr, int length, int (*compare)(int, int)) { int flag = 1; int i, j; for(i = 0; i < length-1 && flag == 1; i++) { flag = 0; for(j = 0; j < length-i-1; j++) { if(compare(arr[j+1], arr[j])) { swap(arr + j + 1, arr + j); flag = 1; } } } }
#include <stdio.h> #include "sort.h"
int main(void) { int number1[] = {3, 5, 1, 6, 9}; sort(number1, 5, larger); printf("大的在前 "); int i; for(i = 0; i < 5; i++) { printf("%d ", number1[i]); } putchar('\n');
int number2[] = {3, 5, 1, 6, 9}; sort(number2, 5, smaller); printf("小的在前 "); for(i = 0; i < 5; i++) { printf("%d ", number2[i]); } putchar('\n'); return 0; }
執行結果:
大的在前 9 6 5 3 1
小的在前 1 3 5 6 9
|
在函式中,不必理會傳入的實際函式,只要呼叫compare()就可以了,在這個例子中,您的sort()上的函式指標宣告有些難以閱讀,您可以使用
typedef,定義一個比較容易閱讀的名稱,例如:
typedef int (*CMP)(int, int); void swap(int*, int*); int larger(int a, int b); int smaller(int a, int b); void sort(int*, int, CMP);
#include "sort.h"
void swap(int *a, int *b) { int t = *a; *a = *b; *b = t; }
int larger(int a, int b) { return a > b; }
int smaller(int a, int b) { return a < b; }
void sort(int* arr, int length, CMP compare) { int flag = 1; int i, j; for(i = 0; i < length-1 && flag == 1; i++) { flag = 0; for(j = 0; j < length-i-1; j++) { if(compare(arr[j+1], arr[j])) { swap(arr + j + 1, arr + j); flag = 1; } } } }
可以看到,重新使用typedef定義CMP名稱後,函式比較容易閱讀的多了。
您也可以宣告函式指標陣列,例如:
int (*compare[10])(int, int);
上面這個宣告產生具有10個元素的陣列,可以儲存10個sort函式型態的位址,不過這樣的宣告實在難以閱讀,可以使用typedef來改進:
typedef int
(*CMP)(int, int);
CMP
compare[10];
可以看到這次的宣告比較容易閱讀了。
|
|