溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么理解C語言中的函數(shù)指針

發(fā)布時(shí)間:2021-10-23 15:39:11 來源:億速云 閱讀:164 作者:iii 欄目:編程語言

本篇內(nèi)容主要講解“怎么理解C語言中的函數(shù)指針”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“怎么理解C語言中的函數(shù)指針”吧!

1.函數(shù)指針的定義


  顧名思義,函數(shù)指針就是函數(shù)的指針。它是一個(gè)指針,指向一個(gè)函數(shù)??蠢樱?/p>

A) char * (*fun1)(char * p1,char * p2);  
B) char * *fun2(char * p1,char * p2);  
C) char * fun3(char * p1,char * p2);



看看上面三個(gè)表達(dá)式分別是什么意思?  


C)這很容易,fun3是函數(shù)名,p1,p2是參數(shù),其類型為char *型,函數(shù)的返回值為char *類型。
B) 也很簡單,與C)表達(dá)式相比,唯一不同的就是函數(shù)的返回值類型為char**,是個(gè)二級(jí)指針。
A) fun1是函數(shù)名嗎?回憶一下前面講解數(shù)組指針時(shí)的情形。我們說數(shù)組指針這么定義或許更清晰:

int (*)[10] p;

再看看A)表達(dá)式與這里何其相似!明白了吧。這里fun1不是什么函數(shù)名,而是一個(gè)指針變量,它指向一個(gè)函數(shù)。這個(gè)函數(shù)有兩個(gè)指針類型的參數(shù),函數(shù)的返回值也是一個(gè)指針。同樣,我們把這個(gè)表達(dá)式改寫一下:

char * (*)(char * p1,char * p2) fun1;



這樣子是不是好看一些呢?只可惜編譯器不這么想。^_^。

2.函數(shù)指針使用的例子


  上面我們定義了一個(gè)函數(shù)指針,但如何來使用它呢?先看如下例子:

#include <stdio.h>
#include <string.h>
char * fun(char * p1, char * p2)
{
    int i= 0;
    i = strcmp(p1,p2);
    if (0 == i)
    {
        return p1;
    }
    else
    {
        return p2;
    }
}

int main()
{
    char * (*pf)(char * p1,char * p2);
    pf = &fun;
    (*pf) ("aa","bb");
    return 0;
}



  這里需要注意到是,在Visual C++6.0里,給函數(shù)指針賦值時(shí),可以用&fun或直接用函數(shù)名fun。這是因?yàn)楹瘮?shù)名被編譯之后其實(shí)就是一個(gè)地址,所以這里兩種用法沒有本質(zhì)的差別。這個(gè)例子很簡單,就不再詳細(xì)討論了?! ∥覀兪褂弥羔樀臅r(shí)候,需要通過鑰匙(“*”)來取其指向的內(nèi)存里面的值,函數(shù)指針使用也如此。通過用(*pf)取出存在這個(gè)地址上的函數(shù),然后調(diào)用它。

如果覺得文字不是很好吸收的話可以配合下面這個(gè)視頻一起看哦>>

讓你不再害怕C語言中的指針(上)_嗶哩嗶哩 (゜-゜)つロ 干杯~-bilibiliwww.bilibili.com

3.*(int*)&p ----這是什么?


  也許上面的例子過于簡單,我們看看下面的例子:

void Function()
{
    printf("Call Function!\n");
}

int main()
{
    void (*p)();
    *(int*)&p=(int)Function;
    (*p)();
    return 0;
}


這是在干什么?*(int*)&p=(int)Function;表示什么意思?
別急,先看這行代碼:

void (*p)();



這行代碼定義了一個(gè)指針變量p,p指向一個(gè)函數(shù),這個(gè)函數(shù)的參數(shù)和返回值都是void。
&p是求指針變量p本身的地址,這是一個(gè)32位的二進(jìn)制常數(shù)(32位系統(tǒng))。
(int*)&p表示將地址強(qiáng)制轉(zhuǎn)換成指向int類型數(shù)據(jù)的指針。
(int)Function表示將函數(shù)的入口地址強(qiáng)制轉(zhuǎn)換成int類型的數(shù)據(jù)。
分析到這里,相信你已經(jīng)明白*(int*)&p=(int)Function;表示將函數(shù)的入口地址賦值給指針變量p。

那么(*p) ();就是表示對(duì)函數(shù)的調(diào)用。


講解到這里,相信你已經(jīng)明白了。其實(shí)函數(shù)指針與普通指針沒什么差別,只是指向的內(nèi)容不同而已。
使用函數(shù)指針的好處在于,可以將實(shí)現(xiàn)同一功能的多個(gè)模塊統(tǒng)一起來標(biāo)識(shí),這樣一來更容易后期的維護(hù),系統(tǒng)結(jié)構(gòu)更加清晰。或者歸納為:便于分層設(shè)計(jì)、利于系統(tǒng)抽象、降低耦合度以及使接口與實(shí)現(xiàn)分開。


推薦一下自己的linuxC/C++交流群:973961276!整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料以及大廠面經(jīng)視頻共享在群文件里面,有需要的小伙伴可以自行添加哦!~

怎么理解C語言中的函數(shù)指針

4.(*(void(*) ())0)()------這是什么?


  是不是感覺上面的例子太簡單,不夠刺激?好,那就來點(diǎn)刺激的,看下面這個(gè)例子:

