娓娓道來c指標 3 指標和陣列

2021-06-22 21:55:36 字數 3022 閱讀 4919

(3)指標和陣列

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

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

int main()

; 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])

int main()

; printf(" sizeof(array)...%d\n", sizeof(array));

fun(array);

return 0;

}

執行

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

從效率上考慮,若是把整個陣列賦值過去,太耗時,也耗空間。還不如傳位址過去,使用同乙份內容。

在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 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()

; 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)c陣列本質。

專欄目錄:

娓娓道來c指標 3 指標和陣列

3 指標和陣列 在c中指標和陣列似乎有著千絲萬縷的關係。其實它們不是一回事 指標是指標,陣列是陣列,兩者不相同。說它們有關係,不過是因為常見這樣的 cpp view plain copy print int main int n sizeof array sizeof int int p array...

娓娓道來c指標 8 開發可變引數函式

8 開發可變引數函式 在c語言中,可變引數的函式極其常見,如常用的printf 可變引數函式的一般形式如下 返回值型別 函式名 型別1 引數1,型別2 引數2,型別n 引數n,如上所示,這是乙個典型的可變引數樣式,它共有n個確定的引數,最後的.表示可變引數的含義。必須指出.必須位於最後,並且它至少要...

娓娓道來c指標 4 解析c的宣告語句

4 解析c的宣告語句 在繼續探索c指標之前,有必要來解析下c語言中複雜的宣告語法。只需要記住兩則 乙個原則,乙個規則。原則 先看標示符。規則 運算子優先順序是規則。舉例說明 1.最簡單的 int array 3 結論 array是陣列,陣列規模是3,元素型別是int。解析過程 先看標示符 array...