C 語言常見誤解/指標/指標運算

指標(三)指標運算

编辑

問:假如有兩個指標型態都是 int*, 可以相減得知他們相差多遠嗎?

答:一般來說不行。兩個指標必須指向相同陣列的元素,或是該陣列最後一個元素超過一格的位置,才能相減比較。陣列太大也有可能出狀況,請看下一個問題。(另外參考這個問題和 clc FAQ 5.17 看實際例子)


問:指標相減得到的距離是什麼型態?

答:是有號整數型態 ptrdiff_t. 注意如果因為陣列太大導致這個型態無法表示之間的距離,則相減視為嚴重的錯誤。請務必檢查 PTRDIFF_MAXPTRDIFF_MIN 確保此型態滿足程式所需。


問:我知道陣列和指標不同,但既然陣列在很多地方都會自動轉型成指標,如果把 int a[100] 的型態理解成 int * const(不能改內容的指標)會有什麼陷阱呢?

答:一個經典的例子是如果第一個檔案寫

int a[100];

第二個檔案寫

extern int * const a;

則在很多實作中,第二個檔案內存取 a[0] 時,編譯器會把第一個檔案 a[0] 的內容硬當作 int 指標 p 再把 *p 當作計算結果,進而發生嚴重的錯誤。在這例子中 C99 (N1256) 並不要求編譯器發出任何錯誤訊息。


問:如果一個結構是

  struct {
     int heap[1024];
     int stack[1];
  };

那可以用 .stack[-1] 去存取 heap 的內容嗎?

答:不行。首先要考慮填充的問題,heap 和 stack 中間不一定連續。就算確定沒有填充,陣列存取等價於先做指標運算後再解參照,而指標運算只能在同一陣列內部或超出最後一個元素一格的位置之間移動。也就是說,符合標準的編譯器可以額外加上陣列範圍檢查。


問:如果一個陣列 a 型態為 int[5][5] 可以用 a[1][10] 去存取嗎?陣列不是連續的嗎?

答:這樣存取不保證成功。雖然陣列是連續的,看起來也可以存取,但是不行。陣列存取等價於指標運算加上解參照,在這例子中等價於 *(*(a+1)+10) 這個表達式。但指標運算只能在同一陣列內部或超出最後一個元素一格的位置之間移動。+10 違反了這個限制。(請一同參考指標相減的規則。)標準允許實作主動檢查指標是否超過範圍,甚至用完全不同的方法表示陣列。(參考 N1256 Annex J.2p1clc FAQ 5.17 看實際例子)