C語言中的指針能夠指向整型、字符型或者結構體類型,一樣也能夠指向一個函數,這就是函數的指針。函數指針的值等於該函數存放其二進制執行代碼的內存區域的首地址:數組
函數指針的通常聲明形式以下:函數
函數的返回值 (*指針變量名)(函數的參數列表);
例如:spa
int (*p)(int, int);
該變量聲明瞭一個指針變量p,其指向的內容是一個函數。該函數的返回值是一個整型,其參數也是兩個整型變量。聲明瞭一個函數指針後就能夠對其進行賦值。函數名的本質是存放函數代碼的內存空間的首地址,所以能夠將一個函數名賦值給一個指向函數的指針,以後這個函數指針就能夠表示這個函數了:指針
p = f;
表示將f()的存儲空間的首地址賦值給函數指針p,p指向f()這個函數。引用指針就至關於調用這個函數:code
(*p)(1, 2); //等價於 f(1, 2);
下面的程序演示了用函數指針實現兩個整數的四則運算:對象
/** * common.h 聲明全局變量和外部函數的頭文件 */ #include <stdio.h> //聲明四個全局變量 extern int (*p1)(int , int); //引用加法函數 extern int (*p2)(int , int); //引用減法函數 extern int (*p3)(int , int); //引用乘法函數 extern int (*p4)(int , int); //引用除法函數 //四則運算函數聲明 int add(int a, int b); //加法函數 int sub(int a, int b); //減法函數 int mul(int a, int b); //乘法函數 int div(int a, int b); //除法函數
/** * lib.c 定義全局變量和四則運算函數 */ #include "common.h" //全局變量定義 int (*p1)(int , int) = NULL; int (*p2)(int , int) = NULL; int (*p3)(int , int) = NULL; int (*p4)(int , int) = NULL; //四則運算函數 //加法函數 int add(int a, int b) { return a + b; } //減法函數 int sub(int a, int b) { return a - b; } //乘法函數 int mul(int a, int b) { return a * b; } //除法函數 int div(int a, int b) { return a / b; }
在main函數中調用四則運算函數:內存
#include "common.h" int main(void) { int a, b, res; //使用四個全局變量的函數指針來引用這四個函數 p1 = add; p2 = sub; p3 = mul; p4 = div; a = 2; b = 1; printf("add : %d\n", (*p1)(a, b)); printf("sub : %d\n", (*p2)(a, b)); printf("mul : %d\n", (*p3)(a, b)); printf("div : %d\n", (*p4)(a, b)); return 0; }
運行結果:input
假設有一個max()函數能夠在任意一組對象中找到鍵碼最大的對象,這些對象多是一些整數,也多是一些結構體。回調函數
爲了將max()函數實現的更加通用,能夠將其適用於任何對象,所以須要由調用max()函數的調用者本身提供一個比較兩個對象的函數做爲標準,這兩個比較函數就是回調函數。string
下面演示max函數的實現:
在main函數中調用max()函數,分別比較尋找一個整型數組中的最大值和一個存儲圖書信息的結構體數組中圖書id最大的圖書結構體。
/** * common.h 聲明全局變量和外部函數的頭文件 */ #include <stdio.h> #include <stdlib.h> #include <string.h> /** * 定義一個自定義類型的函數指針,返回值是整數,兩個參數是兩個任意類型的指針 * 該函數的兩個參數分別是須要比較的兩個對象,在比較時將其轉換 * 若是大於則返回1,等於則返回0,小於則返回-1 */ typedef int (*cmp)(void *, void *); typedef struct book* Book; /** * 圖書結構: * id:圖書的編號 * name:圖書的名字 */ struct book{ int id; char name[10]; }; //求最大對象的函數 extern void *max(void *array[], int len, cmp func); //比較兩個整數的函數 extern int cmp_int(void *p, void *q); //比較兩個圖書結構的函數 extern int cmp_struct(void *p, void *q); //插入一個結構 extern int insert_struct(Book *pos, int id, char * name); //插入一個整數 extern int insert_int(int **pos, int val);
/** * max.c 實現max()函數和用做對象比較的回調函數 */ #include "common.h" /** * 求序列中最大對象的函數,而且返回最大對象的位置 * array:存儲對象的數組,每一個元素是一個指向對象的指針 * len:存儲對象的數組的元素個數 * func:用於比較兩個對象的回調函數 */ void *max(void *array[], int len, cmp func) { int i; void *tmp; tmp = array[0]; //初始時最大對象是數組的第一個對象 for(i = 1; i < len; i++){ //比較兩個對象,調用用戶提供的比較函數 //若是當前對象大於以前的對象,則替換掉對打對象 if((*func)(tmp, array[i]) == -1) { tmp = array[i]; } } return tmp; //返回最大對象 }
/** * cmp.c 定義比較兩個對象的回調函數 */ #include "common.h" int cmp_int(void *p, void *q) { int *a, *b; a = (int *)p; //將參數中void*類型指針轉換爲int型的指針 b = (int *)q; if(*a > *b) { //比較兩個值的大小 return 1; } else if(*a < *b){ return -1; } else{ return 0; } } int cmp_struct(void *p, void *q) { Book a, b; a = (Book)p; //將參數中void*類型的指針轉換爲Book類型的指針 b = (Book)q; if(a->id > b->id){ return 1; } else if(a->id < b->id){ return -1; } else{ return 0; } }
/** * obj.c 定義與對象相關的輸入函數 */ #include "common.h" /** * 建立一個圖書結構,並將其插入到指定的位置 * pos:保存新建立的結構體的數組的指針,注意這是一個指向Book指針類型的指針 * id:新結構體的id * name:新結構體的name * 若是成功建立一個新結構體並將其設置到指定位置,則返回0,失敗返回-1 */ int insert_struct(Book *pos, int id, char *name) { Book p; p = (Book)malloc(sizeof(struct book)); //分配一個空間 if(p == NULL){ perror("fail to malloc"); return -1; } p->id = id; strcpy(p->name, name); //對結構體變量進行賦值 *pos = p; //將結構體變量賦值到數組中 return 0; } //爲了統一模式,添加一個插入整型元素的函數,這個函數也能夠不要 int insert_int(int **pos, int val) { int *p; p = (int *)malloc(sizeof(int)); //分配一個整型數據 *p = val; *pos = p; return 0; }
在main函數中使用:
#include "common.h" #define MAX 3 int main(void) { Book array1[MAX]; //結構體變量的數組 int *array[MAX]; //整型變量的數組 int i, id, val; char name[10]; Book res1; int *res2; for(i = 0; i < MAX; i++){ printf("input info of book\n"); scanf("%d", &id); scanf("%s", name); if(insert_struct(array1 + i, id, name) == -1){ exit(1); } printf("input int\n"); scanf("%d", &val); if(insert_int(array + i, val) == -1){ exit(1); } } res1 = (Book)max((void **)array1, MAX, cmp_struct);//獲得id最大的圖書結構 res2 = (int *)max((void **)array, MAX, cmp_int);//獲得最大的整型元素 printf("the max of books : %d, %s\n", res1->id, res1->name); printf("the max of int : %d\n", *res2); return 0; }
運行結果爲:
回調函數在C語言中的應用是很普遍的,這使得C語言中提供泛型函數成爲可能,同事也使得代碼的通用性更強,可是一樣會使代碼的數量變得龐大並且執行效率不那麼高。
C語言中能夠出現函數指針的數組,該數組中的每個元素是一個函數的指針。通常的定義以下:
函數返回值 (*數組名[元素個數])(參數列表);
例如:
int (*f[10])(int , int);
該定義表示定義了一個數組f,其數組中每一個元素是一個指針。該指針是一個指向函數的指針,該函數擁有一個整型返回值,兩個整型的參數。這個函數指針數組共有10個元素。
下面的例子定義和使用函數數組的實例:
#include <stdio.h> //加法函數 int add(int a, int b) { return a + b; } //乘法函數 int mul(int a, int b) { return a * b; } int main(void) { /** * 定義一個函數指針的數組 * 這個數組名爲op,數組共有兩個元素,每一個元素是一個函數指針 * 這個函數指針指向一個有一個整型返回值,兩個整型參數的函數 */ int (*op[2])(int a, int b); op[0] = &add; //第一個指向add()函數 op[1] = &mul; //第二個指向mul()函數 printf("%d %d\n", op[0](1, 2), op[1](1, 2)); return 0; }
運行結果: