相信大家當(dāng)初學(xué)習(xí)C語言的時(shí)候,老師一定跟你說過這樣的一句大實(shí)話:【**指針,是C語言的靈魂**】。
? 筆者自出來工作以來,幾乎天天都要跟C語言打交道,回過頭來想一想,這話確實(shí)沒有錯(cuò)。
? 本文,打算從一個(gè)另類的角度,介紹下C語言指針的高級用法,通過本文的閱讀,你將了解到以下知識:
- C語言的指針是什么?
- C語言指針的高級應(yīng)用:函數(shù)指針
- 函數(shù)指針的具體應(yīng)用示例
C語言的指針是什么
? 指針是什么?相信所有的C語言教程,都會告訴你:【指針就是地址】。沒錯(cuò),的確是這么回事。C語言的指針就好比房屋的地址,只要有了地址,我們就可以訪問到全世界的每一個(gè)角落。C語言的世界也是如此,地址就是一切,有了地址,就沒有干不成的事情。
? 在C語言里,如果想對一個(gè)int類型的變量a進(jìn)行賦值操作,我們會這樣寫: a = 5;這樣的形式,就是直接訪問。對應(yīng)的,我們有間接訪問的方式,就是通過指針來實(shí)現(xiàn)。比如我們可以定義一個(gè)指針 int *b = &a; 指針b存放的是a變量的地址,我們通過這樣: *b = 5;一樣可以實(shí)現(xiàn)對a進(jìn)行賦值操作,這就是間接訪問的力量。
? C語言的指針是靈活的,它不僅可以像如上代碼一樣,指向一個(gè)普通變量,它也可以指向一個(gè)結(jié)構(gòu)體變量,甚至還可以指向一個(gè)函數(shù)名。原因就在于,函數(shù)名,在C語言的語法里,本質(zhì)上就代表了函數(shù)的執(zhí)行地址,說白了,它也是一個(gè)“指針”。而這,就是我們以下要詳細(xì)介紹的【函數(shù)指針】。
C語言指針的高級應(yīng)用:函數(shù)指針
? 【函數(shù)指針】,顧名思義,就是一個(gè)指向函數(shù)的指針,它的本質(zhì)還是一個(gè)指針,只不過這個(gè)指針指向的內(nèi)容是一個(gè)函數(shù)。
? 在講解【函數(shù)指針】之前,我們先假設(shè)有若干個(gè)函數(shù),它們的原型定義如下所示:
int test_function_1(int arg);
int test_function_2(int arg);
int test_function_3(int arg);
...
int test_function_n(int arg);
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-NgxkHoX2-1661923373249)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]
? 從函數(shù)原型上我們可以知道,這些個(gè)函數(shù)都是接收一個(gè)int類型的形參,返回值類型為int型。從原型上看,這幾個(gè)函數(shù)幾乎是一模一樣,那么我們有沒有方法可以將這些原型一致的函數(shù)重新整理定義呢?答案肯定是,有的。
? 追求高效、簡潔的C語言就我們提供了一個(gè)非常有用的關(guān)鍵字typedef,通過typedef我們可以重新創(chuàng)造出一個(gè)新的數(shù)據(jù)類型,而不再局限于C語言的基本數(shù)據(jù)類型。比如我們就可以利用typedef定義一個(gè)叫形如上述函數(shù)原型的【函數(shù)指針】數(shù)據(jù)類型,它的寫法如下所示:
typedef int (*FUNCTION)(int arg);
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-MLEkQ9Bo-1661923373252)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]
? 從定義上看,因?yàn)?)擁有最高優(yōu)先級,所以*FUNCTION首先結(jié)合在一起,這就決定了它是一個(gè)指針。接著,*FUNCTION的后面接上了(int arg),這就是函數(shù)的入?yún)?;而前面的int 就表示函數(shù)的返回值。這就是【函數(shù)指針】的原型定義。
? 【函數(shù)指針】最為一種特殊的指針,自然它也是要指向內(nèi)容才能使用的,毫無疑問,它就是要指向?qū)?yīng)原型的函數(shù)。具體怎么使用呢?
函數(shù)指針的具體應(yīng)用示例
? 【函數(shù)指針】這種高階用法,可能有些人用得比較少,但是如果你閱讀過類似openssl這樣的大型C語言編寫的開源代碼之后,相信你一定會感嘆:原來,C語言的指針還能這么用!??!
? 有了【函數(shù)指針】的利器,我們就可以用它來大做文章,請看以下示例代碼:
int test_function_1(int arg)
{
printf("This msg is printed form %s ...\n", __func__);
return arg;
}
int test_function_2(int arg)
{
printf("This msg is printed form %s ...\n", __func__);
return arg;
}
int test_function_3(int arg)
{
printf("This msg is printed form %s ...\n", __func__);
return arg;
}
typedef int (*FUNCTION)(int arg);
int function_pointer_test_1(void)
{
int ret;
int arg = 1;
FUNCTION func = NULL; //定義個(gè)函數(shù)指針
func = test_function_1; //把函數(shù)指針指向test-function-1
//ret = test_function_1(arg); //通過函數(shù)名直接調(diào)用test-function-1函數(shù)
ret = func(arg); //通過函數(shù)指針間接調(diào)用test-function-1函數(shù)
func = test_function_2; //把函數(shù)指針指向test-function-2
//ret = test_function_2(arg); //通過函數(shù)名直接調(diào)用test-function-2函數(shù)
ret = func(arg); //通過函數(shù)指針間接調(diào)用test-function-2函數(shù)
func = test_function_3; //把函數(shù)指針指向test-function-3
//ret = test_function_3(arg); //通過函數(shù)名直接調(diào)用test-function-3函數(shù)
ret = func(arg); //通過函數(shù)指針間接調(diào)用test-function-3函數(shù)
return 0;
}
int function_pointer_test_2(void)
{
int ret;
int arg = 1;
int i = 0;
FUNCTION func = NULL; //定義個(gè)函數(shù)指針
FUNCTION func_array[] = //定義一組函數(shù)列表
{
test_function_1,
test_function_2,
test_function_3,
};
//終極大招,循環(huán)處理3個(gè)函數(shù)的間接調(diào)用
for (i = 0; i < sizeof(func_array); i ++) {
func = func_array[i]; //把函數(shù)指針指向?qū)?yīng)的函數(shù)
ret = func(arg); //通過函數(shù)指針間接調(diào)用對應(yīng)的函數(shù)
}
return 0;
}
int main(int argc, char **argv)
{
function_pointer_test_1();
function_pointer_test_2();
/*
結(jié)果輸出,兩個(gè)function_pointer_test函數(shù)均有同樣的輸出結(jié)果:
This msg is printed form test_function_1 ...
This msg is printed form test_function_2 ...
This msg is printed form test_function_3 ...
*/
return 0;
}
/*
總結(jié):
雖然通過兩個(gè)調(diào)用的方式,輸出結(jié)果是一致的,但是顯然方式2的處理更為高效、簡潔;
從代碼的字里行間,仿佛看到C語言的“多態(tài)”:將不同的函數(shù)名賦值給同一個(gè)函數(shù)指針變量;
使用同一個(gè)函數(shù)指針發(fā)起函數(shù)調(diào)用,得到不一樣的結(jié)果輸出,這不就是多態(tài)嗎?
*/
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-oLznHZnb-1661923373260)(data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)]
? 通過如上的示例代碼,C語言的【多態(tài)】你get到了嗎?
? 千萬不要小瞧了上面的示例代碼,如果你能熟練掌握其中的【指針精髓】,再去閱讀一些業(yè)內(nèi)廣泛使用的C語言編寫的開源項(xiàng)目源碼,比如大名鼎鼎的openssl;相信閱讀之后,你的C語言功力一定會大大地提升。
? 不過,值得注意的是,文中的示例代碼均是筆者在非編程環(huán)境下編寫,屬于【白板編程】,難免會出現(xiàn)編寫錯(cuò)誤、編譯不過、或執(zhí)行結(jié)果不正確的情況;還請細(xì)心的讀者誠心指正,感激不盡。
延伸閱讀預(yù)告:
為充實(shí)C語言的指針知識,筆者將會在后續(xù)的文章中整理大名鼎鼎的C語言巨著《C和指針》,敬請期待。
-
C語言
+關(guān)注
關(guān)注
180文章
7616瀏覽量
137892 -
指針
+關(guān)注
關(guān)注
1文章
482瀏覽量
70614 -
函數(shù)指針
+關(guān)注
關(guān)注
2文章
56瀏覽量
3838
發(fā)布評論請先 登錄
相關(guān)推薦
評論