c語言-函數指針和回調函數

函數指針,顧名思義指向函數的指針

函數的首地址在代碼區,函數名就是一個函數的首地址

函數指針的定義如下

函數的返回類型 (*函數指針變量名)(參數類型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;

}

}

}

}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章