1. 程式人生 > >說出來你們可能不信,但是陣列名確實不是指標常量

說出來你們可能不信,但是陣列名確實不是指標常量

這篇是一篇C語言勸退流教學文,看不懂的同學應該是勸退教學流的目標物件

(寫完了才想起來注一下,本文提到的“陣列”和“陣列名”字樣,指的是陣列左值表示式(array lvalue expression)或陣列宣告(array declaration)所宣告的變數)

首先,陣列名不是常量指標,從兩方面:
1. 型別方面,陣列的型別是type[size],和常量指標型別type* const不同
2. 使用方面,sizeof(陣列名)等於陣列所有元素的大小,而不是sizeof(指標);對陣列取地址,得到的指標進行加減,增減位元組數是sizeof(陣列);你可以用字串字面量初始化一個字元陣列,但是不能用常量指標來初始化一個字元陣列。

其次,為什麼很多老師都說陣列是常量指標:
1. 他們不瞭解C語言的型別系統和隱式轉換規則
2. 他們怕下面的人聽不懂
3. 他們解釋不清為什麼陣列名不能進行賦值或者++之類的運算而指標可以

切入正題,我們從型別系統和隱式轉換規則來講:
1. 陣列名的型別就是陣列型別type[size] (參見Array declaration)
對陣列取址,得到的型別是指向陣列的指標type(*)[size] (參見Member access operators)
2. 陣列名在大部分情況下會隱式轉換為首元素指標右值,除了(參見 Implicit conversions)

  • sizeof運算的時候
  • 取址的時候
  • 用字串字面量初始化字元陣列的時候
  • 以及C11的_Alignof運算子(這個本文不考慮)

其他情況下都會發生陣列到指標隱式轉換,比如你用方括號取值,如果方括號左邊是個陣列,那麼陣列會被隱式轉換為首元素指標右值,然後對這個值進行的解引用。(參見Member access operators)

更進一步,二維陣列type[size1][size2],實際上就是元素型別是陣列的陣列,進行隱式轉換後得到的首元素指標型別是type(*)[size2],指向陣列的指標,對這個指標加減,得到的也是陣列的指標,對它解引用,得到陣列。這一套過程,用那個什麼陣列名是常量指標的說法,是解釋不來的。

最後出一個題:寫出程式輸出

typedef char(*AP)[5];
AP foo(char* p) {
    for (int i = 0; i < 3; i++) {
        p[strlen(p)] = 'A';
    }
    return (AP)p+1;
}
int main() {
    char s[] = "FROG\0SEAL\0LION\0LAMB";
    puts(foo(s)[1] + 2);
}

這個題用陣列名是指標那套理論是做不出來的。