一、可能的組合:
(1)const char*p
(2)char const*p
(3)char *const p
(4)const char **p
(5)char const**p
(6)char *const *p
(7)char **const p
當然還有在(5)、(6)、(7)中再插入一個const的若干情況,不過分析了以上7中,其他的就可類推了!
二、理解助記法寶:
1、關鍵看const 修飾誰。
2、由於沒有 const *的運算,若出現 const * 的形式,則const實際上是修飾前面的。
比如:char const*p,由於沒有const*運算,則const實際上是修飾前面的char,因此char const*p等價於const char*p。也就是說上面7種情況中,(1)和(2)等價。 同理,(4)和(5)等價。在(6)中,由於沒有const*運算,const實際上修飾的是前面的char*,但不能在定義時轉換寫成 const(char *)*p,因為在定義是"()"是表示函數。
三、深入理解7種組合
程序 在執行時為其開辟的空間皆在內存(RAM)中,而RAM里的內存單元是可讀可寫 的;指針只是用來指定或定位要操作的數據的工具,只是用來讀寫RAM里內存單元的工作指針 。若對指針不加任何限定,程序中一個指針可以指向RAM中的任意位置(除了系統敏感區,如操作系統內核所在區域)並對其指向的內存單元進行讀和寫操作(由RAM的可讀可寫屬性決定);RAM里內存單元的可讀可寫屬性不會因為對工作指針的限定而變化(見下面的第4點),而所有對指針的各種const限定說白了只是對該指針 的 讀寫權限 (包括讀寫位置)進行了限定 。
(1)char *p:p是一個工作指針,可以用來對任意位置 (非系統敏感區域)進 行讀操作和寫操作 ,一次讀寫一個字節(char占一個字節)。
注: 特例: const char wang[]={"wang"}; char *p; p=wang; 是錯誤的。 所以char *p中的P不能指向常變量
(2)const char*p或者char const *p(因為沒有const*p運算,因此const修飾的還是前面的char):可以對任意位置(非系統敏感區域)進行“只讀” 操作。(“只讀”是相對於char *p來說所限定的內容)
(3)char *const p(const 修飾的是p):只能對“某個固定的位置” 進 行讀寫操作,並且在定義p時就必須初始化(因為在后面不能執行“p=..”的操作,因此就不能在后面初始化,因此只能在定義時初始化)。(“某個固定的位 置”是相對於char *p來說所限定的內容)
可以總結以上3點為:char *p中的指針p通常是”萬能”的工作指針 ,而(2)和(3)只是在(1)的基礎上加了些特定的限制 ,這些限制在程序中並不是必須的,只是為了防止程序員的粗心大意而產生事與願違的錯 誤。
另外,要明白“每塊內存空間都可有名字;每塊內存空間內容皆可變(除非有所限) ” 。比如函數里定義的char s[]="hello";事實上在進程的棧內存里開辟了6個變量共6個字節的空間,其中6個字符變量的名字分別為:s1[0]、s1[1]、 s1[2]、s1[3]、s1[4]、s1[5](內容是'\0')
{
待驗證 : 還有一個4字節的指針變量s 。不過s是“有所限制”的,屬於char *const類型,也就是前面說的 (3)這種情況,s一直指向s[0], 即(*s==s[0]=='h'),可以通過*s='k'來改變s所指向的 s[0]的值,但不能執行(char *h=“aaa”;s=h;)來對s另外賦值。
}
(4)上面的(2)和(3)只是對p進行限定,沒有也不能對p所指向的空間進行限定,對於"char s[]="hello";const char*p=s;" 雖然不能通過*(p+i)='x'或者p[i]='x'來修改數組元素s[0]~s[4]的值,但可以通過*(s+i)='x'或者s[i]='x'來修改原數組元素的值--RAM里內存單元的可讀可寫屬性不因對工作指針的限定而改變,而只會因對其本身的限定而改變。如const char c=‘A’,c是RAM里一個內存單元(8字節)的名字,該內存單元的內容只可讀,不可寫。
(5)const char **p或者char const**p :涉及兩個指針p和 *p。由於const修飾char ,對指針p沒有任何限定,對指針*p進行了上面情況(2)的限定。
(6)char *const *p:涉及兩個指針p和 *p。由於const修飾前面的char*,也就是對p所指向的內容*p進行了限定(也屬於前面的情況(2))。而對*p來說,由於不能通過"*p=..."來進行另外賦值,因此屬於前面的情況(3)的限定。
(7)char **const p : 涉及兩個指針p和 *p,const修飾p,對p進行上面情況(3)的限定,而對*p,沒有任何限定。
四、關於char **p 、const char **p的類型相容性問題
1、問題
char *p1;const *p2=p1;//合法
char **p1;const char**p2=p1;//不合法,會有警告warning: initialization from incompatible pointer type
char **p1;char const**p2=p1;//不合法,會有警告warning: initialization from incompatible pointer type
char**p1;char*const*p2=p1;//合法
2、判斷規則
明確const修飾的對象!對於指針p1,和p2,若要使得p2=p1成立,則可讀做 :
“p1是指向X類型的指針,p2是指向“帶有const限定”的X類型的指針 “。只要二者的X類型一樣,就是合法的。
char *p1;const *p2=p1;//合法:p1是指向(char)類型的指針,p2是指向“帶有const限定"的(char)類型的指針。
char **p1;const char**p2=p1;//不合法:p1是指向(char*)類型的指針,p2是指向 ((const char)*)類型的指針。
char **p1;char const**p2=p1;//不合法;與上等價。
char**p1;char*const*p2=p1;//合法: p1是指向(char *)類型的指針,p2是指向“帶有const限定"的(char*)類型的指針。
五、其他
1、含有const的單層或雙層指針的統一讀法:
“p是一個指針,是一個[“帶有const限定”的]指向[”帶有const限定”的]X類型的指針”。
l例如:const char* const *p就是說:p是一個帶有const限定的指向帶有const限定的(char*)類型的指針。
2、定義時const修飾的對象是確定的,但不能在定義時加括號,不然就和定義時用“()”表示的函數類型相混淆了!因此定義時不能寫(char *)const *p或者(const char) **p。
