之前在寫C的時候,沒怎麼留意數組,就這麼定義一個,然後顛來倒去的使用就行了。不過後來碰到了點問題,解決後決定寫這麼一篇博客,數組離不開指針,索性就放一起好了。
現在我定義了一個數組:int cc[10];
圍繞這個數組有好幾種指針:cc, cc+1, &cc[0], &cc, &cc+1等等。你知道它們都是什麼含義嗎?試試運行以下帶代碼:
#includecc,這是學數組時第一個接觸的"指針",最為熟悉,它是數組的首個元素。int main() { int cc[10]; printf("%x\n", cc); printf("%x\n", cc+1); printf("%x\n", &cc[0]); printf("%x\n", &cc); printf("%x\n", &cc+1); getchar(); return 0; }
cc+1,這是指向數字第二個位置的指針。
&cc[0],這個其實就是cc,指向數組的首個元素。
&cc,這是什麼玩意兒?指向指針的指針?
&cc+1,如果上面的意思是指向指針的指針,那這個豈不是指向野地址了?
假設運行環境是32位機,並且數組首地址為0x28ff00,那麼:
cc的結果為0x28ff00,這點毫無疑問。
cc+1的地址是0x28ff04而不是0x28ff01,因為一個int占用了4個字節的空間。cc+1其實是當成cc+1*sizeof(int)來看待。
&cc[0]的結果是0x28ff00,cc[0]表示的是數組的首個元素,那麼&cc[0]自然就是首個元素的地址了。&cc[0] == cc。
&cc,這個就難說了,指針cc的值是0x28ff00,&cc表示這個指針本身的地址,我們怎麼可能會知道這個地址?輸出是個隨機地址嗎?隨機數的話這個輸出完全沒有意義啊。如果不是隨機地址的話,難不成還是0x28ff00?這樣的話a不就等於&a了?明顯不對吧。。。
對於基本類型的指針,如int *tt; 那麼*tt是其值,&tt是指針的地址,&tt != tt
但是上述的cc是個數組,實際上,&cc被編譯成了&cc[0],但是其含義不同,&cc指向的是整個數組的開頭。&cc與cc的指向可以用下圖來形象表示:
上圖可以看出,&cc其實代表的是int(*)[10],那麼&cc+1就可以理解為cc + sizeof(cc)/4,之所以除以4是因為int型指針++其實是移動了4個字節。
又或者說%cc == cc + sizeof(cc)/4 == cc + 10,所以&cc+1的值為0x28ff28。
可見我們平常使用的數組名,並不能單純的當成指針看待。數組名的本質是代表數組對象的變量名,是一個左值,是一個不能被改變的左值。但是由於在程序中不保存數組的大小,所以通過數組名只能訪問數組的左值,不能訪問數組的右值。由於這個原因,數組名在作為右值使用的時候被賦予另外一個新的意義——指向數組第一個元素的指針,這就是array-to-pointer轉換規則。根據標准規定,只有當數組名作為sizeof、&運算符的操作數的時候,它是一個左值,其類型為數組類型。除此之外的所有情況,數組名都是一個右值,被編譯器自動轉換為指針類型,這種情況下我們就說數組名是一個指針,並且是一個指針常量。
接下來是另外一些有趣的東西,我們結合sizeof與數組輸出各類值。以下程序的輸出結果是什麼?建議思考後再運行程序來驗證答案。
#includesizeof(cc[0]),一個int的大小,輸出4,沒問題。int main() { int cc[10]; printf("%d\n", sizeof(cc[0])); printf("%d\n", sizeof(cc)); printf("%d\n", sizeof(&cc)); printf("%d\n", sizeof(int(*)[10])); getchar(); return 0; }
sizeof(cc),注意不要和上面搞混,這不是數組首地址的指針,cc在這裡是左值,其為數組類型,所以結果為40。
sizeof(&cc),這個的答案應該是多少呢?注意了,cc在這裡還是左值,其為數組類型,但&cc不同於cc,不管數組怎麼復雜它始終是個指針,32位機上指針大小始終是4個字節,所以結果為4。
sizeof(int(*)[10]),這個其實和上面的&cc是一個樣的,代表了整個數組,但還是指針,所以結果同樣為4。
練習:下面的程序輸出結果是什麼(假設32位機):
#includeint main() { int *p[2]; printf("%d\n", *p); printf("%d\n", sizeof(p)); printf("%d\n", sizeof(&p)); getchar(); return 0; }
答案是:隨機數、8、4
再來一個練習:下列程序的輸出是什麼?
#includeint main() { char str[]="hactrox"; char *p = str; printf("%d %d\n", sizeof(str), sizeof(p)); getchar(); return 0; }
答案:8、4(不要忘了'\0')