《C專家編程》的筆記-指針與數組的區別

  1. int a[10];
  2. int main(){
  3. int *p = a;
  4. p[5] = 4;
  5. return p[5];
  6. }
翻譯出的彙編可以看到
movl $4, -24(%ebp)
對於一個數組char a[10]而言,如果訪問a[i],步驟是:
1. 將a的地址讀入寄存器,由於a其實就是一個別名,所以a的地址本身就是a[0]的地址
2. 根據類型計算並添加偏移,得到目標地址
3. 訪問內存得到a[i]
而如果聲明是char *a,訪問a[i],其步驟是:
1. 將a的地址讀入寄存器,a是一個指針,指向a[0]的地址。
2. 訪問內存讀取a的值,得到a[0]的地址。
3. 根據類型計算並添加偏移量,得到目標地址
4. 訪問內存得到a[i]
根據這樣的理解,當我們在一個文件中聲明變量爲char *a,而在另一個文件中將a定義爲數組,即char a[10],將會造成非常大的問題。在聲明變量的文件中使用a[i],將首先會把a的地址讀入寄存器,訪問內存取出a的值,而由於其定義爲數組,因此a的地址就是a[0]的地址,將取出的a[0]作爲目標地址的基址顯然是錯誤的。
那麼肯定有人會問,int *p = a算是個什麼東西,不是說好的a是個別名而已麼,a的地址纔是a[0]的地址啊。其原因是,C標準中說道,在表達式中使用數組,編譯器會將數組自動轉化成指針,這是所有C編譯器必須有的行爲,該指針指向數組的第一個元素。
需要注意的是,對於指針的下標操作[],當且僅當其定義是數組的時候纔有效,對於指針類型的聲明,編譯器將下標操作直接作爲加號操作,因此a[5]和5[a]在a爲指針的時候都是合法的。
可能又會有人有疑問,常常看到一些函數的簽名是指針,可傳入的是數組,不也沒事兒麼。C標準還有一條:當數組出現在函數的參數中時,無論是形參還是實參,都轉換爲指針再進行操作。因此main函數的參數char *argv[],也可以寫成char **argv.
但這種轉換不是在任何時候都成立的,比如多維數組的情形,char a[3][4][5]作爲參數傳遞的時候只會轉換爲一個3維數組的指針char (*a)[4][5],而不會轉成指針的指針的指針。
函數不可以返回數組,但可以返回數組的指針,比如:
  1. int (*func())[]{
  2. ...
  3. }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章