(*(void(*) ())0)();



這是《C Traps and Pitfalls》這本經(jīng)典的書中的一個(gè)例子。沒有發(fā)狂吧?下面我們就來分析分析:

第一步:void(*) (),可以明白這是一個(gè)函數(shù)指針類型。這個(gè)函數(shù)沒有參數(shù),沒有返回值。 第二步:(void(*) ())0,這是將0強(qiáng)制轉(zhuǎn)換為函數(shù)指針類型,0是一個(gè)地址,也就是說一個(gè)函數(shù)存在首地址為0的一段區(qū)域內(nèi)。 第三步:(*(void(*) ())0),這是取0地址開始的一段內(nèi)存里面的內(nèi)容,其內(nèi)容就是保存在首地址為0的一段區(qū)域內(nèi)的函數(shù)。 第四步:(*(void(*) ())0)(),這是函數(shù)調(diào)用。


好像還是很簡單是吧,上面的例子再改寫改寫:

(*(char**(*) (char **,char **))0) ( char **,char **);



如果沒有上面的分析,肯怕不容易把這個(gè)表達(dá)式看明白吧。不過現(xiàn)在應(yīng)該是很簡單的一件事了。讀者以為呢?

5.函數(shù)指針數(shù)組

  現(xiàn)在我們清楚表達(dá)式

char * (*pf)(char * p);

定義的是一個(gè)函數(shù)指針pf。既然pf是一個(gè)指針,那就可以儲(chǔ)存在一個(gè)數(shù)組里。把上式修改一下:

char * (*pf[3])(char * p);



這是定義一個(gè)函數(shù)指針數(shù)組。

  它是一個(gè)數(shù)組,數(shù)組名為pf,數(shù)組內(nèi)存儲(chǔ)了3個(gè)指向函數(shù)的指針。這些指針指向一些返回值類型為指向字符的指針、參數(shù)為一個(gè)指向字符的指針的函數(shù)。

  這念起來似乎有點(diǎn)拗口。不過不要緊,關(guān)鍵是你明白這是一個(gè)指針數(shù)組,是數(shù)組。函數(shù)指針數(shù)組怎么使用呢?這里也給出一個(gè)非常簡單的例子,只要真正掌握了使用方法,再復(fù)雜的問題都可以應(yīng)對(duì)。

如下:

#include <stdio.h>  
#include <string.h>  
char * fun1(char * p) {
	printf("%s\n",p);
	return p;
}
char * fun2(char * p) {
	printf("%s\n",p);
	return p;
}
char * fun3(char * p) {
	printf("%s\n",p);
	return p;
}
int main() {
	char * (*pf[3])(char * p);
	pf[0] = fun1;
	//可以直接用函數(shù)名    
	pf[1] = &fun2;
	//可以用函數(shù)名加上取地址符    pf[2] = &fun3;  
	pf[0]("fun1");
	pf[0]("fun2");
	pf[0]("fun3");
	return 0;
}

6.函數(shù)指針數(shù)組的指針


  看著這個(gè)標(biāo)題沒發(fā)狂吧?函數(shù)指針就夠一般初學(xué)者折騰了,函數(shù)指針數(shù)組就更加麻煩,現(xiàn)在的函數(shù)指針數(shù)組指針就更難理解了。
其實(shí),沒這么復(fù)雜。前面詳細(xì)討論過數(shù)組指針的問題,這里的函數(shù)指針數(shù)組指針不就是一個(gè)指針嘛。只不過這個(gè)指針指向一個(gè)數(shù)組,這個(gè)數(shù)組里面存的都是指向函數(shù)的指針。僅此而已。


下面就定義一個(gè)簡單的函數(shù)指針數(shù)組指針:

1

char * (*(*pf)[3])(char * p);


注意,這里的pf和上一節(jié)的pf就完全是兩碼事了。上一節(jié)的pf并非指針,而是一個(gè)數(shù)組名;這里的pf確實(shí)是實(shí)實(shí)在在的指針。這個(gè)指針指向一個(gè)包含了3個(gè)元素的數(shù)組;這個(gè)數(shù)字里面存的是指向函數(shù)的指針;這些指針指向一些返回值類型為指向字符的指針、參數(shù)為一個(gè)指向字符的指針的函數(shù)。

  這比上一節(jié)的函數(shù)指針數(shù)組更拗口。其實(shí)你不用管這么多,明白這是一個(gè)指針就ok了。其用法與前面講的數(shù)組指針沒有差別。下面列一個(gè)簡單的例子:

#include <stdio.h>
#include <string.h>
char * fun1(char * p) {
	printf("%s\n",p);
	return p;
}
char * fun2(char * p) {
	printf("%s\n",p);
	return p;
}
char * fun3(char * p) {
	printf("%s\n",p);
	return p;
}
<br>int main() {
	char * (*pf[3])(char * p);
	pf[0] = fun1;
	//可以直接用函數(shù)名    
	pf[1] = &fun2;
	//可以用函數(shù)名加上取地址符    pf[2] = &fun3;<br>    
	pf[0]("fun1");
	pf[0]("fun2");
	pf[0]("fun3");
	return 0;

到此,相信大家對(duì)“怎么理解C語言中的函數(shù)指針”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI