国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
高級(jí)指針話題-函數(shù)指針

腳本之家

你與百萬開發(fā)者在一起

來源:編程珠璣

今日分享:直覺能使吾人得到一個(gè)經(jīng)驗(yàn),而不能使吾人成立一個(gè)道理。一個(gè)經(jīng)驗(yàn)本身,吾所謂真妄;一個(gè)道理,是一個(gè)判斷,判斷必合邏輯。-《中國(guó)哲學(xué)史》

前言

函數(shù)指針是什么?如何使用函數(shù)指針?函數(shù)指針到底有什么大用?本文將一一介紹。

如何理解函數(shù)指針

如果有int *類型變量,它存儲(chǔ)的是int類型變量的地址;那么對(duì)于函數(shù)指針來說,它存儲(chǔ)的就是函數(shù)的地址。函數(shù)也是有地址的,函數(shù)實(shí)際上由載入內(nèi)存的一些指令組成,而指向函數(shù)的指針存儲(chǔ)了函數(shù)指令的起始地址。如此看來,函數(shù)指針并沒有什么特別的。我們可以查看程序中函數(shù)的地址:

#include <stdio.h>
int test()
{
    printf('this is test function');
    return 0;
}
int main(void)
{
    test();
    return 0;
}

編譯:

gcc -o testFun testFun.c

查看test函數(shù)相對(duì)地址(并非實(shí)際運(yùn)行時(shí)的地址):

$ nm testFun |grep test  #查看test函數(shù)的符號(hào)表信息
0000000000400526 T test

如何聲明函數(shù)指針

聲明普通類型指針時(shí),需要指明指針?biāo)赶虻臄?shù)據(jù)類型,而聲明函數(shù)指針時(shí),也就要指明指針?biāo)赶虻暮瘮?shù)類型,即需要指明函數(shù)的返回類型和形參類型。例如對(duì)于下面的函數(shù)原型:

int sum(int,int);

它是一個(gè)返回值為int類型,參數(shù)是兩個(gè)int類型的函數(shù),那么如何聲明該類型函數(shù)的指針呢?很簡(jiǎn)單,將函數(shù)名替換成(*pf)形式即可,即我們把sum替換成(*fp)即可,fp為函數(shù)指針名,結(jié)果如下:

int (*fp)(int,int);

這樣就聲明了和sum函數(shù)類型相同的函數(shù)指針fp。這里說明兩點(diǎn),第一,*和fp為一體,說明了fp為指針類型,第二,*fp需要用括號(hào)括起來,否則就會(huì)變成下面的情況:

int *fp(int,int);

這種情況下,意思就大相徑庭了,它聲明了一個(gè)參數(shù)為兩個(gè)int類型,返回值為int類型的指針的函數(shù),而不再是一個(gè)函數(shù)指針了。

在經(jīng)常使用函數(shù)指針之后,我們很快就會(huì)發(fā)現(xiàn),每次聲明函數(shù)指針都要帶上長(zhǎng)長(zhǎng)的形參和返回值,非常不便。這個(gè)時(shí)候,我們應(yīng)該想到使用typedef,即為某類型的函數(shù)指針起一個(gè)別名,使用起來就方便許多了。例如,對(duì)于前面提到的函數(shù)可以使用下面的方式聲明:

typedef int (*myFun)(int,int);//為該函數(shù)指針類型起一個(gè)新的名字
myFun f1;       //聲明myFun類型的函數(shù)指針f1

上面的myFun就是一個(gè)函數(shù)指針類型,在其他地方就可以很方便地用來聲明變量了。typedef的使用不在本文的討論范圍,但是特別強(qiáng)調(diào)一句,typedef中聲明的類型在變量名的位置出現(xiàn),理解了這一句,也就很容易使用typedef了。因而下面的方式是錯(cuò)誤的:

typedef myFun (int)(int,int);   //錯(cuò)誤
typedef (int)(int,int)  *myFun;   //錯(cuò)誤

為函數(shù)指針賦值

賦值也很簡(jiǎn)單,既然是指針,將對(duì)應(yīng)指針類型賦給它既可。例如:

#include<stdio.h>
int test(int a,int b)
{
    /*do something*/
    return 0
}
typedef int(*fp)(int,int);
int main(void)
{
    fp f1 = test; //表達(dá)式1
    fp f2 = &test;//表達(dá)式2
    printf('%p',f1);
    printf('%p',f2);
    return 0;
}

在這里,聲明了返回類型為int,接受兩個(gè)int類型參數(shù)的函數(shù)指針f1和f2,分別給它們進(jìn)行了賦值。表達(dá)式1和表達(dá)式2在作用上并沒有什么區(qū)別。因?yàn)楹瘮?shù)名在被使用時(shí)總是由編譯器把它轉(zhuǎn)換為函數(shù)指針,而前面加上&不過顯式的說明了這一點(diǎn)罷了。

調(diào)用

調(diào)用也很容易,把它看成一個(gè)普通的函數(shù)名即可:

#include<stdio.h>
int test(int a,int b)
{
    /*do something*/
    printf('%d,%d',a,b);
    return 0
}
typedef int(*fp)(int,int);
int main(void)
{
    fp f = test; 
    f(1,2);//表達(dá)式1
    (*f)(3,4);//表達(dá)式2
    return 0;
}

在函數(shù)指針后面加括號(hào),并傳入?yún)?shù)即可調(diào)用,其中表達(dá)式1和表達(dá)式2似乎都可以成功調(diào)用,但是哪個(gè)是正確的呢?ANSI C認(rèn)為這兩種形式等價(jià)。

函數(shù)指針有何用

