記憶體與指標

指標的型別

每個指標都帶著一個標籤,說明它指向什麼東西:int * 是「某個 int 的位址」,char * 是「某個 char 的位址」,double * 是「某個 double 的位址」。裡面的位址號碼可能一樣,但型別告訴編譯器:在那裡要讀幾個位元組、又該如何詮釋它們。

被指型別做兩件實在的事。第一是解參考:對 int * 做 *p 會讀 4 個位元組並當成 int,而對 char * 做 *p 恰好讀 1 個位元組並當成字元。第二是指標算術:p + 1 前進的是「一個被指物的大小」,不是一個位元組——所以在 int * 上它向前跳 4 個位元組,落在下一個 int 上。正是型別讓 p[i] 不管元素多大都代表「第 i 個元素」。不同型別的指標一般不可互換,若不經轉型就互相指派,編譯器會警告。

有兩種指標型別與眾不同。void * 是無型別指標:它持有一個位址,卻沒有被指型別,所以在你把它轉成具體型別之前,既不能解參考,也不能做算術。此外,被指型別本身也可以是 const 或帶其他修飾——const char * 承諾「我不會透過這個指標寫入」——這正是 const 正確性的基礎。

給定 char *c = (char*)0x1000; 與 int *n = (int*)0x1000;,兩者都持有 0x1000,但 c + 1 是 0x1001(前進一個位元組),而 n + 1 是 0x1004(前進一個 int,也就是四個位元組)。同樣的位址,不同的步幅。

決定步幅、以及 *p 讀幾個位元組的是型別,不是位址。

所有物件指標在記憶體中的寬度都一樣(64 位元機器上通常是 8 位元組)——型別是編譯期資訊,不是額外的儲存。把 int * 轉型成 char * 不會改變位址,只改變編譯器如何讀取它、以何步幅前進。

又稱
pointee type被指型別