程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 函數指針與指針函數的進修總結

函數指針與指針函數的進修總結

編輯:關於C++

函數指針與指針函數的進修總結。本站提示廣大學習愛好者:(函數指針與指針函數的進修總結)文章只能為提供參考,不一定能成為您想要的結果。以下是函數指針與指針函數的進修總結正文


函數指針是指向函數的指針,指針函數是指一個函數的前往值是一個指針,但上面的幾道題照樣感到很困惑。列位可否講的具體點呢?

(1) float(**def)[10]   def是甚麼?
(2) double*(*gh)[10]   gh是甚麼?
(3) double(*f[10])()   f是甚麼?
(4) int*((*b)[10])    b是甚麼?如許老感到有點亂,有甚麼訣竅可以記得並懂得的清晰一點麼?

======================
解答:
  
(1) def是一個指針, 指向的對象也是一個指針, 指向的指針終究指向的是10個float組成的數組.

(2) gh是指針, 指向的是10個元素組成的數組, 數組的元素是double*類型的指針.

(3) f是10個元素組成的數組, 每一個元素是指針, 指針指向的是函數, 函數類型為無參數且前往值為double. 上面要講的訣竅的例子跟這個很相似.

(4) b是指針,指向的是10個元素組成的數組, 數組元素為int*類型的指針.

訣竅以下:
假如我們碰著龐雜的類型聲明,該若何解析它?例如:
char (*a[3])(int);
a究竟被聲明為何東東?指針?數組?照樣函數?

剖析時,從a 最接近(按運算符優先級)處開端。我們看到a最接近符號是[ ]——留意:*比[ ]的優先級低。a後既然有[ ],那末a是數組,並且是包括3個元素的數組。

那這個數組的每一個元素是甚麼類型呢?固然數組a只含有a[0]、a[1]、a[2]三個元素,a[3]現實上曾經越界,但在剖析數組a的元素的類型時,我們正好須要情勢上的元素a[3]。曉得了a[3]的類型,就曉得了a的元素的類型。 a[3]是甚麼類型?是指針,由於它的後面有*. 由此可知,數組a的元素是指針。

光說是指針還不敷。關於指針,必需說出它指向的東東是甚麼類型。它指向的東東是甚麼,就看*a[3]是甚麼(a[3]是指針,它指向的東東固然是*a[3])了。持續按優先級不雅察,我們看到*a[3]前面有小括號,所以可以確定*a[3]是函數。即數組a的元素是指向函數的指針。

指向的是甚麼類型的函數?這很顯著,是入參為int、前往值為char的類型的函數。
至此解析終了。
按上述辦法,再龐雜的也能夠一步步解析出來。

就像習武不是為了打人而是為了防身一樣,我們懂得上述辦法是為了看懂他人寫的龐雜聲明,而不是為了在理論中本身去結構這類龐雜的東東。其實須要龐雜聲明時,可以用typedef替換一部門。例如下面語句可改成兩句:
typedef char (*FUN_PTR)(int);
FUN_PTR a[3];
如許就清楚多了。
另外,下面的剖析辦法還讓我們對某些器械的實質加倍清晰。好比,n維數組的實質都是一維數組。看個詳細的例子:
int a[3][5];
這句聲明的是一個包括3個元素的一維數組,其每一個元素又是一個由5個int數組成的數組。我們不克不及懂得為:a是一個包括5個元素的一維數組,其每一個元素又是一個由3個int數組成的數組。為何?照樣按下面的辦法剖析,這裡從略。

有的書上或網上供給"向右看,向左看"的辦法, 其實缺少通用性, 好比它不實用於對多維數組實質的剖析. 並且這類辦法掩飾了實質. 實質應當是按下面所講的,依據運算符優先級逐層剝開.

  ==============================================================================
 
1、指針函數
當一個函數聲明其前往值為一個指針時,現實上就是前往一個地址給挪用函數,以用於須要指針或地址的表達式中。
格局:
類型解釋符 * 函數名(參數)
固然了,因為前往的是一個地址,所以類型解釋符普通都是int。
例如:int *GetDate();
      int * aaa(int,int);
函數前往的是一個地址值,常常應用在前往數組的某一元素地址上。

        int * GetDate(int wk,int dy);
        main()
        {
            int wk,dy;
            do
            {
                printf(Enter week(1-5)day(1-7)/n);
                scanf(%d%d,&wk,&dy);
            }
            while(wk<1||wk>5||dy<1||dy>7);
            printf(%d/n,*GetDate(wk,dy));
        }

        int * GetDate(int wk,int dy)
        {
            static int calendar[5][7]=
            {
               {1,2,3,4,5,6,7},
               {8,9,10,11,12,13,14},
               {15,16,17,18,19,20,21},
               {22,23,24,25,26,27,28},
               {29,30,31,-1}
            };
            return &calendar[wk-1][dy-1];
        }
       
