函式指標
函式在記憶體區塊text segment,有記憶體位址。
使用函式指標,指向函式的記憶體位址。
定義函式指標
傳回值類型 (*指標名)(參數類型1, 參數類型2, 參數類型3 ....)
以下函式指標名是pf,傳回值類型是int,參數有2個,參數類型都為int。
1
int (* pf)(int,int);
函式名就是記憶體位址
函式指標指向函式名的記憶體位址。
傳回值類型 (*指標名)(參數類型 ...) = 函式名
以下max()函式也符合傳回值類型是int,參數數量為2,參數類型為int。
1
2
3
4
5
6
int max(int x, int y) {
if (x > y)
return x;
else
return y;
}
把max函式名(記憶體位址)指派給pf函式指標。
1
int (* pf)(int,int) = max;
函式指標存放的位址
下圖中,Stack區域有一個pf變數,本身記憶體位址是0x1000,存放的記憶體位址是0x2000。
使用程式碼印出pf指標變數,印出pf與*pf,二者的值都是存放的記憶體位址0x2000。
1
2
3
4
5
6
7
8
9
10
11
int max(int x, int y) {
if (x > y)
return x;
else
return y;
}
int main() {
int (* pf)(int,int) = max;
printf("pf addr= %p, &pf addr= %p, * pf addr = %p\n",pf, &pf, * pf);
return 0;
}
pf addr= 0x2000, &pf addr= 0x1000, * pf addr = 0x2000
函式指標呼叫函式
pf指標存放的是max()函式記憶體位址。
方式1
1
int ret = pf(x,y);
完整程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
int max(int x, int y) {
if (x > y)
return x;
else
return y;
}
int main() {
int (* pf)(int,int) = max;
int a = 10, b = 20;
int ret = pf(a, b);
cout << ret << endl;
return 0;
}
20
方式2
pf指標存放的是max()函式記憶體位址。函式記憶體位址使用*取值運算子,把max()函式整個從記憶體中取出來。
1
int ret = (* pf)(x,y);
完整程式碼
1
2
3
4
5
6
7
8
9
10
11
12
13
int max(int x, int y) {
if (x > y)
return x;
else
return y;
}
int main() {
int (* pf)(int,int) = max;
int a = 10, b = 20;
int ret = (* pf)(a, b);
cout << ret << endl;
return 0;
}
20
運算子優先順序
函式指標正確寫法,回傳值類型為int整數。
1
int (* pf)(int,int);
錯誤寫法,沒有使用括號:
1
int * pf(int,int);
回傳值類型為「int指標」,函式名為pf。
1
int* pf(int,int);
所以使用圓括號包住指標名(* pf),相當重要,沒有圓括號,傳回值類型就變成指標。
函式指標作為函式參數
建立一個大小為10的陣列,裡面的值都是亂數。
產生亂數的getRand()函式
1
2
3
int getRand() {
return rand();
}
根據getRand()函式,定義函式指標。
傳回值是int,沒有參數,void代表沒有參數。
1
int(* pf)(void);
初始化陣列函式initArr(),把函式指標作為函式參數傳入。
1
void initArr(int arr[], int size, int(* pf)(void));
由函式指標去呼叫getRand()函式。
1
2
3
4
5
void initArr(int arr[], int size, int(* pf)(void)) {
for (int i = 0; i < size; i++) {
arr[i] = pf(); // 呼叫getRand()
}
}
完整程式碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int getRand() {
return rand();
}
void initArr(int arr[], int size, int(* pf)(void)) {
for (int i = 0; i < size; i++) {
arr[i] = pf();
}
}
int main() {
int arr[10] = {0};
int len = sizeof(arr) / sizeof(int);
initArr(arr, len, getRand);
for (int i = 0; i < len; i++) {
cout << arr[i] << ", ";
}
cout << endl;
return 0;
}
16807, 282475249, 1622650073, 984943658, 1144108930, 470211272, 101027544, 1457850878, 1458777923, 2007237709,
以下為舊文章
函式資料型態
函式資料型態是由函式的傳回值資料型態/參數資料型態/參數的數量
所組成。
如果多個函式的傳回值資料型態/參數資料型態/參數的數量
都一樣,代表這些函式是同一個資料型態。
以下三個函式都是相同資料型態,傳回值資料型態/參數資料型態/參數的數量都一樣。
- int func1(int code, string msg);
- int func2(int age, string name);
- int func3(int userId, string userName);
以下三個函式都是相同資料型態,傳回值資料型態/參數資料型態/參數的數量都一樣。
- bool func4(string param1);
- bool func5(string msg);
- bool func6(string name);
以下二個函式不是相同資料型態。
- int func1(int code, string msg);
- bool func4(string param1);
以下三個函式的函式資料型態為 int (*pf1)(int,string),其中pf1為函式指標的變數名,可以為任意名稱,名稱前面要有星號*,要用括號()包起來,int為傳回值資料型態,(int,string)為函式參數資料型態與參數數量。
- int func1(int code, string msg);
- int func2(int age, string name);
- int func3(int userId, string userName);
以下三個函式的函式資料型態為 bool (*pf2)(string),其中pf2為函式指標的變數名,可以為任意名稱。
- bool func4(string param1);
- bool func5(string msg);
- bool func6(string name);
宣告函式指標
1
2
3
4
5
6
7
8
9
10
int func1(int code, string msg) {
cout << "Err code = " << code << ", msg = " << msg << endl;
return code;
}
int main() {
int (*pf1)(int,string); //宣告函式指標變數pf1
pf1 = func1; //將func1函式設給pf1函式指標變數
pf1(404, "Page not found."); //使用函式指標pf1呼叫函式
return 0;
}
第1行,宣告函式。
第6行,宣告函式指標變數pf1。
第7行,將func1函式設給pf1函式指標變數。
第8行,使用函式指標pf1呼叫函式。
執行結果
Err code = 404, msg = Page not found.
typedef函式指標類型別名
語法
typedef 傳回值(*類型別名)(參數1,參數2,參數3 ...);
將前一個宣告函式指標的程式碼
1
int (*pf1)(int,string);
改成下方的程式碼,前面添加typedef,並把pf1改成Func1,Func1可以為任意名字,並放在程式的開頭。
1
typedef int (*Func1)(int,string);
修改完的程式碼如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;
//宣告Func1類型別名
typedef int (*Func1)(int,string);
int func1(int code, string msg) {
cout << "Err code = " << code << ", msg = " << msg << endl;
return code;
}
int main() {
//宣告指標變數pf1為Func1類型
Func1 pf1; //宣告函式指標變數pf1
pf1 = func1; //函式指標變數pf1設定函式
pf1(404, "Page not found.");//使用函式指標pf1呼叫函式
return 0;
}
執行結果
Err code = 404, msg = Page not found.
函式參數是函式指標
宣告函式print404Msg(),第一個參數為函式指標,函式的資料型態是傳回值為int,函式指標名為pf1,2個參數資料型態分別為int跟string。
1
2
3
void print404Msg(int (*pf1)(int,string), string msg) {
pf1(404, msg);
}
第1行,宣告函式print404Msg(),第一個參數為函式指標,第二個參數為string資料型態。
第2行,使用函式指標pf1呼叫函式,並把404整數與msg的參數傳進函式。
完整程式
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
using namespace std;
void print404Msg(int (*pf1)(int,string), string msg) {
pf1(404, msg);
}
int func1(int code, string msg) {
cout << "Err code = " << code << ", msg = " << msg << endl;
return code;
}
int main() {
print404Msg(func1, "Page not Found");
return 0;
}
執行結果
Err code = 404, msg = Page not Found
函式參數是typedef函式指標類型別名
也可以使用typedef函式指標類型另取別名。
1
2
3
4
5
6
//宣告Func1類型別名
typedef int (*Func1)(int,string);
//第一個參數資料型態為Func1
void print404Msg(Func1 pf1, string msg) {
pf1(404, msg);
}
完整程式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;
typedef int (*Func1)(int,string);
void print404Msg(Func1 pf1, string msg) {
pf1(404, msg);
}
int func1(int code, string msg) {
cout << "Err code = " << code << ", msg = " << msg << endl;
return code;
}
int main() {
print404Msg(func1, "Page not Found");
return 0;
}
函式指標應用
自訂二個函式指標類型別名
1
2
3
4
5
//宣告類型別名
//傳回值為void,別名為Success,參數資料型態char*指標
typedef void (*Success)(char*);
//傳回值為void,別名為Failure,參數類型分別為int,char*指標
typedef void (*Failure)(int, char*);
1
2
3
4
5
6
void httpOk(char* msg) {
printf("成功,結果:%s\n", msg);
}
void httpFailure(int code, char* msg) {
printf("失敗%d,原因:%s\n", code, msg);
}
第1行,宣告函式,傳回值與參數資料型態都符合函式指標類型別名Success
第4行,宣告函式,傳回值與參數資料型態都符合函式指標類型別名Failure
1
2
3
4
5
6
7
8
9
10
11
12
void http(int res, Success success, Failure failure) {
if(res == 1) {
success("取得資料成功");
} else {
failure(505,"網路連線有問題");
}
}
int main() {
http(1,httpOk,httpFailure);
http(0,httpOk,httpFailure);
return 0;
}
第1行,宣告函式,第1個參數資料型態int,第2個參數函式指標類型別名Success,第3個參數函式指標類型別名Failure。
第3行,使用函式指標Success呼叫函式。
第5行,使用函式指標Failure呼叫函式,並傳入參數。
第9行,呼叫http函式,並把函式傳回值參數與自訂Success函式資料型態一樣的httpOk函式傳入。
第10行,呼叫http函式,並把函式傳回值參數與自訂Failure函式資料型態一樣的httpFailure函式傳入。
完整程式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
using namespace std;
//函式指標類型別名
typedef void (*Success)(char*);
typedef void (*Failure)(int, char*);
void httpOk(char* msg) {
printf("成功,結果:%s\n", msg);
}
void httpFailure(int code, char* msg) {
printf("失敗%d,原因:%s\n", code, msg);
}
void http(int res, Success success, Failure failure) {
if(res == 1) {
success("取得資料成功");
} else {
failure(505,"網路連線有問題");
}
}
int main() {
http(1,httpOk,httpFailure);
http(0,httpOk,httpFailure);
return 0;
}
執行結果
成功,結果:取得資料成功
失敗505,原因:網路連線有問題