『摘要』本文主要通過實例展示C/C++中二重指針的用法和用途,對于諸如二叉樹等遞歸定義的數據結構有一定的指導作用 。
【關鍵字】:C/C++、二重指針、遞歸
本人最近想實現一個B+樹,雖然對B+樹的理論有一定的認識,但由于考研花去大量時間復習功課,對C的一些細節有所遺忘,因此決定從二叉樹的實現開始。但剛寫完二叉樹的創建函數且在編譯通過之后,調試時卻出現了問題。二叉樹是一種遞歸定義的數據結構,因此其創建函數也必定是遞歸的。其創建函數描述如下:

圖1 二叉樹創建函數
理論上沒有錯誤,同時在創建二叉樹時也能成功,但通過本人編寫的先序遍歷該二叉樹時,卻顯示0,即空的二叉樹,相關操作代碼如下:
//具體的操作步驟
TREE tree = 0; //TREE為二叉樹結構體的指針型別
createBinaryTree(tree);
//先序遍歷
由于結果錯誤,因此開始調試,通過觀察發現當createVinartTree(tree)操作完成后tree的屬性仍然為0,即仍然tree=0。后來又通過仔細分析,發現問題出在函數的參數上。雖然該函數傳入的是指針型別,屬于實參,但是該函數內部主要以原指針作為操作對象,因此相對于指針來說,傳入的只是結構體指針的形參。所以,在函數內部操作的只是一個副本,因此二叉樹的創建失敗。
為了解決這個問題,筆者決定驗證自己的想法是否正確,于是寫了如下一段測試代碼,代碼如下:
//版本1
typedef struct student {
char* name;
int age;
}Student,*STUDENT;
void getInstance(STUDENT s);
int main(){
Student* st = 0;
printf("指針st的地址=%d\n",&st);
getInstance(st);
printf("st新實例的地址=%d\n",st);
return 1;
}
void getInstance(STUDENT s){
printf("指針S的地址 =%d\n",&s);
s = (Student*)malloc(sizeof(student));
printf("s新實例的地址=%d\n",s);
}
這個函數的傳值形式與之前二叉樹的函數差不多,因此可以類比,具體運行之后得到的記過是(如圖):

圖2 版本1的運行結果
結果很顯然,指針傳入函數之后產生了一個新的副本,對副本的任何操作,都不會影響到原指針指向的結構體,與二叉樹創建失敗類似,目的指針的副本指向了目標結構體,產生了內存泄漏。
這個問題的解決也十分的簡單,將結構體的指針作為實參傳入函數即可,這樣就可以直接操作目標指針,也就不會出現錯誤的結果。運用二重指針可以輕松實現,具體修改如下:
//版本2
typedef struct student {
char* name;
int age;
}Student,**STUDENT;
void getInstance(STUDENT s);
int main(){
Student* st = 0;
printf("指針st的地址=%d\n",&st);
getInstance(&st);
printf("st新實例的地址=%d\n",st);
return 1;
}
void getInstance(STUDENT s){
printf("指針S的地址 =%d\n",s);
*s = (Student*)malloc(sizeof(student));
printf("s新實例的地址=%d\n",*s);
}
修改部分如黑體部分所示,具體的運行結果如下圖:

圖3 版本2的運行結果
測試成功,函數內部操作的指針就是實際傳入的指針,即通過二重指針實現了目標操作指針的實參傳遞,因此能達到預想的結果。這也說明了二重指針的實際用處。