法式應當是很好懂得的,子函數前往的是數組某元素的地址。輸入的是這個地址裡的值。

2、函數指針
指向函數的指針包括了函數的地址,可以經由過程它來挪用函數。聲明格局以下:
類型解釋符 (*函數名)(參數)
其實這裡不克不及稱為函數名,應當叫做指針的變量名。這個特別的指針指向一個前往整型值的函數。指針的聲明必需和它指向函數的聲明堅持分歧。
指針名和指針運算符裡面的括號轉變了默許的運算符優先級。假如沒有圓括號,就釀成了一個前往整型指針的函數的原型聲明。
例如:
    void (*fptr)();
把函數的地址賦值給函數指針,可以采取上面兩種情勢:
        fptr=&Function;
        fptr=Function;
取地址運算符&不是必須的,由於單單一個函數標識符就標號表現了它的地址,假如是函數挪用,還必需包括一個圓括號括起來的參數表。
可以采取以下兩種方法來經由過程指針挪用函數:
        x=(*fptr)();
        x=fptr();
第二種格局看上去和函數挪用無異。然則有些法式員偏向於應用第一種格局,由於它明白指出是經由過程指針而非函數名來挪用函數的。上面舉一個例子:

        void (*funcp)();
        void FileFunc(),EditFunc();
        main()
        {
            funcp=FileFunc;
            (*funcp)();
            funcp=EditFunc;
            (*funcp)();
        }

        void FileFunc()
        {
            printf("FileFunc/n");
        }

        void EditFunc()
        {
            printf("EditFunc/n");
        }

法式輸入為:
    FileFunc
    EditFunc

3、指針的指針
指針的指針看上去有些使人隱晦。它們的聲明有兩個星號。例如:
        char ** cp;
假如有三個星號,那就是指針的指針的指針,四個星號就是指針的指針的指針的指針,順次類推。
當你熟習了簡略的例子今後,便可以敷衍龐雜的情形了。固然,現實法式中,普通也只用到二級指針,三個星號不罕見,更別說四個星號了。
指針的指針須要用到指針的地址。
        char c='A';
        char *p=&c;
        char **cp=&p;
經由過程指針的指針,不只可以拜訪它指向的指針,還可以拜訪它指向的指針所指向的數據。上面就是幾個如許的例子:
        char *p1=*cp;   // (&c)
        char c1=**cp;
你能夠想曉得如許的構造有甚麼用?應用指針的指針可以許可被挪用函數修正部分指針變量和處置指針數組。

        void FindCredit(int **);
        main()
        {
            int vals[]={7,6,5,-4,3,2,1,0};
            int *fp=vals;
            FindCredit(&fp);
            printf(%d/n,*fp);
        }

        void FindCredit(int ** fpp)
        {
            while(**fpp!=0)
            if(**fpp<0) break;
            else (*fpp)++;
        }

起首用一個數組的地址初始化指針fp,然後把該指針的地址作為實參傳遞給函數FindCredit()。FindCredit()函數經由過程表達式**fpp直接地獲得數組中的數據。

為遍歷數組以找到一個負值,FindCredit()函數停止自增運算的對象是挪用者的指向數組的指針,而不是它本身的指向挪用者指針的指針。語句(*fpp)++就是對形參指針指向的指針停止自增運算的。然則由於*運算符高於++運算符,所以圓括號在這裡是必需的,假如沒有圓括號,那末++運算符將感化於二重指針fpp上。

4、指向指針數組的指針
指針的指針另外一用法舊處置指針數組。有些法式員愛好用指針數組來取代多維數組,一個罕見的用法就是處置字符串。

        char *Names[]=
        {
             Bill,
             Sam,
             Jim,
             Paul,
             Charles,
             0
        };

        main()
        {
            char **nm=Names;
            while(*nm!=0) printf(%s/n,*nm++);
        }

先用字符型指針數組Names的地址來初始化指針nm。每次printf()的挪用都起首傳遞指針nm指向的字符型指針,然後對nm停止自增運算使其指向數組的下一個元素(照樣指針)。留意完成上述以為的語法為*nm++,它起首獲得指針指向的內容,然後使指針自增。

留意數組中的最初一個元素被初始化為0,while輪回以次來斷定能否到了數組末尾。具有零值的指針經常被用做輪回數組的終止符。法式員稱零值指針為空指針(NULL)。采取空指針作為終止符,在樹種增刪元素時,就不用修改遍歷數組的代碼,由於此時數組依然以空指針作為停止。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved