在c語言中,一個聲明你是否都能很明確的知道他是什麼類型?
它肯定是兩大類型:變數或者函數。但需要更具體點:
1、變數分為:非指標類型的變數、指向變數的指標類型的變數(這個指標變數指向的可能是非指標變數,也可能是指標變數)、指向函數的指標類型的變數
2、函數:返回非指標類型的函數、返回指標變數的函數
所以在c語言裡面,一個聲明你需要清晰的知道該聲明是上面綜述的5種類型中的哪一種類型。要怎麼進行分析、要根據什麼來進行分析。
下面有幾個聲明,請先自己分析一下。
---------------------------------------------------------------
int p;
int *p;
int p[3];
int *p[3];
int (*p)[3];
int **p;
int p(int);
int (*p)(int);
int *(*p(int))[3];
int*(*ptr)[4];
---------------------------------------------------------------
要如何分析呢?
編譯器當然是要根據某種規範來解析這些聲明:
A 聲明從它的名字開始讀取,然後按照優先順序順序依次讀取;
B 優先順序從高到低依次是:
B.1 聲明中被括弧括起來的那部分
B.2 尾碼操作符;
括弧()表示這是一個函數,而
方括弧[] 表示這是一個數組。
B.3 首碼操作符; 星號 * 表示“指向...的指標”。
C 如果const 和 ( 或 ) volatile 關鍵字的後面緊跟類型說明符 (如 int, long等),那麼它作用於類型說明符。在其他情況下,const 和 ( 或 ) volatile 關鍵字作用於它左邊緊鄰的指標星號。
根據以上的紅色字部門的規範我們來一一進行解析
int p;
//這裡的p是最簡單的非指標類型的變數
int *p;
//這裡的p是最簡單的指標類型的變數
int p[3];
//1、根據原則A先讀取p
//2、根據原則B.1,發現除尾碼之外並無括弧
//3、根據原則B.2,發現p有尾碼[3]所以這是一個數群組類型的非指標類型的變數
//4、最後再與類型int結合,所以p是一個int類型的陣列變數
int *p[3];
//1、根據原則A先讀取p
//2、根據原則B.1,發現除尾碼之外並無括弧
//3、根據原則B.2,發現有尾碼[3],說明P不是一個指標類型的變數,而是一個非指標類型的變數(陣列變數)
//4、這時你會想這數組是什麼類型的呢?
//把p[3]用q代替則聲明為:int * q,則說明q是一個int類型的指標,這裡說明p[3]的這個數組的類型是int指標類型即數組的元素是int類型指標
//這也就是指標數組
int (*p)[3];
//1、根據原則A讀取p
//2、根據原則B.1,說明p是一個指標,那麼p所指向的類型是什麼呢?把*p用q代替,則聲明為int q[3]
//3、根據原則B.2,發現q有尾碼[3],則q與[3]結合,再與int 結合,說明q是一個數組。所以p指標所指向的類型為int類型的數組
//這即是數組指標
int **p;
//1、根據原則A讀取p
//2、根據原則B.1,發現除尾碼之外並無括弧
//3、根據原則B.2,p並無括弧或者中括弧.
//4、p直接與其前面的第一個*結合,說明p是一個指標,該指標指向什麼呢?同理代替 int * q; q為int類型的指標,所以p指標指向的是int 類型的指標
int p(int);//這基礎的簡單的函式宣告
int (*p)(int);
//這裡就不具體再說明,編譯器先讀取到p,然後在由於小括弧的優先順序比較高,所以p與*結合,即p是一個指標那麼p指向什麼呢,同理代替,則聲明為:int q(int)
//所以p指向的是int q(int)類型的函數
int *(*p(int))[3];
//先讀取p,p與(int)結合,說明p是一個參數是int類型的函數,那麼該函數返回的類型是什麼呢,同理代替,則聲明為: int*(*q)[3];從這裡可以看出q與*結合,則可以看出q是一 //個指標,那麼q指標指向的是什麼呢?同理代替,則聲明為:int *r[3],從上面知道 int * r[3]是一個指標數組。由此可以看出這是一個傳回型別為指標的函數的聲明,返回的指標所指向的還是一個指標類型的變數,該類型的指標指向的是一個指標數組.
int*(*ptr)[4];
//ptr先與*結合,所以ptr是一個指標,該指標指向什麼呢,同理代替,聲明為:int *q[4], 所以ptr指標指向的是一個指標數組.
直到這裡,已把開頭說的聲明的五種類型都包括了。
你 。。還不明白嗎