在看書的時(shí)候有個(gè)往鏈表里添加節(jié)點(diǎn)的函數(shù)爆土,代碼中考慮到可能給出的頭指針為空搁嗓,并做另外一些處理贬丛。具體代碼如下:
#include <iostream>
#include <string>
using namespace std;
struct ListNode
{
int val;
ListNode* next;
};
void AddToTail(ListNode** pHead, int value);
int main() {
// TODO
}
void AddToTail(ListNode** pHead, int value) {
ListNode* pNew = new ListNode();
pNew->val = value;
pNew->next = NULL;
if (*pHead == NULL) {
*pHead = pNew;
}
else {
ListNode* p = *pHead;
while (p->next != NULL) {
p = p->next;
}
p->next = pNew;
}
}
網(wǎng)上其他人的博客中對(duì)函數(shù)AddToTail的參數(shù)的描述跟書中如出一轍:第一個(gè)參數(shù)pHead是一個(gè)指向指針的指針扇救,當(dāng)向一個(gè)空鏈表插入一個(gè)節(jié)點(diǎn)時(shí),新插入的節(jié)點(diǎn)是鏈表的頭指針橙垢,此時(shí)會(huì)改動(dòng)頭指針垛叨,因此必須把pHead參數(shù)設(shè)置為指向指針的指針。
為什么呢柜某?在以前學(xué)習(xí)C++的時(shí)候点额,我們只知道在參數(shù)中,以傳值的形式作為參數(shù)的變量在函數(shù)體內(nèi)被修改之后莺琳,出了函數(shù)體就會(huì)失效还棱,準(zhǔn)確的說(shuō)這個(gè)變量沒(méi)有被修改過(guò),因此需要傳入該變量的指針或者使用引用傳參的方式惭等≌涫郑可是上述AddToTail中已經(jīng)是一個(gè)指針了啊辞做?于是我測(cè)試了一下琳要,不使用指針的指針會(huì)怎樣:
#include <iostream>
#include <string>
using namespace std;
struct ListNode
{
int val;
ListNode* next;
};
void AddToTail(ListNode* pHead, int value);
int main() {
// TODO
ListNode* head = NULL;
AddToTail(head, 10);
if (head != NULL) {
cout << head->val << endl;
}
else {
cout << "head is NULL.." << endl;
}
}
void AddToTail(ListNode* pHead, int value) {
ListNode* pNew = new ListNode();
pNew->val = value;
pNew->next = NULL;
if (pHead == NULL) {
pHead = pNew;
}
else {
ListNode* p = pHead;
while (p->next != NULL) {
p = p->next;
}
p->next = pNew;
}
}
結(jié)果:
head is NULL..
作為指針pHead竟然真的沒(méi)被修改過(guò)!
其實(shí)真的很好理解秤茅,既然你懂得函數(shù)中的值傳參稚补,假設(shè)int a,作為參數(shù)傳入的時(shí)候沒(méi)被修改框喳,所以需要用指向a的指針课幕,那么應(yīng)該也可以理解厦坛,指針變量pHead作為參數(shù)傳入的時(shí)候被修改無(wú)效,因此需要用指向pHead的指針乍惊,只不過(guò)pHead本身就是一個(gè)指針了杜秸,所以才存在有指針的指針看起來(lái)稍微復(fù)雜一點(diǎn)的說(shuō)法。因?yàn)槿笠铮赶騛的指針作為參數(shù)傳入進(jìn)去時(shí)撬碟,如果你對(duì)它進(jìn)行修改,其實(shí)也是無(wú)效的莉撇,但是修改指針指向的內(nèi)容的修改是有效的呢蛤,也即,(&a)對(duì)a取地址得到的指針傳入進(jìn)去之后棍郎,此時(shí)你修改這個(gè)指針也是沒(méi)有什么實(shí)際作用的顾稀,原因我等下會(huì)說(shuō)。但是坝撑,你修改指針指向的內(nèi)容這就有效了,因此通常我們?cè)诤瘮?shù)體內(nèi)是修改對(duì)指針取內(nèi)容后的內(nèi)存粮揉,即*(&a)巡李。所以,你對(duì)指針pHead的修改時(shí)無(wú)效的扶认,只有對(duì)指向pHead的指針指向的內(nèi)容(很繞吧侨拦,其實(shí)就是pHead),這時(shí)候才是有效的辐宾,因此AddToTail的第一個(gè)參數(shù)必須用指針的指針狱从。
現(xiàn)在來(lái)說(shuō)說(shuō)為什么對(duì)值傳參在函數(shù)體內(nèi)的修改無(wú)效。因?yàn)閍傳進(jìn)去的時(shí)候會(huì)被復(fù)制了一份copy叠纹,此后的修改都是在臨時(shí)變量copy上季研,出了函數(shù)體copy被銷毀,a還是原來(lái)的a誉察,根本就沒(méi)被修改過(guò)与涡,所以才會(huì)值傳參對(duì)變量的修改無(wú)效。要使得對(duì)a的修改有效持偏,一方面是傳入a的地址驼卖,也就是對(duì)指向a的指針作為值傳參(反正修改的不是a的指針,修改了也無(wú)所謂鸿秆,反正只是修改a的指針的copy)酌畜,此時(shí)a的指針的copy指向的內(nèi)容也是a,因此對(duì)copy指向的內(nèi)容修改會(huì)導(dǎo)致a的內(nèi)容也被修改卿叽,check桥胞!另外一種方式就是引用傳參恳守,引用傳參往往要比值傳參高效,因?yàn)樗侵苯訉作為參數(shù)傳入進(jìn)去埠戳,而少了對(duì)a進(jìn)行復(fù)制這部分的開(kāi)銷井誉,既然傳入進(jìn)去的是a,那么對(duì)a的修改肯定也生效整胃。
為了證明上述廢話颗圣,我將代碼2中的AddToTail函數(shù)的第一個(gè)參數(shù)也作為引用參數(shù)傳入(指向指針的指針肯定正確啦,就不測(cè)試了)屁使,此時(shí)預(yù)測(cè)的結(jié)果是修改有效在岂。代碼如下:
#include <string>
using namespace std;
struct ListNode
{
int val;
ListNode* next;
};
void AddToTail(ListNode* &pHead, int value);
int main() {
// TODO
ListNode* head = NULL;
AddToTail(head, 10);
if (head != NULL) {
cout << head->val << endl;
}
else {
cout << "head is NULL.." << endl;
}
}
void AddToTail(ListNode* &pHead, int value) {
ListNode* pNew = new ListNode();
pNew->val = value;
pNew->next = NULL;
if (pHead == NULL) {
pHead = pNew;
}
else {
ListNode* p = pHead;
while (p->next != NULL) {
p = p->next;
}
p->next = pNew;
}
}
只是簡(jiǎn)單的在代碼2中的函數(shù)聲明和定義中,第一個(gè)參數(shù)加入了"&"表示使用一個(gè)引用參數(shù)蛮寂,結(jié)果如下蔽午,check!
10
轉(zhuǎn)載:https://blog.csdn.net/shen_jz2012/article/details/50631317