函數(shù)指針的應(yīng)用場(chǎng)景比較多,以庫(kù)函數(shù)qsort排序函數(shù)為例,它的原型如下:

void qsort(void *base,size_t nmemb,size_t size , int(*compar)(const void *,const void *));

看起來很復(fù)雜對(duì)不對(duì)?拆開來看如下:

void qsort(void *base, size_t nmemb, size_t size, );

拿掉第四個(gè)參數(shù)后,很容易理解,它是一個(gè)無返回值的函數(shù),接受4個(gè)參數(shù),第一個(gè)是void*類型,代表原始數(shù)組,第二個(gè)是size_t類型,代表數(shù)據(jù)數(shù)量,第三個(gè)是size_t類型,代表單個(gè)數(shù)據(jù)占用空間大小,而第四個(gè)參數(shù)是函數(shù)指針。這第四個(gè)參數(shù),即函數(shù)指針指向的是什么類型呢?

int(*compar)(const void *,const void *)

很顯然,這是一個(gè)接受兩個(gè)const void*類型入?yún)ⅲ祷刂禐閕nt的函數(shù)指針。
到這里也就很清楚了。這個(gè)參數(shù)告訴qsort,應(yīng)該使用哪個(gè)函數(shù)來比較元素,即只要我們告訴qsort比較大小的規(guī)則,它就可以幫我們對(duì)任意數(shù)據(jù)類型的數(shù)組進(jìn)行排序。

在這里函數(shù)指針作為了參數(shù),而他同樣可以作為返回值,創(chuàng)建數(shù)組,作為結(jié)構(gòu)體成員變量等等,它們的具體應(yīng)用我們?cè)诤竺娴奈恼轮袝?huì)介紹,本文不作展開。本文只介紹一個(gè)簡(jiǎn)單實(shí)例。

實(shí)例介紹

我們通過一個(gè)實(shí)例來看函數(shù)指針怎么使用。假設(shè)有一學(xué)生信息,需要按照學(xué)生成績(jī)進(jìn)行排序,該如何處理呢?

#include <stdio.h>
#include <stdlib.h>
#define STU_NAME_LEN 16
/*學(xué)生信息*/
typedef struct student_tag
{
    char name[STU_NAME_LEN];  //學(xué)生姓名
    unsigned int id;          //學(xué)生學(xué)號(hào)
    int score;                //學(xué)生成績(jī)
}student_t;
int studentCompare(const void *stu1,const void *stu2)
{
  /*強(qiáng)轉(zhuǎn)成需要比較的數(shù)據(jù)結(jié)構(gòu)*/
    student_t *value1 = (student_t*)stu1;
    student_t *value2 = (student_t*)stu2;
    return value1->score-value2->score;
}
int main(void)
{
    /*創(chuàng)建三個(gè)學(xué)生信息*/
    student_t stu1 = {'one',1,99};
    student_t stu2 = {'two',2,77};
    student_t stu3 = {'three',3,88};

    student_t stu[] = {stu1,stu2,stu3};

    /*排序,將studentCompare作為參數(shù)傳入qsort*/
    qsort((void*)stu,3,sizeof(student_t),studentCompare);
    int loop = 0;

    /**遍歷輸出*/
    for(loop = 0; loop < 3;loop++)
    {
        printf('name:%s,id:%u,score:%d',stu[loop].name,stu[loop].id,stu[loop].score);
    }
    return 0;
}

我們創(chuàng)建了一個(gè)學(xué)生信息結(jié)構(gòu),結(jié)構(gòu)成員包括名字,學(xué)號(hào)和成績(jī)。main函數(shù)中創(chuàng)建了一個(gè)包含三個(gè)學(xué)生信息的數(shù)組,并使用qsort函數(shù)對(duì)數(shù)組按照學(xué)生成績(jī)進(jìn)行排序。qsort函數(shù)第四個(gè)參數(shù)是函數(shù)指針,因此我們需要傳入一個(gè)函數(shù)指針,并且這個(gè)函數(shù)指針的入?yún)⑹莄ont void *類型,返回值為int。我們通過前面的學(xué)習(xí)知道了函數(shù)名本身就是指針,因此只需要將我們自己實(shí)現(xiàn)的studentCompare作為參數(shù)傳入即可。

最終運(yùn)行結(jié)果如下:

name:two,id:2,score:77
name:three,id:3,score:88
name:one,id:1,score:99

可以看到,最終學(xué)生信息按照分?jǐn)?shù)從低到高輸出。

總結(jié)

本文介紹了函數(shù)指針的聲明和使用。更多使用將在后面的文章介紹,本文總結(jié)如下:

  • 函數(shù)指針與其他指針類型無本質(zhì)差異,不過它指向的是函數(shù)的地址罷了。

  • 聲明函數(shù)指針需要指明函數(shù)的返回類型和形參類型。

  • 函數(shù)名在被使用時(shí)總是由編譯器把它轉(zhuǎn)換為函數(shù)指針。

  • 要想聲明函數(shù)指針,只需寫出函數(shù)原型,然后將函數(shù)名用(*fp)代替即可。這里fp是聲明的函數(shù)指針變量。

  • typedef中聲明的類型在變量名的位置出現(xiàn)。

思考

下面的聲明如何理解

void (*signal(int sig, void(*func)(int)))(int);
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
深入理解C語(yǔ)言中的函數(shù)聲明
C基礎(chǔ)—指針/指針與動(dòng)態(tài)變量/指針與數(shù)組/指針與函數(shù)
typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
詳解C/C++函數(shù)指針聲明
typedef定義函數(shù)類型
typedef 定義函數(shù)指針 typedef void (*CALLBACK)(int a,int b)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服