昨天QQ里有個學C++的朋友問我個問題,怎樣利用swap(int *x,int *y)交換x,y指向的地址值。起初我很簡單的給了他一個方法:
方法一:
int *p;
void swap(int *x,int *y)
{
?cout<<"swap("<<*x<<","<<*y<<")"<<endl;
?p=x;
?x=y;
?y=p;
?cout<<"swap("<<*x<<","<<*y<<")"<<endl;
}
int main()
{
?int a=10;
?int b=2;
?int *x=&a;
?int *y=&b;
?cout<<*x<<" "<<*y<<endl;
?swap(x,y);
?cout<<*x<<" "<<*y<<endl;
}
運算結果卻是:
10? 2
10? 2?? //swap
2??? 10 //swap
10? 2
從結果上可以看出swap()仍然沒有起到效果
接著用&來做實驗
方法二:
void swap(int &x,int &y)
{
?cout<<"swap("<<x<<","<<y<<")"<<endl;
?int temp;
?temp=x;
?x=y;
?y=temp;
?cout<<"swap("<<x<<","<<y<<")"<<endl;
}
int main()
{
?
?int a=10;
?int b=2;
?int &x=a;
?int &y=b;
?cout<<x<<" "<<y<<endl;
?swap(x,y);
?cout<<x<<" "<<y<<endl;
}
運算結果是:
10? 2
10? 2?? //swap
2??? 10 //swap
2??? 10
從結果上可以看出swap()起到預定效果
用int *&做實驗
方法三:
int *p;
void swap(int *&x,int *&y)
{
?cout<<"swap("<<*x<<","<<*y<<")"<<endl;
?p=x;
?x=y;
?y=p;
?cout<<"swap("<<*x<<","<<*y<<")"<<endl;
}
int main()
{
?int a=10;
?int b=2;
?int *x=&a;
?int *y=&b;
?cout<<*x<<" "<<*y<<endl;
?swap(x,y);
?cout<<*x<<" "<<*y<<endl;
}?
運算結果是:
10? 2
10? 2?? //swap
2??? 10 //swap
2??? 10
從結果上可以看出swap()起到預定效果
最后,再次用int *做實驗,注意swap()部分的變化
方法四:
void swap(int *x,int *y)
{
?int temp=0;
?cout<<"swap("<<*x<<","<<*y<<")"<<endl;
?temp=*x;
?*x=*y;
?*y=temp;
?cout<<"swap("<<*x<<","<<*y<<")"<<endl;
}
int main()
{
?
?int a=10;
?int b=2;
?int *x=&a;
?int *y=&b;
?cout<<*x<<" "<<*y<<endl;
?swap(x,y);
?cout<<*x<<" "<<*y<<endl;
}
運算結果是:
10? 2
10? 2?? //swap
2??? 10 //swap
2??? 10
從結果上可以看出swap()起到預定效果
=============================================================
好,現在來說下為什么使用方法一和方法四,同樣是傳遞的地址,為什么結果會不同?答案就在swap(int *x,int *y)上。在main()里雖然有x和y指針,但是,在swap()里的x,y卻是臨時變量。首先說明這一點是有好處的。我們來繼續分析以下代碼內容:
?(一)
?? p=x;??//該方法看似我們希望通過交換臨時指針x,y所指向的地址,來達到交換main()函數中實參x,y所指
?? x=y;??//向地址,從而達到交換數值的效果。雖然邏輯上是正確的,程序編譯也通過,但是,卻忽略了??
???y=p; //一個非常重要的內容,那就是swap()中的x,y仍然是臨時的,雖然該程序確實在swap中暫時交換
?????????? //了x,y所指向的地址,但是實際上x,y所指向地址的數值仍然沒有被改變!
?(四)
?? int temp=0;?? //通過對 方法一 的總結,我們作如下調整,在swap()函數中,我們立刻改變臨時指針?
???temp=*x;???? //x,y所指向地址的數值,即改變main()函數中實參指針x,y所指向地址的數值。所以,即使
?? *x=*y;???????? //swap()函數調用完后內部臨時x,y消失,但它們所做的工作已經完成:改變數值!
?? *y=temp;
同理,對于方法三和方法二,通過int & 和int *&也是做了類似方法四的工作,所以能正確swap所需內容。
至于說使用哪種方法,就是仁者見仁的事了。
方法四只不過是交換了值。不防打印出他們的地址來看看。
交換地址需要傳指針的指針:
void swap(int **x,int **y)
{
cout<<*x<<" "<<*y<<endl;
int *t = *x;
*x = *y;
*y = *t;
cout<<*x<<" "<<*y<<endl;
}
我說的交換地址是指 “臨時指針x,y所指向的 a,b的內存地址”,并非“指針x,y的地址!”。從方法一中可以看到,臨時指針x起先指向a的地址,之后改為指向b的地址,指針的特性就是可以指向任何地址,但是只要臨時指針x沒有解引用,沒有對所指向的地址的內容進行操作,則不管x 指向哪里,以前地址里的內容仍然不會改變:a的數值仍然是以前的,b的數值也仍然是以前的。
“臨時指針x,y所指向的 a,b的內存地址”和“指針x,y的地址”是兩碼事。
“怎樣利用swap(int *x,int *y)交換x,y指向的地址值”,也就是a,b的內存地址。
你能交換a,b的內存地址么,不能。你要交換的是x,y的值。而不是交換a,b內存的值。
你能交換a,b的內存地址么,不能。你要交換的是x,y的值。而不是交換a,b內存的值。
--------------------------------------------------------
不明白你的意思?
但是我想說下,如果方法四中不是交換了a,b的內存值,那你看到的會是什么結果?
---------------------------------------------------
方法一并沒有交換臨時數值(我說的這個臨時數值不是a,b的地址,而是a,b的實際數值)。臨時指針x,y可以指向任何地址,也就是說現在x指向a所在地址,等下也可以指向b所在地址,有什么關系呢?我x不解引用,不做為右值,那就不會改變a,b所在地址內的實際數值。
方法一:
p=x;
x=y;
y=p;
cout<<*x<<" "<<*y<<endl;
//得出的結果為 2,10
//那是因為x,y交換了分別指向的地址而已,所以從表面上看以為是更改了a,b地址的內容,其實什么也沒變,現在的*x其實就是之前的y指向地址的實際數值,同樣y也是
方法三:
通過int *&x,int *&y
&的作用和指針一樣,但是它是直接作用于實參x,y上(在本例中)
p=x;
x=y;
y=p;
這個時候在swap()中的操作其實是完全對實參x,y的操作了,也就是把外部x,y所指向的地址相互交換了一下。所以,在main()中使用*x,*y得到的結果為2,10的時候,其實使用了上面臨近評論里的意思:用了個障眼法!其實這個時候在main()中的*x,*y好比之前真正的*y,*x(說白了a,b所在地址和數值完全沒改變)不知道任我行兄能否理解我的意思?
這個寫法,你可以參考一下《高質量C/C++》
int *p;
void swap(int *x,int *y)
{
int *_x = x;//原來函數內的x都被替換為_x
int *_y = y;
cout<<"swap("<<*_x<<","<<*_y<<")"<<endl;
p=_x;
_x=_y;
_y=p;
cout<<"swap("<<*_x<<","<<*_y<<")"<<endl;
}
其他觀點都一樣。
我再說一下的是:x,y的值和x,y的地址是不一樣的。