引用或指標作為函式引數——引數地址參與判斷條件
引用或指標作為函式引數——引數地址參與判斷條件
如下為雙鏈表所有程式碼
#include<iostream> #define ERROR 0 #define OK 1 #define NOTFOUND 0 using namespace std; typedef char ElemType; typedef struct LinkedNode { ElemType data; LinkedNode *next; } CLinkedList; void InitList(CLinkedList &L){ L.next = &L; } bool ListEmpty(CLinkedList L){ return (L.next == &L); } int ListLength(CLinkedList &L){ LinkedNode *temp = &L; int c =0; while(temp->next!=&L){ temp = temp->next; c++; } return c; } LinkedNode *ListInsertL(CLinkedList &L,ElemType x){ LinkedNode *toAdd = new LinkedNode; toAdd->data = x; toAdd->next = L.next; L.next = toAdd; return toAdd; } /*展示雙鏈表所有元素*/ void DispLinkedList(CLinkedList clinkedList) { if(ListEmpty(clinkedList)) return; /*temp指標用於遍歷連結串列中所有的資料元素*/ LinkedNode *temp = clinkedList.next; cout << &clinkedList << endl; int i = 1; while(temp!=&clinkedList){ /*輸出移動變數的地址和雙鏈表頭指標的地址*/ cout << "temp:" << temp << " | &clinkedList:" << &clinkedList << endl; /*輸出資料元素以及所在索引*/ cout<<"elment "<<i++<<" : "<<temp->data<<endl; temp = temp->next; } cout<<endl<<"while-loop end"<<endl; /*迴圈結束,對比移動變數和雙鏈表頭指標的地址*/ cout << "temp:" << temp << " &clinkedList :" << &clinkedList << endl; } int main(){ /*建立並初始化雙鏈表L*/ CLinkedList L,*pL; InitList(L); /*使用頭插法依次插入三個結點*/ ListInsertL(L,'c'); ListInsertL(L,'b'); ListInsertL(L,'a'); /*輸出雙鏈表所有資料元素*/ DispLinkedList(L); }
重點考察如下部分:
/*展示雙鏈表所有元素*/ void DispLinkedList(CLinkedList clinkedList) { if(ListEmpty(clinkedList)) return; /*temp指標用於遍歷連結串列中所有的資料元素*/ LinkedNode *temp = clinkedList.next; cout << &clinkedList << endl; int i = 1; while(temp!=&clinkedList){ /*輸出移動變數的地址和雙鏈表頭指標的地址*/ cout << "temp:" << temp << " | &clinkedList:" << &clinkedList << endl; /*輸出資料元素以及所在索引*/ cout<<"elment "<<i++<<" : "<<temp->data<<endl; temp = temp->next; } cout<<endl<<"while-loop end"<<endl; /*迴圈結束,對比移動變數和雙鏈表頭指標的地址*/ cout << "temp:" << temp << " &clinkedList :" << &clinkedList << endl; }
按照一般思維,若是對連結串列只讀,一般用值傳遞引數,而不是引用或者指標傳遞引數,因為值傳遞不影響實參,可以有效保護原有資料,相反,引用或者指標可能會對原資料產生改變[如 void merge_sort(int *arr,int l,int )]。我們嘗試將DispLinkedList函式中的引數傳遞改為值傳遞,再重新執行程式碼。
/*展示雙鏈表所有元素*/ void DispLinkedList(CLinkedList clinkedList) { if(ListEmpty(clinkedList)) return; /*temp指標用於遍歷連結串列中所有的資料元素*/ LinkedNode *temp = clinkedList.next; cout << &clinkedList << endl; int i = 1; while(temp!=&clinkedList){ /*輸出移動變數的地址和雙鏈表頭指標的地址*/ cout << "temp:" << temp << " | &clinkedList:" << &clinkedList << endl; /*輸出資料元素以及所在索引*/ cout<<"elment "<<i++<<" : "<<temp->data<<endl; temp = temp->next; } cout<<endl<<"while-loop end"<<endl; /*迴圈結束,對比移動變數和雙鏈表頭指標的地址*/ cout << "temp:" << temp << " &clinkedList :" << &clinkedList << endl; }
執行結果:
0x61fda0
temp:0x7616c0 | &clinkedList:0x61fda0
elment 1 : a
temp:0x7616a0 | &clinkedList:0x61fda0
elment 2 : b
temp:0x761680 | &clinkedList:0x61fda0
elment 3 : c
temp:0x61fe10 | &clinkedList:0x61fda0
elment 4 :
temp:0x7616c0 | &clinkedList:0x61fda0
elment 5 : a
temp:0x7616a0 | &clinkedList:0x61fda0
elment 6 : b
temp:0x761680 | &clinkedList:0x61fda0
elment 7 : c
temp:0x61fe10 | &clinkedList:0x61fda0
elment 8 :
.......
發現DispLinkedList中的while迴圈是個死迴圈,由輸出我們發現,這是因為用於遍歷的temp指標的指標永遠不等於值傳遞的雙鏈表引數的地址。
按理說,雙鏈表CLinkedList最後一個指標的指標域(*next)應該指向雙鏈表本身的頭指標,本應該不會出現死迴圈。但是,問題在於,當DispLinkedList使用值傳遞時,會在記憶體空間中新開闢一個記憶體地址,而新開闢的記憶體地址不等於原有雙鏈表頭指標的地址,因而temp!=&cLinkedList恆成立,while進入死迴圈。
因而,為了使引數的地址與原有雙鏈表的頭指標地址相同,我們應該使用引用傳遞或者指標傳遞來傳遞函式引數,如下。
/*展示雙鏈表所有元素*/
void DispLinkedList(CLinkedList clinkedList) {
if(ListEmpty(clinkedList)) return;
/*temp指標用於遍歷連結串列中所有的資料元素*/
LinkedNode *temp = clinkedList.next;
cout << &clinkedList << endl;
int i = 1;
while(temp!=&clinkedList){
/*輸出移動變數的地址和雙鏈表頭指標的地址*/
cout << "temp:" << temp << " | &clinkedList:" << &clinkedList << endl;
/*輸出資料元素以及所在索引*/
cout<<"elment "<<i++<<" : "<<temp->data<<endl;
temp = temp->next;
}
cout<<endl<<"while-loop end"<<endl;
/*迴圈結束,對比移動變數和雙鏈表頭指標的地址*/
cout << "temp:" << temp << " &clinkedList :" << &clinkedList << endl;
}
int main(){
/*建立並初始化雙鏈表L*/
CLinkedList L,*pL;
InitList(L);
/*使用頭插法依次插入三個結點*/
ListInsertL(L,'c');
ListInsertL(L,'b');
ListInsertL(L,'a');
/*輸出雙鏈表所有資料元素*/
DispLinkedList(L);
}
執行結果:
0x61fe10
temp:0xda16c0 | &clinkedList:0x61fe10
elment 1 : a
temp:0xda16a0 | &clinkedList:0x61fe10
elment 2 : b
temp:0xda1680 | &clinkedList:0x61fe10
elment 3 : c
while-loop end
temp:0x61fe10 &clinkedList :0x61fe10
總結以下,就是當引數地址參與判斷時,使用指標傳遞或者引用傳遞,因為以上兩種傳遞會保留原實參的地址,保證判斷正確。