1. 程式人生 > 其它 >引用或指標作為函式引數——引數地址參與判斷條件

引用或指標作為函式引數——引數地址參與判斷條件

引用或指標作為函式引數——引數地址參與判斷條件

如下為雙鏈表所有程式碼

#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

​ 總結以下,就是當引數地址參與判斷時,使用指標傳遞或者引用傳遞,因為以上兩種傳遞會保留原實參的地址,保證判斷正確。