int *p[n]; int (*p)[n];

在編程中,會遇到這樣的情況:
int *p[n];
int (*p)[n];
還有一種情況是聲明函數:
int *p();
int (*p)();
這些分別表示什麼意思呢?


表面上看這些問題,好像是指針,但是,如何來正確判斷這幾個定義,需要我們首先有運算符優先級的概念。
  
在c語言中,[]和()的優先級比星號(星號的名字叫做“指針運算符”)要高,所以,在這幾個聲明中,先看[]和()。
同時,這兩個括號的運算符的結合順序,是從左到右的。因此,int *p[n],實際上相當與int *(p[n]),也就是(int *)(p[n])。
讓我們來逐步分析:
(int *)(p[n])首先是一個數組(比如,把int *換爲int,就是“元素是整形數據的數組”。那麼,換爲int*,就是“元素是指向整形數據的指針的數組”)。


再看另一個:
int (*p)[n]改變了自然的運算符的優先級,相當於(int)((*p)[n])。一有指針就頭疼,我們把指針先替換掉,就是int a[n],是一個n維數組,數組首地址(也就是數組名)是a。
那麼,int (*p)[n]也是一個n維數組,但是這個數組的首地址是*p,也就是說,p指向的內容,是一個數組的首地址。
那麼,p就是指向一個數組的指針,這個數組中的元素都是int。實際上,p相當於是一個二維指針。


同樣的道理,可以分析 int *p();和int (*p)();

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
注意,這裏我們對於星號賦予了不同的含義。闡述如下:
int a;
int *p=&a;//定義指向a的指針p
*p = 10;

這裏,第二行中的星號表示“定義了一個指向int型數據的指針,爲什麼呢?因爲實際上,*  相當於  (int *),定義了一個指向int型數據的指針。
第三行的星號,表示p所指向的數據,因爲星號前面並沒有諸如int void char等表示類型的東西。

換句話說,如果星號前面有表示類型的int,void等數據,我們認爲,這裏的星號的意義,是“定義了一個指針”
如果星號前面沒有表示類型的東西,那麼我們認爲,這裏的星號的意義,是”該指針所指向的數據“。

那麼,讓我們回頭看看int *p[n]和int (*p)[n]。
由於我們剛剛把優先級分析過,那麼前者相當於(int *)(p[n]),後者相當於 int ((*p)[n])
根據剛纔我們的關於星號的結論,前者表示定義了一個長度爲n的數組(p[n]),每個元素都是指向int數據的指針(int *)。

後者表示,定義了一個int a[n]。這裏大家都明白,然後把a換成*p,於是意思就是,p是一個指針,其指向的內容(也就是*p)是一個數組的首地址(就是a)

下面對函數指針進行說明:

(一) 用函數指針變量調用函數


  可以用指針變量指向整形變量、字符串、數組、結構體、也可以指向一個函數。一個函數在編譯時被分配一個入口地址。這個入口地址就稱爲函數指針。可以用一個指針變量指向函數,然後通過該指針變量調用此函數。用簡單的數值比較爲例:




 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 
 4  int main()
 5 {
 6     int max(int,int);
 7     int (*p)(int,int);
 8     int a,b,c;
 9     p = max;
10     scanf("%d,%d",&a,&b);
11     c = (*p)(a,b);
12     printf("a=%d,b=%d,max=%d\n",a,b,c);
13     return 0;
14 }
15 
16 int max(int x,int y)
17 {
18     int z;
19     if(x>y) z = x;
20     else z = y;
21     return(z);
22 }


  main函數中的" c = max(a,b); " 包括了一次函數的調用。每一個函數都佔用一段內存單元。因此,可以用一個指針變量指向一個函數,通過指針變量來訪問它指向的函數。


  第7行:int (*p)( int,int );  用來定義 p 是一個指向函數的指針變量,該函數有兩個整形參數,函數值爲整形。注意 *p 兩側的括號不可省略,表示 p 先與 * 結合,是指針變量,然後再與後面的 ( ) 結合,表示此指針變量指向函數,這個函數值 (即函數的返回值) 是整形的。如果寫成 int *p ( int,int ) ,由於( )的優先級高於 *,它就成了聲明一個函數P( 這個函數的返回值是指向整形變量的指針)。


  賦值語句 p = max ; 作用是將函數 max 的入口地址賦給指針變量p。和數組名代表數組首元素地址類似,函數名代表該函數的入口地址。這時 p 就是指向函數 max 的指針變量,此時 p 和 max都指向函數開頭,調用 *p 就是調用 max 函數。但是p作爲指向函數的指針變量,它只能指向函數入口處而不可能指向函數中間的某一處指令處,因此不能用 *(p + 1)來表示指向下一條指令。


  注意:


  (1) 指向函數的指針變量的一般定義形式爲:


  數據類型 (*指針變量名)(函數參數列表)


  這裏數據類型就是函數返回值的類型


  (2) int (* p) ( int,int ); 它只是定義一個指向函數的指針變量 p, 它不是固定指向哪一個函數的,而只是表示定義這樣一個類型的變量,它是專門用來存放函數的入口地址的。在程序中把哪一函數(該函數的值應該是整形的,且有兩個整形參數)的地址賦給它,他就指向哪一個函數。在一個函數中,一個函數指針變量可以先後指向同類型的不同函數。


  (3) p = max; 在給函數指針變量賦值時,只需給出函數名而不必給出函數參數,因爲是將函數的入口地址賦給 p ,而不涉及 實參和形參的結合問題,不能寫成 p = max(a,b);


  (4) c = (*p)(a,b) 在函數調用時,只需將( *p ) 代替函數名即可,後面實參依舊。


  (5) 對於指向函數的指針變量,像 p++ ,p+n.....是無意義的。


  (二) 用指向函數的指針作爲函數參數


  函數指針變量通常的用途之一就是把指針作爲參數傳遞到其他函數。


  函數的參數可以是變量、指向變量的指針變量、數組名、指向數組的指針變量,也可以是指向函數的指針也可以作爲參數,以實現函數地址的傳遞,這樣就能夠在被調用的函數中使用實參函數。


  void  sub ( int ( *x1) (int), int (*x2) (int,int) )


    {


      int a,b,i,j;


      a = (*x1)(i);      /* 調用 f1 函數 */


      b = (*x2)(i)(j);    /* 調用 f2 函數 */


    }


  如果實參爲兩個 函數名 f1 和 f2. 在函數首部定義x1、x2爲函數指針變量,x1指向的函數有一個整形形參,x2指向的函數有兩個形參。i 和 j 是函數f1 和 f2所要的參數。函數sub的形參 x1、x2(指針變量)在函數 sub 未被調用時並不佔用內存單元,也不指向任何函數。在sub被調用時,把實參函數 f1 和 f2的入口地址傳給形式指針變量 x1 和 x2.


  既然在 sub 函數中要調用 f1 和 f2 函數,爲什麼不直接調用f1 和 f2而要用函數指針變量呢? 確實,如果只是用到f1 和 f2 函數,完全可以在sub函數中直接調用f1 和 f2,而不必設指針變量 x1 和 x2。 但是,如果在每次調用sub時,調用的函數不是固定的,下次是f3 和 f4,再是f5 和 f6...這時用指針變量就比較方便了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章