傳值,傳指針(地址),傳引用以及表添加函數中為什么要用指向鏈表指針的指針


        在看書的時候有個往鏈表里添加節點的函數,代碼中考慮到可能給出的頭指針為空,並做另外一些處理。具體代碼如下:


  1. #include <iostream>  
  2. #include <string>  
  3. using namespace std;  
  4.   
  5. struct ListNode  
  6. {  
  7.     int val;  
  8.     ListNode* next;  
  9. };  
  10.   
  11. void AddToTail(ListNode** pHead, int value);  
  12.   
  13. int main() {  
  14.     // TODO  
  15. }  
  16.   
  17. void AddToTail(ListNode** pHead, int value) {  
  18.     ListNode* pNew = new ListNode();  
  19.     pNew->val = value;  
  20.     pNew->next = NULL;  
  21.   
  22.     if (*pHead == NULL) {  
  23.         *pHead = pNew;  
  24.     }  
  25.     else {  
  26.         ListNode* p = *pHead;  
  27.         while (p->next != NULL) {  
  28.             p = p->next;  
  29.         }  
  30.         p->next = pNew;  
  31.     }  
  32. }  


        網上其他人的博客中對函數AddToTail的參數的描述跟書中如出一轍:第一個參數pHead是一個指向指針的指針,當向一個空鏈表插入一個節點時,新插入的節點是鏈表的頭指針,此時會改動頭指針,因此必須把pHead參數設置為指向指針的指針。

        為什么呢?在以前學習C++的時候,我們只知道在參數中,以傳值的形式作為參數的變量在函數體內被修改之后,出了函數體就會失效,准確的說這個變量沒有被修改過,因此需要傳入該變量的指針或者使用引用傳參的方式。可是上述AddToTail中已經是一個指針了啊?於是我測試了一下,不使用指針的指針會怎樣:

  1. #include <iostream>  
  2. #include <string>  
  3. using namespace std;  
  4.   
  5. struct ListNode  
  6. {  
  7.     int val;  
  8.     ListNode* next;  
  9. };  
  10.   
  11. void AddToTail(ListNode* pHead, int value);  
  12.   
  13. int main() {  
  14.     // TODO  
  15.     ListNode* head = NULL;  
  16.     AddToTail(head, 10);  
  17.     if (head != NULL) {  
  18.         cout << head->val << endl;  
  19.     }  
  20.     else {  
  21.         cout << "head is NULL.." << endl;  
  22.     }  
  23.       
  24. }  
  25.   
  26. void AddToTail(ListNode* pHead, int value) {  
  27.     ListNode* pNew = new ListNode();  
  28.     pNew->val = value;  
  29.     pNew->next = NULL;  
  30.   
  31.     if (pHead == NULL) {  
  32.         pHead = pNew;  
  33.     }  
  34.     else {  
  35.         ListNode* p = pHead;  
  36.         while (p->next != NULL) {  
  37.             p = p->next;  
  38.         }  
  39.         p->next = pNew;  
  40.     }  
  41. }  


        運行結果如下



        作為指針pHead竟然真的沒被修改過!

        其實真的很好理解,既然你懂得函數中的值傳參,假設int a,作為參數傳入的時候沒被修改,所以需要用指向a的指針,那么應該也可以理解,指針變量pHead作為參數傳入的時候被修改無效,因此需要用指向pHead的指針,只不過pHead本身就是一個指針了,所以才存在有指針的指針看起來稍微復雜一點的說法。因為,指向a的指針作為參數傳入進去時,如果你對它進行修改,其實也是無效的,但是修改指針指向的內容的修改是有效的,也即,(&a)對a取地址得到的指針傳入進去之后,此時你修改這個指針也是沒有什么實際作用的,原因我等下會說。但是,你修改指針指向的內容這就有效了,因此通常我們在函數體內是修改對指針取內容后的內存,即*(&a)。所以,你對指針pHead的修改時無效的,只有對指向pHead的指針指向的內容(很繞吧,其實就是pHead),這時候才是有效的,因此AddToTail的第一個參數必須用指針的指針。


        現在來說說為什么對值傳參在函數體內的修改無效。因為a傳進去的時候會被復制了一份copy,此后的修改都是在臨時變量copy上,出了函數體copy被銷毀,a還是原來的a,根本就沒被修改過,所以才會值傳參對變量的修改無效。要使得對a的修改有效,一方面是傳入a的地址,也就是對指向a的指針作為值傳參(反正修改的不是a的指針,修改了也無所謂,反正只是修改a的指針的copy),此時a的指針的copy指向的內容也是a,因此對copy指向的內容修改會導致a的內容也被修改,check!另外一種方式就是引用傳參,引用傳參往往要比值傳參高效,因為它是直接將a作為參數傳入進去,而少了對a進行復制這部分的開銷,既然傳入進去的是a,那么對a的修改肯定也生效。


        為了證明上述廢話,我將代碼2中的AddToTail函數的第一個參數也作為引用參數傳入(指向指針的指針肯定正確啦,就不測試了),此時預測的結果是修改有效。代碼如下:

  1. #include <iostream>  
  2. #include <string>  
  3. using namespace std;  
  4.   
  5. struct ListNode  
  6. {  
  7.     int val;  
  8.     ListNode* next;  
  9. };  
  10.   
  11. void AddToTail(ListNode* &pHead, int value);  
  12.   
  13. int main() {  
  14.     // TODO  
  15.     ListNode* head = NULL;  
  16.     AddToTail(head, 10);  
  17.     if (head != NULL) {  
  18.         cout << head->val << endl;  
  19.     }  
  20.     else {  
  21.         cout << "head is NULL.." << endl;  
  22.     }  
  23.       
  24. }  
  25.   
  26. void AddToTail(ListNode* &pHead, int value) {  
  27.     ListNode* pNew = new ListNode();  
  28.     pNew->val = value;  
  29.     pNew->next = NULL;  
  30.   
  31.     if (pHead == NULL) {  
  32.         pHead = pNew;  
  33.     }  
  34.     else {  
  35.         ListNode* p = pHead;  
  36.         while (p->next != NULL) {  
  37.             p = p->next;  
  38.         }  
  39.         p->next = pNew;  
  40.     }  
  41. }  


        只是簡單的在代碼2中的函數聲明和定義中,第一個參數加入了"&"表示使用一個引用參數,結果如下圖,check!



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM