本篇是第一篇,介紹指針的本質是什么。
在相當一部分的C++教程中,講到指針時,基本上都會舉swap(int a,int b)這個 數據交換的例子。我也同樣愿意舉這個例子作為講述指針的開始。
下面是類的代碼內容:
//……限于篇幅,只留說明問題的部分內容……
定義部分:
public:

void swap(int a,int b);

實現部分:

void CPointerResearch::swap(int x,int y)
{

int nTmp = x;

x = y;

y = nTmp;

}

下面是測試數據及結果:
輸入:
100, 200
輸出(執行swap函數后):
100, 200
Press any key to continue
可以很清楚的看出,并沒有實現數據交換。
我們來假想一下程序員寫這樣程序時的心里:有兩個小框,甲框放數字為100的卡片,乙框放數字為200的卡片,現將兩張卡片交換一下位置,變成甲框存放數字為200的卡片,乙框存放數字為100的卡片。
這樣的想法有問題嗎?答案很明確,一點點問題都沒有!想法完全正確,他(她)只要確實是這樣做的,卡片交換就一定能成功。但為什么上面的程序模擬這樣的執行過程,結果卻不是想要的呢?要想徹底弄明白這個問題,我們必須認識問題的根本,即這個問題的本質是什么,這才是真正解決問題。
我們來深入分析一下上面那個看似簡單的假想情景。第一,有兩個框,這是確定的事實,毋庸置疑。第二,框里都裝有卡片,并且上面的數字不同,這個是不爭的事實。第三,交換卡片過程中,雖然兩個框都沒挪動,但里面的卡片都有挪動。第四,卡片挪動是從一個框挪到另一個框。正是有了這四點作保證,卡片才得以成功交換。換句話說,上面的數據交換程序的執行交換過程如果滿足這四個條件的話,計算機執行后輸出的結果就一定是我們期待的正確結果。那么,至此出錯原因已很明確,就是計算機執行程序的過程中,上面這四點至少有一點一定不符合。下面一一分析。
第一, 從輸入條件看。
輸入條件是int a =100;int b= 200;從這兩個C++語句我們可以看出,兩個“框”已經有了,分別是a和b,也就是說具備了第一個條件。此外,甲框(a)放了數字為100的卡片(int a=100;), 乙框(b)放了數字為200的卡片(int b=200;),這說明第二個條件也具備。從輸入條件已經看不出什么其它的有用的信息。至此我們已經可以判斷出問題出在后兩個條件有不滿足的地方。
第二, 從swap函數體看。
函數體 int nTmp = x; x = y; x = nTmp;是最典型的只用三行代碼就實現數據交換的代碼。沒問題,在執行這三行代碼前和執行后分別打印輸出就可以看得一清二楚,確實實現交換了。這說明上面的第四個條件也滿足,因為這三行代碼就是“從甲框拿x卡片放到地上,再把乙框的y卡片放入甲框,最好將地上的那張卡片(就是x卡片)揀起來放到乙框中去”。那么,到現在可以說明問題出在第三個條件不滿足。我們再繼續分析下去。
第三, 從swap函數聲明看。
從數據交換的程序代碼看,也就只剩這么一點東西還沒有去分析一下。我們的執行過程其實又有幾個分步驟:
首先,輸入:int a= 100; int b= 200;這只是賦值操作,肯定沒有問題。
其次,執行:步驟1,為調swap(int x,int y)函數做準備,將a傳給x,b傳給y。
步驟2,執行swap(x, y),就是執行函數體內容。步驟2在上面已經得到驗證,沒問題。
最后,執行完畢在主函數里輸出a和b:100,200,這是調C++標準輸出函數輸出的,提供什么數據就如實地輸出來。這也沒問題。
至此,問題已經可以定位,就在“其次”里的“步驟1”!對這一步的執行過程再繼續細分,就是:將甲框(輸入的a)的數字為100的卡片放到丙框(swap函數的參數x)注1, 將乙框(b)的數字為200的卡片放到丁框(swap函數的參數y)。程序接下來就是執行“其次”里的“步驟2”,也即進入函數體執行,這時候在悄悄的把丙框和丁框的卡片相交換。可見原來交換的是丙框和丁框!甲框和乙框原來是什么樣還是什么樣。這當然不會看到期望的輸出。
所以解決問題的根本是必須要“找對框”,只交換想要交換的“框”。對這個“找對框”的真正理解程度會直接反映出對指針的真正理解程度。 這樣,可能的解決方法比如:
基于指針的swap方法(直接拿甲框和乙框的卡片并進行交換,根本就沒有丙框和丁框):

void CPointerResearch::swap(int* x,int* y)
{

int nTmp = *x;

*x = *y;

*y = nTmp;

}

基于引用的swap方法(不直接用丙框(而是引用到甲框)和丁框(而是引用到乙框)):

void CPointerResearch:: swap (int& x,int& y)
{

int nTmp = x;

x = y;

y = nTmp;

}

注1:本文舉的假想例子主要是為了說明問題,但例子不一定很貼切。“將甲框(輸入的a)的數字為100的卡片放到丙框(swap函數的參數x)”這句話,更貼切的說應該是“甲框有跟線系在數字為100的卡片上,現在執行“a傳給x”操作,就是說丙框要拉一根線出來也系到那張數字為100的卡片上”。
本篇內容強調的就是一點,“什么是指針?指針的本質是什么?”。理解指針的本質是學習指針的關鍵所在。特別是初學指針者,如果能把這個swap函數真正搞明白,那么對指針的理解應該說已經有了一定的功底。如果很浮躁或很膚淺的去看待指針,是不會真正掌握指針的豐富內涵的。用指針,要用,那就要用到“沒指針,就感覺不知道如何是好”這個地步。否則用指針也沒太大的意思,又容易出錯,不止怎么排除,自己可能興趣也不高。