曾被 int * (* (*fp1) (int) ) [10]; 這類宣告搞得頭暈目眩?本文由淺入深教你破解複雜 C/C++ 宣告:從基本宣告、const 修飾符、typedef、函數指標,到終極武器——右左法則。注意:複雜宣告非良好程式風格,本文僅教導理解技巧。建議 1024×768 以上解析度閱讀。
核心原則:以變數名為中心,向外擴展閱讀。
int n; → 「n 是 int」int *p; → 「p 是 int*」建議寫法:int *p; (星號貼變數),避免 int* p, q; 誤以為 q 也是指標(實則 q 是 int)。char **argv; → 「argv 是指向 char* 的指標」int RollNum[30][4]; int (*p)[4] = RollNum; int *q[5];
p:指向「4 個 int 陣列」的指標q:5 個「int 指標」的陣列* 與 &:
int **p1; → int 指標的指標int *&p2; → int 指標的參考int &*p3; → 錯誤:參考的指標不合法int &&p4; → 錯誤:參考的參考不合法const 位置決定修飾對象:
const int n = 5; / int const m = 10; → 同為「const int」(整數常數),推薦前者。const int *p; / int const *q; → 「指向 const int 的指標」(*p 不可改)int * const r = &n; → 「const 指標,指向 int」 (r 不可改,*p 可改)const int * const p = &n; → 「const 指標,指向 const int」 (雙重不可改)| 宣告 | 含義 |
|---|---|
char **p1; | 指向 char 指標的指標 |
const char **p2; | 指向 const char 指標的指標 |
char * const *p3; | 指向 char const 指標的指標 |
const char * const *p4; | 指向 const char const 指標的指標 |
char ** const p5; | const 指標,指向 char 指標 |
const char ** const p6; | const 指標,指向 const char 指標 |
char * const * const p7; | const 指標,指向 char const 指標 |
const char * const * const p8; | const 指標,指向 const char const 指標 |
typedef 可建立型別別名,解決「* 僅能修飾變數不能修飾型別」的問題:
typedef char * PCHAR;
PCHAR p, q; // p、q 皆為 char*
typedef char * a; // a: char*
typedef a b(); // b: 回傳 char* 的函數
typedef b *c; // c: 指向 b 類型函數的指標
typedef c d(); // d: 回傳 c 的函數
typedef d *e; // e: 指向 d 類型函數的指標
e var[10]; // var: 10 個 e 的陣列
typedef struct tagPOINT {
int x, y;
} POINT;
POINT p; // C/C++ 通用,C 中免寫 struct
最易混淆的宣告類型。範例:
int (*p)(char); → 指向「接受 char、回傳 int 的函數」的指標char ** (*p)(float, float); → 指向「接受兩 float、回傳 char** 的函數」的指標void * (*a[5])(char * const, char * const); → 5 個指標的陣列,各指向「接受兩 const char*、回傳 void*」的函數規則:從變數名開始,向右讀,再向左讀。遇到括號反向。括號內讀完跳出。重複直到結束。
修正:起點必須是變數名,非最內層括號。
int * (* (*fp1) (int) ) [10];
fp1),向左見 * → 指標(int) → 接受 int 參數的函數* → 回傳指標[10] → 10 元素陣列* → 指標int → int 型別結論:fp1 是函數指標,該函數接受 int,回傳指向「10 個指標陣列」的指標。
int *( *( *arr[5])())();
arr[5] → 5 元素陣列* → 指標() → 無參函數* → 回傳指標() → 無參函數* → 回傳指標int → int結論:arr 是 5 元素陣列,元素為指標,指向「無參函數」,該函數回傳指標,指向「無參函數」,該函數回傳指標,指向 int。
| 宣告 | 右左法則速讀結果 |
|---|---|
float ( * ( *b()) [] )(); | b: 函數,回傳指標,指向陣列,陣列元素為指標,指向回傳 float 的函數 |
void * ( *c) ( char, int (*)()); | c: 指標,指向函數,接受 char 與函數指標(無參、回傳 int),回傳 void* |
void ** (*d) (int &, char **(*)(char *, char **)); | d: 指標,指向函數,接受 int& 與函數指標(接受 char*、char**、回傳 char**),回傳 void** |
float ( * ( * e[10]) (int &) ) [5]; | e: 10 元素陣列,元素為指標,指向函數(接受 int&、回傳指向 5 float 陣列的指標) |