娓娓道來c指標 (3)指標和數組

來源:互聯網
上載者:User

標籤:c語言   c指標   數組   

                            (3)指標和數組

在c中指標和數組似乎有著千絲萬縷的關係。其實它們不是一回事:指標是指標,數組是數組,兩者不相同。

說它們有關係,不過是因為常見這樣的代碼:

int main(){int array[] = {1,2,3,4,5};int n = sizeof(array) / sizeof(int);int *p = array;int i;for (i = 0; i < n; i++)printf("p[%d]...%d\n", i, p[i]);system("pause");return 0;}
運行


在上面的代碼中,指標和下標運算子的結合使用,給人一種指標和數組是一樣的感覺。

本質是:數組名是一個指向數組起始元素的常量指標。這也是數組和指標的唯一聯絡!

之所以可以使用 p[i] 來訪問數組中的元素,是因為在編譯器中 p[i] 被解釋為 *(p+i),這仍然是指標的功能。對編譯器而言,用p[i]表達*(p+i)的含義是沒有意義的,它只是為了讓人看著舒服,用著方便。這是文法糖

    p[i]是*(p+i)的簡單寫法,實際上,至少對於編譯器來說,[]這樣的運算子完全可以不存在。

    可是對於人類來說,*(p+i)的寫法在解讀上比較困難,寫起來也麻煩(鍵入量大)。因此,c語言引入[]運算子。

    就像這樣,這些僅僅是為了讓人類容易理解而引入的功能,的確可以讓我們感受到程式設計語言的甜蜜味道(容易著手),有時我們稱這些功能為文法糖(syntax sugar 或者 syntactic sugar)。

以上摘自《征服c指標》,藉此推薦這本書。書中一針見血地指出:只有在聲明語句中,[]才表達數組的含義,在運算式中,[]與數組無關!

總結起來就是,看似數組的用法:p[i],其實是*(p+i)的文法糖,p仍然是指標,與數組並無關係。


指標和數組的不同之處,還可以從下面的例子看出

void fun(int array[5]){printf("  sizeof(array)...%d\n", sizeof(array));}int main(){int array[] = { 1, 2, 3, 4, 5 };printf("  sizeof(array)...%d\n", sizeof(array));fun(array);return 0;}
運行


從運行結果看,函數形參雖然用數組的方式進行了聲明,但仍然被當做指標。這揭示了c語言中傳遞數組時的規則:傳遞過去的是地址,是指向數組起始元素的地址。之所以這樣,基於兩點;

  1. 從效率上考慮,若是把整個數組賦值過去,太耗時,也耗空間。還不如傳地址過去,使用同一份內容。
  2. 在c語言設計之初,賦值操作就僅限於基本類型(char、int、float……),而數組是彙總類型。
這給我們的編程啟示是:傳遞數組時,不要忘了把數組大小也傳遞過去。否則,函數那邊由於不知道數組大小,極易越界。應這樣設計函數 void fun(int *array, int n),n是數組大小。還有一點需要指出,即使函數被設計成void fun(int array[5], int n),array依然被看成是指標。也就是說即使數組帶了長度,該長度也會被編譯器忽略掉。一句話:形參中的數組統統看成指標。既然如此,還不如直接寫成void fun(int *array, int n)。指標的形式,更能表達本意。

再思考:如果p[i]是*(p+i)的意思,由於加法具有交換律:p+i=i+p,那麼i[p]同樣可以表達p[i]的意思,是這樣的嗎?實驗驗證:
int main(){int array[] = { 1, 2, 3, 4, 5 };int n = sizeof(array) / sizeof(int);int *p = array;int i;for (i = 0; i < n; i++)printf("  %d[p]...%d\n", i, i[p]);return 0;}
運行
實驗證明,我們的猜想是正確的:p[i]確實是*(p+i)的文法糖。i[p]這樣的寫法是否很逆天呢!
總結:只有在函數形參中,僅有這一種情況,聲明的數組,如 int array[]會被看作是指標。其它情況下,指標與數組並無聯絡。
&array的含義還有一點,對於 int array[5];array表示指向數組起始元素的指標,那麼&array又是什麼呢?實驗下:
int main(){int array[] = { 1, 2};printf("   array...%p\n", array);printf("  &array...%p\n", &array);printf("&array+1...%p\n", &array+1);return 0;}
運行
分析實驗結果:0031FCEC與0031FCE4相差8,而sizeof(array)就是8。結論就是:array和&array都是指標,但類型不同。array的類型是int*,而&array的類型是int(*)[2]。array是指向普通int類型的指標;&array是數組指標,該數組元素是int類型的,且數組大小是2。至於array和&array兩者的值是一樣的,應該很好理解。
補充標量(scalar):簡單講,標量就是指char、int、double和枚舉類型等數值類型,再加上指標。至於數組、結構體和共用體這樣將多個標量進行組合的類型,我們稱之為彙總類型(aggregate)。

那麼為什麼int(*)[2]表示的是數組指標呢?這需要透徹理解c的聲明文法。又比如,二維數組(更甚者,多維陣列)的數組名又是什麼類型的指標呢?這需要瞭解c中數組的實際含義,後序講解。





相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.