陣列與指標的比喻
陣列與指標的比喻
新人小白,初學陣列與指標,想要略談一下兩者的聯絡與區別。
我喜歡用比喻的方式說明問題。
現在,你可以把龐大的電腦記憶體看作一個世界(類似於我的世界),每個方塊都有它的座標,,每個方塊也都有它本身的內容(比如說石頭,草塊,泥土);這就對應著電腦資料內容的兩大要素:資料本身與資料在電腦中的地址。
而陣列可以說是電腦為了宣告一堆資料而在這個世界中建的公寓,一維陣列即為一層公寓,多個房間;二維可以是多層公寓,多個房間;三維就是一個小區了……需要注意的是,這些房子的建設者為了省事兒,把每個房間的大小建設的一樣大,房間大小取決於你的你的宣告,如果你用int宣告,那麼你會得到一堆四個格格大小的房間。
而指標就是電腦資料對應的地址,記錄的就是每個房間的門牌號。對於一個大小隻有四個格格的房間來說,他的門牌號就是第一個格子的座標,對於一整個陣列來說,他的地址就是第一個房間的第一個格子的座標。
需要注意的是,這裡指標加一不是數值加一,而是“門牌號”加一,即直接加了一個房間的格數。如:
#include<stdio.h>
#define SIZE 4
int main()
{
short dates[SIZE];
short *pti;
short index;
double bills[SIZE];
double *ptf;
pti = dates;
ptf = bills;
printf("%23s %15s\n","short","double");
for(index=0;index<SIZE;index++)
printf("pointers+%d: %10p %10p\n",index,pti+index,ptf+index);
return 0;
}
其輸出結果為:
short double
pointers+0: 000000000062FE00 000000000062FDE0
pointers+1: 000000000062FE02 000000000062FDE8
pointers+ 2: 000000000062FE04 000000000062FDF0
pointers+3: 000000000062FE06 000000000062FDF8
明顯的,由於short型別佔用兩個位元組,double型別佔用八個位元組,所以指標加以後分別+2與+8。
上面程式碼中涉及到賦值語句pti=dates。在這裡,dates(陣列名)就代表這整個陣列的“公寓地址”,而這個地址與公寓第一個房間的地址(門牌號)剛好相同,即:
date==&dates[0];
“”“&”都是指標運算子,“”找到地址對應的值,“&”找到值對應的地址。
而陣列與指標的聯絡就呼之欲出了,由於陣列名可以表示陣列第一個元素對應的地址,所以陣列的元素均可以使用指標表示。
如下:
dates + 2==&dates[2];//相同的地址
*(dates + 2)== dates[2];//相同的值
同時,陣列與指標也有一定區別。
我們先來看這樣一個程式碼:
//字串的地址
#define MSG "I`m special"
#include<stdio.h>
int main()
{
char ar[]=MSG;
const char *pt =MSG;
printf("address of \"I`m special\":%p \n","I`m special" );
printf(" address ar:%p \n",ar);
printf(" address pt:%p \n",pt);
printf(" address MSG:%p \n",MSG);
printf("address of \"I`m special\":%p \n","I`m special" );
return 0;
}
其輸出結果為:
address of "I`m special":0000000000404000
address ar:000000000062FE00
address pt:0000000000404000
address MSG:0000000000404000
address of "I`m special":0000000000404000
這裡先將字串"Im special"定義為MSG,再分別用陣列與指標研究這個"I
m special"。
根據輸出結果發現:表示該字串的指標pt,與表示該字串的陣列ar地址不同!
對此區別,我們要先明白陣列與指標兩種不同的工作原理:
當把這個程式載入記憶體時,也載入了陣列中的字串,而這些字串儲存在靜態儲存區(在這裡為 0000000000404000 這個地址)中。當程式執行時,就會將這些字串拷貝到陣列(在這裡為 000000000062FE00 這個地址)中。注意,這時候字串有兩個副本,一個是在靜態儲存區中,另一個放在陣列中。
這時的陣列名ar就是ar【0】的地址,但指標pt指向的是字串"I`m special" 的原地址。
通俗來講:你現在在這個世界這個世界的野外修了個兵馬俑(字串),用陣列就是建個房子,把兵馬俑的複製品搬到房間裡,對房間裡一個個小兵進行敲打,整容,截肢,為所欲為。而指標就粗暴了,直接殺到野外,對原兵兵進行敲打,整容,截肢,為所欲為……(只是這樣做屬於破壞公物,一般是不被允許的)
那我們開始說區別:
第一,這裡的ar由於表示的是門牌號,所以它是不能亂改的,就像施工工地上的一個大房子不能亂左右橫跳一樣;但指標pt不一樣,他只是通向兵馬俑的地址,一個數字而已,可以對他進行pt++等運算。
第二,由於陣列地址的不可更改性,ar只能做右值,不能做左值,就像只能X=3不能3=X一樣;但指標可以做左右值。
第三,陣列的元素是變數,所以我們可以對ar【0】或*(ar+0)進行修改,但指標指向的是公物!前面提到,編譯器可以用記憶體中的一個副本表示所有完全相同的字串字面量,運用指標改變字串中內容,即改變了所有相同字串的內容,舉個栗子:
char *p = "Klingon";
p[0]='F';//ok?
printf("Klingon");//一號位
printf(": Beware the %ss!\n","Klingon") ;//二號位
編譯器可能不允許這樣做,也可能允許,但即使可以,對於當前C標準來說,這樣做是未被定義的。
下面我們假設他可以編譯成功,執行後輸出結果將如下:
Flingon: Beware the Flingons!
注意,程式碼中的一二號位Klingon都被列印成了Flingon!
就是說,如果我們用指標把“I love you”改成“I hate you”,那我可能永遠都說不出我愛你了!即使打出我愛你,打印出來的也可能是我恨你。
所以,建議在把指標初始化為字串字面量時使用const限定符,就像這樣:
const char *p="I love you"; //推薦用法
願你的愛生生世世不變質!
好了,謝謝觀看,就先寫這麼多了,拜拜。
(參考第六版C Primer Plus完成)