從C語言的數組參數退化為指針談起

Contact me:

Blog : cugtyt.github.io/blog/i

Email: cugtyt#qq.com, cugtyt#gmail.com


當我們寫下如下代碼:

void fun(int arr[]);// 等同於void fun(int *arr);int a[10];fun(a);

我們知道a原來是個數組,但是當我們調用fun傳入的時候,arr不再是數組的形式,而是退化為指針,假設讀者有這個理解基礎。

那麼問題來了,這個轉變過程我們要注意什麼?

首先考慮如果是個數組我們可以求數組長度:

// 為了避免歧義,假設int是4個位元組,指針也是4個位元組sizeof(a); // 40sizeof(a) / sizeof(a[0]); // 10

但是指針就不一樣了:

sizeof(arr); // 4

我們丟失了數組長度的信息,因此從本質上來說,我們用退化的指針來表示數組是有點問題的,真實的數組指針應該怎麼寫呢?

void fun(int (*arr)[10]);int a[10];fun(&a);

注意到我們不再簡單傳入a,而是傳入&a,這樣就是取數組的地址,函數的參數類型也要改變。如果我們做一下測試:

#include <stdio.h>void fun1(int *arr) { printf("%p
", arr); printf("%p
", arr + 1);}void fun2(int (*arr)[10]) { printf("%p
", arr); printf("%p
", arr + 1);}int main() { int a[10]; fun1(a); fun2(&a);}Output: 0x7fffeadf1b30 0x7fffeadf1b34 0x7fffeadf1b30 0x7fffeadf1b58

可以看到fun1,就是原來的方式,指針增加1,沿著數組元素後移,我們無法得知數組有多長,而fun2是傳入數組指針,指針增加1,地址增加28,注意這裡是16進位,轉為10進位就是40,正好就是數組的長度,也就是說這個指針包含了數組長度的信息。

好像我在表達原來的寫法是錯的,這樣才對,但是並不是。因為雖然保留了數組信息,但是函數的聲明必須把數組長度表示出來,這意味著我們必須事先知道長度,而且不能改變,這就限制了函數的能力。所以C的處理方式是退化數組為指針,然後加上數組長度!

C++加入了std::array<type, length>的容器,但是正如我們上面討論的,由於我們要把長度寫死,因此在函數傳遞的時候就很不方便了,這個容器帶來的好處除了可以用標準庫的函數外,似乎在這方面並沒有什麼值得稱讚的地方。當然用指針,我們得人工保證傳入的東西是正確的。

希望讀者通過這個簡短的分析理解為什麼會有數組退化為指針。

推薦閱讀:

TAG:C編程語言 | 指針 | 編程 |