一、轉(zhuǎn)移表
1.1、轉(zhuǎn)移表的定義
??
??在之前的學(xué)習(xí)中,我們學(xué)習(xí)了函數(shù)指針數(shù)組(詳情請(qǐng)看【C語(yǔ)言】——指針?biāo)模鹤址羔樑c函數(shù)指針變量),在最后。我曾問(wèn)到:函數(shù)指針數(shù)組有什么用呢?別急,本文給大家細(xì)細(xì)道來(lái)。
??
??函數(shù)指針數(shù)組常常被用在轉(zhuǎn)移表中,那轉(zhuǎn)移表是什么呢?
??
??轉(zhuǎn)移表是一種數(shù)據(jù)結(jié)構(gòu),他用于根據(jù)輸入值來(lái)確定需要執(zhí)行的函數(shù)或操作,轉(zhuǎn)移表通常是一個(gè)包含指針的數(shù)組,數(shù)組中每個(gè)元素包含著指向?qū)?yīng)函數(shù)或操作的指針,通過(guò)查找對(duì)應(yīng)的輸入值進(jìn)行索引,程序可以調(diào)用對(duì)應(yīng)位置的函數(shù)或操作,從而實(shí)現(xiàn)通過(guò)輸入值動(dòng)態(tài)調(diào)度程序執(zhí)行不同的功能。
??
圖示:
??
??轉(zhuǎn)移表的使用可以避免冗長(zhǎng)的
i
f
?
e
l
s
e
if-else
if?else 語(yǔ)句或
s
w
i
t
c
h
switch
switch 語(yǔ)句,有效提高代碼的可讀性和維護(hù)性。通過(guò)利用轉(zhuǎn)移表,程序可以根據(jù)輸入值在常量時(shí)間內(nèi)找到對(duì)應(yīng)的操作或函數(shù),并進(jìn)行執(zhí)行,而不需要逐個(gè)判斷條件。轉(zhuǎn)移表在實(shí)現(xiàn)分支邏輯較多、需要快速查找執(zhí)行路徑的情況下非常有用。
??
??不知道你懂了嗎?如果此時(shí)的你還有點(diǎn)懵,我們舉一些生活中的例子來(lái)加深理解吧。
- 比如我們?nèi)ゲ蛷d吃飯,點(diǎn)菜時(shí)菜單就像是一個(gè)轉(zhuǎn)移表,菜單上的每個(gè)菜,可看成轉(zhuǎn)移表中的函數(shù)指針,每道菜對(duì)應(yīng)這一個(gè)價(jià)格和烹飪方法,即函數(shù)定義。當(dāng)我們選擇后,餐廳通知廚師開(kāi)始烹飪,即執(zhí)行相關(guān)函數(shù)??偨Y(jié)下來(lái),即:菜單就是轉(zhuǎn)移表,通過(guò)菜名(輸入值)來(lái)決定具體的烹飪操作(函數(shù))。
?? - 另外,想象你玩一個(gè)游戲,根據(jù)不同的按鍵操作進(jìn)行不同的動(dòng)作,比如按下"A"鍵跳躍、按下"B"鍵攻擊。游戲中的按鍵映射就可以看作是一個(gè)轉(zhuǎn)移表,根據(jù)玩家的操作(輸入值)執(zhí)行相應(yīng)的游戲動(dòng)作(函數(shù))。
??
1.2、簡(jiǎn)易計(jì)算器的一般實(shí)現(xiàn)
??
下面,我們來(lái)用一般方法來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)易計(jì)算器:
#include<stdio.h>
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;
}
void menu()
{
printf("***************************\n");
printf("*** 1: Add 2: Sub ***\n");
printf("*** 3: Mul 4: Div ***\n");
printf("*** 0: exit ***\n");
printf("***************************\n");
}
int main()
{
int x = 0, y = 0;
int input = 0;
int ret = 0;
do
{
menu();
printf("請(qǐng)選擇:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("請(qǐng)輸入要計(jì)算的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
ret = Add(x, y);
printf("運(yùn)算結(jié)果是:%d\n", ret);
break;
case 2:
printf("請(qǐng)輸入要計(jì)算的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
ret = Sub(x, y);
printf("運(yùn)算結(jié)果是:%d\n", ret);
break;
case 3:
printf("請(qǐng)輸入要計(jì)算的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
ret = Mul(x, y);
printf("運(yùn)算結(jié)果是:%d\n", ret);
break;
case 4:
printf("請(qǐng)輸入要計(jì)算的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
ret = Div(x, y);
printf("運(yùn)算結(jié)果是:%d\n", ret);
break;
case 0:
printf("退出計(jì)算器\n");
break;
default:
printf("選擇錯(cuò)誤,請(qǐng)重新選擇\n");
break;
}
} while (input);
return 0;
}
??
1.3、用轉(zhuǎn)移表實(shí)現(xiàn)簡(jiǎn)易計(jì)算器
??
??雖然上述代碼用
s
w
i
t
c
h
switch
switch 語(yǔ)句實(shí)現(xiàn)了簡(jiǎn)易的計(jì)算器,但是可以發(fā)現(xiàn),這段代碼有許多重復(fù)的語(yǔ)句,太過(guò)冗余。那可以怎么改進(jìn)呢?這時(shí),我們就可以用函數(shù)指針數(shù)組實(shí)現(xiàn)一個(gè)轉(zhuǎn)移表
了。
??
int(*p[5])(int, int) = { 0,Add,Sub, Mul,Div };
??
??這里,我們
創(chuàng)建一個(gè)函數(shù)指針數(shù)組作為轉(zhuǎn)移表
??
??因?yàn)閿?shù)組的下標(biāo)是從 0 開(kāi)始
的,因此我們的首位放置 0
,往后各位置放置相應(yīng)函數(shù)地址
(函數(shù)名就是函數(shù)地址),以便與前面的選擇菜單一一對(duì)應(yīng)
??
#include<stdio.h>
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;
}
void menu()
{
printf("***************************\n");
printf("*** 1: Add 2: Sub ***\n");
printf("*** 3: Mul 4: Div ***\n");
printf("*** 0: exit ***\n");
printf("***************************\n");
}
int main()
{
int x = 0, y = 0;
int input = 0;
int ret = 0;
int(*p[5])(int, int) = { 0,Add,Sub, Mul,Div };
do
{
menu();
printf("請(qǐng)選擇:");
scanf("%d", &input);
if(input <= 4 && input >= 1)
{
printf("請(qǐng)輸入要計(jì)算的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
int ret = p[input](x, y);
printf("運(yùn)算結(jié)果是:%d\n", ret);
}
else if(0 == input)
{
printf("退出計(jì)算器\n");
}
else
{
printf("選擇錯(cuò)誤,請(qǐng)重新選擇\n");
}
} while (input);
return 0;
}
??
??
二、回調(diào)函數(shù)
??
2.1、回調(diào)函數(shù)的定義
??
??這里呢,介紹一個(gè)新概念,回調(diào)函數(shù)。
??
??回調(diào)函數(shù)是什么?回調(diào)函數(shù)就是一個(gè)通過(guò)函數(shù)指針調(diào)用的函數(shù)。
??
??如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè)函數(shù)
,當(dāng)這個(gè)指針被用來(lái)調(diào)用其所指向的函數(shù)
時(shí),被調(diào)用的函數(shù)就是回調(diào)函數(shù)?;卣{(diào)函數(shù)不是由該函數(shù)的實(shí)現(xiàn)方直接調(diào)用,而是在特定的條件下,由另一方進(jìn)行調(diào)用,用于對(duì)該條件或事件的響應(yīng)。
??
我們通過(guò)簡(jiǎn)單的例子來(lái)理解一下:
#include<stdio.h>
void test1()
{
printf("hello world\n");
}
void test2(void (*p)())
{
(*p)();
}
int main()
{
test2(test1);
return 0;
}
??
??上述代碼中,
m
a
i
n
main
main函數(shù)通過(guò)調(diào)用
t
e
s
t
2
test2
test2 函數(shù)來(lái)調(diào)用
t
e
s
t
1
test1
test1 函數(shù),最終在屏幕上打印出
"
h
e
l
l
o
"hello
"hello
w
o
r
l
d
"
world"
world"。
??
2.2、用回調(diào)函數(shù)實(shí)現(xiàn)簡(jiǎn)易計(jì)算器
??
??了解了回調(diào)函數(shù),那上面的簡(jiǎn)易計(jì)算器也可以通過(guò)回調(diào)函數(shù)來(lái)改進(jìn)啦。
??
??我們發(fā)現(xiàn),第一個(gè)版本的計(jì)算器中,選擇不同的功能時(shí),
s
w
i
t
c
h
switch
switch 語(yǔ)句太過(guò)冗余
,那么我們可不可以將這部分封裝成一個(gè)函數(shù),再通過(guò)這個(gè)函數(shù)來(lái)調(diào)用運(yùn)算函數(shù)
呢?
??
??
我們可以將他們封裝成
c
a
l
c
calc
calc 函數(shù):
void calc(int(*p)(int, int))
{
int ret = 0;
int x = 0, y = 0;
printf("請(qǐng)輸入要計(jì)算的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
ret = p(x, y);
printf("運(yùn)算結(jié)果是:%d\n", ret);
}
??
??這樣,當(dāng)我們進(jìn)行不同的選擇時(shí),只需要將不同的運(yùn)算函數(shù)指針傳給
c
a
l
c
calc
calc 函數(shù)就行了,省去了大量的重復(fù)代碼。
#include<stdio.h>
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;
}
void menu()
{
printf("***************************\n");
printf("*** 1: Add 2: Sub ***\n");
printf("*** 3: Mul 4: Div ***\n");
printf("*** 0: exit ***\n");
printf("***************************\n");
}
//calc函數(shù)的定義
void calc(int(*p)(int, int))
{
int ret = 0;
int x = 0, y = 0;
printf("請(qǐng)輸入要計(jì)算的兩個(gè)數(shù):");
scanf("%d %d", &x, &y);
ret = p(x, y);
printf("運(yùn)算結(jié)果是:%d\n", ret);
}
int main()
{
int input = 0;
do
{
menu();
printf("請(qǐng)選擇:");
scanf("%d", &input);
switch (input)
{
case 1:
calc(Add);//通過(guò)calc函數(shù)調(diào)用Add函數(shù)
break;
case 2:
calc(Sub);//通過(guò)calc函數(shù)調(diào)用Sub函數(shù)
break;
case 3:
calc(Mul);//通過(guò)calc函數(shù)調(diào)用Mul函數(shù)
break;
case 4:
calc(Div);//通過(guò)calc函數(shù)調(diào)用Div函數(shù)
break;
case 0:
printf("退出計(jì)算器\n");
break;
default:
printf("選擇錯(cuò)誤,請(qǐng)重新選擇\n");
break;
}
} while (input);
return 0;
}
??
??
??
??文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-843397.html
??好啦,本期關(guān)于轉(zhuǎn)移表與回調(diào)函數(shù)就介紹到這里啦,希望本期博客能對(duì)你有所幫助,同時(shí),如果有錯(cuò)誤的地方請(qǐng)多多指正,讓我們?cè)贑語(yǔ)言的學(xué)習(xí)路上一起進(jìn)步!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-843397.html
到了這里,關(guān)于【C語(yǔ)言】——指針五:轉(zhuǎn)移表與回調(diào)函數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!