C++中陣列指標和函式指標
陣列的型別
在往常的程式設計中,我們都知道陣列的名字就代表陣列第一個元素的地址,這總是讓我們對陣列的型別產生誤解。比如對於這條指令int a[10] = {0};
,因為當引用陣列名 a 的時候往往相當於引用陣列第一個元素 a[0] 的地址,所以我們可能會誤認為陣列 a 的型別是 int *
,然而陣列名 a 代表的卻是整個陣列,他的型別並不是簡單的 int *
,那陣列 a 的型別到底是什麼呢?我們都知道一個數組的兩個特點是儲存元素的型別和陣列的大小,那麼很容易的想到陣列 a 的型別便是 int [10]
啦。對於如下兩句程式碼,我們可以用 clang 生成 AST 觀察其型別的特徵:
int a[10] = {0};
int *b = a;
可以看到在第一個 VarDecl 節點,明確的指出了陣列 a 是 int [10]
的型別,而在第二個 VarDecl 節點,為了用 a 初始化變數 b ,首先是通過隱式轉換,將 int [10]
型別轉換為 int *
後再賦值給變數 b ,更進一步說明了陣列 a 的型別就是 int [10]
。由此我們可以總結出任意陣列的型別並不簡單的就是其元素指標的型別,而是形式於 element-type [array-size]
。
陣列指標怎麼寫
既然陣列是有其獨特的型別的話,那麼我們也可以宣告且定義一個指向某種陣列的指標。如下:
int arr[ 10] = {0}; // 定義一個包含10個int型元素的陣列
int *p1[10]; // 陣列名和*之間沒有用括號括起來,聲明瞭包含10個int*型元素的陣列p1
int (*p2)[10] = &arr; // 陣列名和*之間用括號括起來,聲明瞭一個數組指標p2,其指向型別為int[10]的陣列,那麼p2的型別就是int(*)[10]
宣告返回一個數組指標的函式
因為函式不能用來返回一個數組,所以我們可以返回一個數組指標。最直接的方式是直接宣告一個返回陣列指標的函式,如下 func 函式返回一個 int (*) [10] 型陣列指標:
int (*func(int a, int b))[10 ];
我們可以通過從內向外的方式來理解這個宣告,
func(int a, int b)
代表呼叫 func 函式時要兩個 int 型別的實參;(*func(int a, int b))
代表我們可以對函式呼叫的結果解引用;(*func(int a, int b))[10]
代表解引用 func 的呼叫將得到一個大小是 10 的陣列;int (*func(int a, int b))[10]
代表陣列中的元素是 int 型別。所以 func 函式的返回值型別是 int(*)[10]。
也可以通過 typedef 或 using 來宣告類型別名,使得函式返回值看起來更加清楚,如下 func 函式返回一個 int (*) [10] 型陣列指標:
typedef int arrT[10]; //arrT是一個類型別名,表示的型別是含有10個整數的陣列
using arrT = int[10]; //arrT的等價宣告
arrT* func(int a, int b); //func函式的返回值的型別int(*)[10]
在C++11中,可以使用尾置返回型別,使用該特性對於上述 func 函式等價宣告如下:
auto func(int a, int b) -> int(*)[10];
函式的型別
宣告一個數組的時候,會用一個變數來儲存,理解陣列有型別似乎很簡單,但是函式的型別應該理解呢?對於一個函式,我們可以把他的引數看成輸入,返回值看成輸出,這樣函式與外界互動的方式就由其引數和返回值決定,所以函式的型別也由其接收引數的型別和返回值的型別來決定。比如,對於上面直接的 func 函式的宣告,可以輸出語法樹結構來看其函式的型別:
int (*func(int a, int b))[10];
可以看到,func 函式的型別是 int (*(int, int))[10]
,最內層括號代表其接受的引數型別是兩個 int ,括號外層代表其返回值型別是 int (*)[10]。
函式指標怎麼寫
既然函式也是有型別的,那麼自然可以定義函式指標,函式指標也是指標,其指向的是某個具體函式或者為空。如以下例子:
//funcP前面有一個*,所以可以解引用,所以funcP是一個指標;右側是形參列表,表示funcP指向的是函式;而再觀察其餘部分,可知所指向函式的返回型別是int(*)[10]
int (*(*funcP)(int a, int b))[10];
clang 輸出語法樹:
很明顯對於 funcP 是一個變數宣告,而不是函式宣告,funcP 是一個函式指標,其指向的函式型別為 int (*(int, int))[10]
,所以可以初始化 funcP 指向上述所說的 func 函式。
int (*func(int a, int b))[10];
int (*(*funcP)(int a, int b))[10] = func;
參考資料:《C++Prime》