指針類型是C++、Pascal等語言中比較重要的數據類型。在使用上很靈活。在C++中可以使用如下的語句一個int指針類型:
int *p;
如果要為指針變量賦值,可以使用如下的語句:
int x = 4;
int *p;
p = &x;
對於初學者來說,可能理解指針比較困難。實際上,在定義指針變量時,就相當於為該指針變量分配一個32位的內存空間(4個字節長)來保存內存地址(僅限於32位操作系統)。為而指針變量賦的值實際上就是一個變量(可能是簡單類型變量,也可能是復雜類型變量)的首地址。對於32位操作系統來說,不管是什麼類型的變量,地址都是4位的(占一個int類型的空間)。對於兩個指向同一個地址的指針變量,改變一個指針變量所指向的數據,都麼另一個指針變量所指向的數據也將改變,如下面的代碼所示:
int x = 4;
int *p1, *p2;
p1 = &x; p2 = &x;
*p1 = 12;
printf("%d", *p2);
上面的代碼將輸出12。
對於指針的概念及用途,我們也可以做一個形象的比喻。假設有兩個儲物箱A和B。有兩個人P1和P2。 在A中放置了很多東西,而B是空的。P1擁有A和B的鑰匙,而P2只擁有B的鑰匙。並且P1不能直接給P2鑰匙。 那麼P2該如何取得A中的物品呢?(注意,不能直接把A撬開哦,要用鑰匙打開)。
方法嗎有如下兩個:
1.P1將A和B打開,將A中的物品放在B中。
2.P1只將B打開,將A的鑰匙放在B中。
第一種方法是直接將A中的物品放在了B中,這麼做的好處是無論A發生的什麼事,都不會影響B中的物品。但缺點是太麻煩,而且如果A中物品很多的話,是很浪費時間的。而且B的存儲空間要和A的一樣多才能存放A中所有的物品。
第二種方法是P1通過B將A的鑰匙將給了P2,這種方法的好處是方便,而且B也不需要和A一樣大,實際上,只要能放下一把鑰匙即可。但缺點是A可能不只一把鑰匙,如果其他人使用了A的鑰匙打開A,並動了A中的物品,那麼會直接影響到P2所取得的物品。
我們可以將A和B看作是內存中的兩個存儲區域。對於第一種方法來說,實際上相當於如下的代碼:
typedef struct
{
int x
int y;
float abc;
} MyStruct;
// 相當於A中的物品
MyStruct A;
// B參數相當於B儲物箱
void MyMethod(MyStruct B)
{
}
// 將A中的物品放入B中
MyMethod(A);
從上面的代碼可以看出,將A傳入MyMethod方法中需要將A中所有的內容復制到MyMethod的方法棧中,這是很耗費內存資源的。但在MyMethod方法中修改B中的內容,並不會影響到A。但如果使用下面的代碼,就會是另外一個樣子。
// B參數只用於保存鑰匙,也就是4個字節的指針
void MyMethod(MyStruct *B)
{
}
// 將A的鑰匙(指針)放到B中
MyMethod(&A);
上面的方法很節省內存空間,但在MyMethod方法中修改B指向的結構體中變量的值,也同樣會影響到A中相應變量的值。
讀者在使用指針時,可以將指針相象成儲物箱的鑰匙。當定義一個指針變量時,就相當於建立一個只用於儲放鑰匙的儲物箱。而我們為這個變量賦值時,只能放鑰匙(指針)或相當於鑰匙大小的其他物品。一個指針變量可以當成一個int變量來使用,如下面的代碼也是正確的:
int x = 1234;
int *p;
p = (int*)x;
上面的代碼將x中的值強行轉換成了整型指針,實際上,這個指針的值就是1234。也就是說,x變量的值變是一個內存地址了。
那麼指針的指針呢,也就是 int **p;,那麼我們再加一個儲物箱C吧。B保存了A的鑰匙,而C保存了B的鑰匙。只要取得了C的鑰匙,就可以按圖索骥地打開A。
也就是說 ,對於int **p,p中保存了是一個地址,但這個地址指向的內存空間保存了也是一個地址,而這個地址所指向的內存空間保存的才是真正的數據(int類型)。如果是int ***p,那就再加一個儲物箱吧。哈哈。
也許有的讀者可能會注意到本文前面所說的第一種方法是將A中的物品放到B中,那麼A中不就沒了,這不就相當於把A變量清空了,哈哈,沒錯。不過這個比喻只是為了使讀者更容易理解指針的含義和優缺點。如果不想把A清空,就把A中的物品想象成可復制的就可以了,如光盤,把A中的光盤復制一份放到B中,那就更麻煩了。哈哈!