原始問題html
實現二叉樹排序,須要使用一個數組構建一個二叉排序樹,最開始寫的代碼以下:數組
struct BST{ int number; //保存數組元素的值 struct BST* left; struct BST* right; }; void insertBST(BST* tree, int v) { if (tree == NULL) { tree = new BST; tree->left=tree->right=NULL; tree->number=v; return; } if (v < tree->number) insertBST(tree->left, v); else insertBST(tree->right, v); } void createBST(BST* tree, int a[], int n) { tree = NULL; for (int i=0; i<n; i++) insertBST(tree, a[i]); }
結果發現每次進入insertBST的時候,tree指針都是空的。用簡單的例子作實驗,發現若是一個指針爲NULL,那麼在函數中指向一個對象,函數返回後指針依舊爲空,即函數中更改指針指向的對象無效。函數
void tmp(int* a) { if (a==NULL) { a=new int; *a=200; } else *a=100; } int main() { int* b=NULL; tmp(b); if (b == NULL) cout << "b is null"; else cout << *b << " "; }
運行上述代碼,發現輸出「b is null」,即b指針在tmp函數中被賦值無效。spa
而若是b指針預先執行一個對象,那在tmp函數中改變其值是有效的。即在int*b = NULL下邊加上一行b=new int;的代碼,能夠輸出改變後值爲100.指針
若是但願在函數中爲指針複製,可使用額外一層的指針,具體代碼以下:code
void tmp(int** a) { if (*a==NULL) { *a=new int; **a=200; } else **a=100; } int main() { int* b=NULL; tmp(&b); if (b == NULL) cout << "b is null"; else cout << *b << " "; }
此時能夠輸出200.htm
問題分析對象
爲NULL的指針在函數中指向一個對象無效。而初始化以後能夠改變指向對象的值。blog
指針自己也是一個值,它的值是所指向對象的地址。指針傳遞參數本質上是值傳遞的方式,它所傳遞的是一個地址值。值傳遞過程當中,被調函數的形式參數做爲被調函數的局部變量處理,即在棧中開闢了內存空間以存放由主調函數放進來的實參的值,從而成爲了實參的一個副本。值傳遞的特色是被調函數對形式參數的任何操做都是做爲局部變量進行,不會影響主調函數的實參變量的值。排序
回到上述例子上,指針在傳遞時,至關於,在被調函數中,申明瞭一個int*的變量,其值就是傳遞進來的int*.即調用tmp(b)時,會執行 int* c=int*b; 那麼在被調函數的堆棧中修改局部變量int*c是 固然也是不會影響到int*b的地址。
可是當b指針不爲NULL的時候,改變b指針的值會有效,這是由於局部變量c和參數b指向的是同一個對象,針對這個地址的修改在函數返回式依然有效。
解決方法
雙重星號的方式是有效的。
此時傳遞的再也不是b指針的值,而是經過&b傳遞的b指針的地址,此時是參數是引用傳遞的,引用傳遞過程當中,被調函數的形式參數雖然也做爲局部變量在棧中開闢了內存空間,可是這時存放的是由主調函數放進來的實參變量的地址。被調函數對形參的任何操做都被處理成間接尋址,即經過棧中存放的地址訪問主調函數中的實參變量。正由於如此,被調函數對形參作的任何操做都影響了主調函數中的實參變量。所以能夠在函數中改變b指針的值,也就是指針指向的對象。
能夠看出,對指針取地址,函數定義的時候使用雙重星號的做用不單單是爲指針賦初始值,還能夠在函數中改變指針指向哪一個對象,而在普通的指針參數傳遞中,函數只能改變指針指向對象的值,不能改變指針具體指向哪一個對象。
說到底,出現該問題的緣由仍是對指針的理解以及對參數傳遞方式的理解不夠到位。
完整的二叉樹排序代碼見上一篇博客:http://www.cnblogs.com/zhaoshuai1215/p/3448154.html