前面咱們講解了指針數組、二維數組指針、函數指針等幾種較爲複雜的指針,它們的定義形式分別是:html
- int *p1[6]; //指針數組
- int *(p2[6]); //指針數組,和上面的形式等價
- int (*p3)[6]; //二維數組指針
- int (*p4)(int, int); //函數指針
我相信大部分初學者對上面幾種形式的指針都很是迷惑,不知道該從哪裏入手去理解,爲何 p一、p2 是數組,而 p3 倒是指針呢,它們僅僅是一個括號的區別。
指針是C語言中最強大最靈活的一部分,也是最難以理解的一部分,它是學習C語言的重點,沒有學會指針就無從談學會C語言。若是你們以爲上面幾種形式的指針還能勉強接受,那麼下面兩個指針是否是讓人抓狂呢?數組
- char *(* c[10])(int **p);
- int (*(*(*pfunc)(int *))[5])(int *);
只要找到了竅門,再複雜的指針也是能夠理解的,這節咱們就來戳破這層窗戶紙!
C語言標準規定,對於一個符號的定義,編譯器老是從它的名字開始讀取,而後按照優先級順序依次解析。對,從名字開始,不是從開頭也不是從末尾,這是理解複雜指針的關鍵!
對於初學者,有幾種運算符的優先級很是容易混淆,它們的優先級從高到低依次是:函數
- 定義中被括號
( )
括起來的那部分。 - 後綴操做符:括號
( )
表示這是一個函數,方括號[ ]
表示這是一個數組。 - 前綴操做符:星號
*
表示「指向xxx的指針」。
學會了「絕殺招式」,接下來咱們就由淺入深,逐個擊破上面的指針定義。學習
1) int *p1[6];
從 p1 開始理解,它的左邊是 *,右邊是 [ ],[ ] 的優先級高於 *,因此編譯器先解析p1[6]
,p1 首先是一個擁有 6 個元素的數組,而後再解析int *
,它用來講明數組元素的類型。從總體上講,p1 是一個擁有 6 個 int * 元素的數組,也即指針數組。spa
2) int (*p3)[6];
從 p3 開始理解,( ) 的優先級最高,編譯器先解析(*p3)
,p3 首先是一個指針,剩下的int [6]
是 p3 指向的數據的類型,它是一個擁有 6 個元素的一維數組。從總體上講,p3 是一個指向擁有 6 個 int 元素數組的指針,也即二維數組指針。.net
爲了可以經過指針來遍歷數組元素,在定義數組指針時須要進行降維處理,例如三維數組指針實際指向的數據類型是二維數組,二維數組指針實際指向的數據類型是一維數組,一維數組指針實際指向的是一個基本類型;在表達式中,數組名也會進行一樣的轉換(降低一維)。
3) int (*p4)(int, int);
從 p4 開始理解,( ) 的優先級最高,編譯器先解析(*p4)
,p4 首先是一個指針,它後邊的 ( ) 說明 p4 指向的是一個函數,括號中的int, int
是參數列表,開頭的int
用來講明函數的返回值類型。總體來看,p4 是一個指向原型爲int func(int, int);
的函數的指針。指針
4) char *(* c[10])(int **p);
這個定義有兩個名字,分別是 c 和 p,乍看起來 p 是指針變量的名字,不過很遺憾這是錯誤的。若是 p 是指針變量名,c[10]
這種寫法就又定義了一個新的名字,這讓人匪夷所思。
以 c 做爲變量的名字,先來看括號內部(綠色粗體):code
char * (* c[10]) (int **p);htm
[ ] 的優先級高於 *,編譯器先解析c[10]
,c 首先是一個數組,它前面的*
代表每一個數組元素都是一個指針,只是還不知道指向什麼類型的數據。總體上來看,(* c[10])
說明 c 是一個指針數組,只是指針指向的數據類型還沒有肯定。
跳出括號,根據優先級規則(() 的優先級高於 *)應該先看右邊(紅色粗體):blog
char * (* c[10]) (int **p);
( )
說明是一個函數,int **p
是函數參數。
再看左邊(橘黃色粗體):
char * (* c[10]) (int **p);
char *
是函數的返回值類型。
從總體上看,咱們能夠將定義分紅兩部分:
char * (* c[10]) (int **p);
綠色粗體代表 c 是一個指針數組,紅色粗體代表指針指向的數據類型,合起來就是:c 是一個擁有 10 個元素的指針數組,每一個指針指向一個原型爲char *func(int **p);
的函數。
5) int (*(*(*pfunc)(int *))[5])(int *);
從 pfunc 開始理解,先看括號內部(綠色粗體):
int (*(*(*pfunc)(int *))[5])(int *);
pfunc 是一個指針。
跳出括號,看它的兩邊(紅色粗體):
int (*(*(*pfunc)(int *))[5])(int *);
根據優先級規則應該先看右邊的(int *)
,它代表這是一個函數,int *
是參數列表。再看左邊的*
,它代表函數的返回值是一個指針,只是指針指向的數據類型還沒有肯定。
將上面的兩部分合成一個總體,以下面的藍色粗體所示,它代表 pfunc 是一個指向函數的指針,如今函數的參數列表肯定了,也知道返回值是一個指針了(只是不知道它指向什麼類型的數據)。
int (* (*(*pfunc)(int *)) [5])(int *);
藍色粗體之外的部分,就用來講明函數返回什麼類型的指針。
咱們接着分析,再向外跳一層括號(紅色粗體):
int (* (*(*pfunc)(int *)) [5])(int *);
[ ] 的優先級高於 *,先看右邊,[5] 表示這是一個數組,再看左邊,* 表示數組的每一個元素都是指針。也就是說,* [5] 是一個指針數組,函數返回的指針就指向這樣一個數組。
那麼,指針數組中的指針又指向什麼類型的數據呢?再向外跳一層括號(橘黃色粗體):
int (* (*(*pfunc)(int *)) [5]) (int *);
先看橘黃色部分的右邊,它是一個函數,再看左邊,它是函數的返回值類型。也就是說,指針數組中的指針指向原型爲int func(int *);
的函數。
將上面的三部分合起來就是:pfunc 是一個函數指針(藍色部分),該函數的返回值是一個指針,它指向一個指針數組(紅色部分),指針數組中的指針指向原型爲int func(int *);
的函數(橘黃色部分)。