在函數的使用過程中,我們都明白傳值和傳引用會使實參的值發生改變。那么能夠通過傳指針改變指針所指向的地址嗎?
在解決這個問題之前,也許我們應該先了解指針非常容易混淆的三個屬性:
①.指針變量地址(&p)
②.指針變量指向的地址(p,存儲數據的地址)
③.指針變量指向的地址的值(*p)
當我們將指針變量與其它變量比較之后就會發現,指針變量同其它變量是相似的,只是多了最后一種操作。比如一個int類型的變量,int x=5;&x取出存儲5這個數據的地址,同樣,&p也是存儲指針的地址,p就是這個地址里面保存的值,也就是指向的地址。只是與其它變量不同的是,它除了這兩種操作之外,還有一個解引用操作符(*p)去獲取指針變量指向的地址里面保存的值。
一.指針引用
void make(int *pp) { pp=new int(66); //試圖改變p指向的地址 } int main() { int a=5; int *p=&a; //指針變量指向一個int類型的地址 cout<<"address:"<<&a<<" value:"<<a<<endl; cout<<"address:"<<p<<" value:"<<*p<<endl; make(p); cout<<"address:"<<p<<" value:"<<*p<<endl; }
運行結果如下:我們這里雖然使用的是傳指針,但是卻不是直接改變指針變量指向的地址的值,卻是想通過改變指針變量指向的地址來修改它的值,顯然這樣失敗了。
如果我們希望在函數里面修改指針變量存儲的地址而不是它的值,這個時候就需要指針引用了。類似於普通變量傳入變量引用,我們也傳入一個指針引用,在函數里面,你可以將pp認為和p都是這個指針變量(&p==&pp),不似傳入指針參數的時候形參和實參的變量(&p!=&pp)地址不一樣。此時我們操作pp的值就是更改了p的值。
void make(int *&pp) { pp=new int(66); //改變p指向的地址 }
運行結果如下:當我們修改傳入參數為指針的引用的時候就可以修改指針變量所指向的地址了,可以看見,傳入指針引用可以修改指針變量的值(p)和指向的值(*p)。
二.二級指針
指向指針的指針變量稱為二級指針。
如果pp是一個二級指針,那么有如下屬性:
①.二級指針的地址(&pp)
②.二級指針的地址保存的地址(pp)
③.二級指針的地址保存的地址,該地址里面保存的地址(*pp)
④.二級指針的地址保存的地址,該地址里面保存的地址里面的數據(**pp)
除了上面傳入指針引用改變一級指針指向的地址以外,我們還可以通過傳入一個二級指針去修改它對應的一級指針指向的地址,同樣達到了修改指針變量的效果。二級指針的指向的地址存儲的值就是一級指針指向的地址。對一級指針變量解引用得到的是指針指向的地址存儲的數據,二級指針變量解引用得到的也是該二級指針指向的地址存儲的地址值。
void make(int **pp) { int * p=new int(66); *pp=p; //二級指針的解引用被賦值需要得到一個一級指針變量,上圖中二級指針的示意圖中 *pp=p } int main() { int a=5; int *q=&a; int **pp=&q; cout<<"address:"<<&pp<<" "<<pp<<" "<<&q<<" "<<q<<" value:" <<*q<<endl; make(pp); cout<<"address:"<<&pp<<" "<<pp<<" "<<&q<<" "<<q<<" value:"<<*q<<endl; }
運行結果如下:通過對二級指針的解引用賦值成功修改了一級指針指向的地址。如果僅僅在make函數里面對**pp=66;操作,那么所有的地址不會改變,僅僅會改變值為66。