函數指針,顧名思義指向函數的指針
函數的首地址在代碼區,函數名就是一個函數的首地址
函數指針的定義如下
函數的返回類型 (*函數指針變量名)(參數類型1, 參數類型2......) = 初始值;
若兩個函數指針完全相同 則函數的返回類型和參數的個數以及類型都是相同的.
例如
int max(int x, int y){
return x > y ? x : y;
}
int sum(int x, inty){
return x +y;
}
在main函數中可以這樣使用如下兩個函數
int a = 9, b = 3;
max(a, b);
sum(a, b);
我們發現上面的兩個函數中都有一個返回類型爲int型,並且都是有兩個參數,而且類型是相同的.我們這個時候就可以定義一個函數指針
如下
int (*p) (int x, int y) = NULL;
這個時候如果我們想求最大值,我們就可以用p指針來調用這個函數,我們上面說過函數的名字即是函數的首地址,我們可以讓p指針指向這個函數的首地址
即p = max;
這樣便可以通過p來調用這個函數了p(a, b);
當然我們也可以用p來調用sum這個求和函數,p是一個函數指針變量,可以重定向,即可以指向max函數也可以指向sum這個函數
p = sum; p(a, b); 這樣就可以求出最大值.
但是這個時候我們會發現一個問題,我們在想使用sum 和max函數的時候需要調用兩次,我們可以把函數指針作爲函數的參數,這樣我們在main函數中傳入max或者是sum這樣便可以自動根據我們的需要求出想要的結果
改進如下:
typedef int (*p) (int , int);//這是對函數指針類型的重命名,和別的typedef不同的是,這個時候新命的名字在*後面,我們這個即p指針
int function(int x, int y, p type);
int max(int x, inty);
int sum(int x, inty);
int max(int x, inty){
return x > y ? x : y;
}
int sum(int x, inty){
return x + y;
}
int function(int x, int y, p type){
return type(x, y);
}
這個時候在mian函數中,如果想求兩個數的和以及最大值便可以如下
int a = 2, b = 3;
function(2, 3, sum);
function(2, 3, max);
這便是回調函數的用法:使用指針來調用函數
我們現在對我們經常對學生信息排序用一個回調函數來實現
首先定義一個結構體數組
struct student{
char name[20];
int age;
};
typedef student Student;
//我們來定義一個結構體數組
Student stu[3] = {
{"liyang", 56},
{"liyan", 23},
{"liming", 24}
};
如果我們想對年齡排序我們通常會寫如下函數:
void bubbleSort (Student *p, int n){
BOOL flag= YES;
for(int i = 0; i < n - 1; i ++){
flag = NO;
for(int j = 0; j < n - 1 - i; j++){
if((p + j)- > age > (p + j + 1)){
Student temp = *(p + j);
*(p + j) = *(p + j + 1);
*(p + j + 1) = temp;
}
}
}
}
如果我們想對學生按照姓名排序,就要再if這個判斷條件修改一下,改成判斷姓名就可以了,別的並沒有修改
這個時候我們可以把這個判斷條件寫成一個函數如下
BOOL isAge(Student *stu1, Student *stu2);
BOOL isAge(Student *stu1, Student *stu2){
return stu1-> age > stu2->age;//條件關係符返回的是一個布爾值,如果表達式成立,則返回YES,如果表達式不成立,則返回NO
}
BOOL isName(Student *stu1, Student *stu2);
BOOL isName(Student *stu1, Student *stu2){
return strcmp(stu1->name > stu2->name) > 0;
}
這個時候冒泡中的條件就可以寫成 isAge((p + j), (p + j + 1));但是這個時候還是不是很好,我們可以如上面的回調函數一樣,用函數指針作爲形參
typedef BOOL (* type) (Student *stu1, Student *stu2);
void bubbleSort (Student *p, int n, type rt){
BOOL flag= YES;
for(int i = 0; i < n - 1; i ++){
flag = NO;
for(int j = 0; j < n - 1 - i; j++){
if(rt(p + j), (p + j + 1)){
Student temp = *(p + j);
*(p + j) = *(p + j + 1);
*(p + j + 1) = temp;
}
}
}
這樣在主函數中就可以使用
bubbleSort (stu, 3, isName);//按照名字排序
bubbleSort (stu, 3, isAge);//按照年齡排序
但是如果客戶的話,他可能不知道isAge是什麼isName是什麼,但是他想按照"name"排序
可能就會傳入
bubbleSort (stu, 3, "name");
這個時候我們怎麼樣調用呢,當然我們之前的函數仍然可以使用,這個時候我們可以把name傳過去,然後接受的時候判斷一下是該執行那個函數,然後返回那個函數的地址,這個時候我們就要返回一個一個函數的指針,我們把判斷的語句單獨拿出來即如下所示
typedef BOOL(* sortType ) (student *, student *);
sortType isType(char *string){
if(strcmp(string) == "name"){
return isName;
} else if (strcmp(string) == "age"){
return isAge;
} else {
return isName;//如果不是name或者是age則默認按姓名排序
}
}
void bubbleSort (Student *p, int n, char *string){
sortType rt = isType(string);
BOOL flag= YES;
for(int i = 0; i < n - 1; i ++){
flag = NO;
for(int j = 0; j < n - 1 - i; j++){
if(rt(p + j), (p + j + 1)){
Student temp = *(p + j);
*(p + j) = *(p + j + 1);
*(p + j + 1) = temp;
}
}
}