首頁 > 軟體

詳解C語言中二級指標與連結串列的應用

2022-07-06 18:04:29

前言

這篇文章即將解決你看不懂或者不會寫連結串列的基本操作的問題,對於初學者而言,有很多地方肯定是費解的。比如函數的參數列的多樣化,動態分配記憶體空間函數malloc等,其實這些知識和指標聯絡緊密,尤其是二級指標。那麼開始好好的學習這篇文章吧!

二級指標講解

簡述:其實就是一個指標指向另一個指標的地址。

我們都知道指標指向地址,但是指標自身也是一個變數,當然也可以被二級指標所指向。

語法:形如 int x = 10; int *q = &x; int **p = & q;

那麼這裡的q指標指向x的地址,p指標指向指標q的地址,*q可以得到x的值,*p可以得到q指標本身,**p也可以得到x的值。

程式碼範例:

int main(void)
{
    int x = 10; 
    int* q = &x;
    int** p = &q;    
    printf("x 的地址為:    %dn", &x);
    printf("q 指向的地址為:%dn", q);
    printf("*p的值為:      %dn", *p);   //p指向指標q的地址,那麼*p是解除參照操作,
                                          //就等於了q本身
    printf("x 的值為:     %dn", x);
    printf("q 存取的值為: %dn", *q);
    printf("**p的值為:    %dn", **p);    //**p相當於解除參照解了兩次,第一次先得到q本身,
                                          //第二次得到q指向地址的值
    return 0;
}

執行結果:

連結串列的應用 

這裡以帶頭結點的雙連結串列為例

定義雙連結串列的結構體

typedef int ElemType;//將整型資料重新命名為int
typedef int Status;//整型重新命名為Status
 
//雙連結串列的資料結構定義
typedef struct DouNode {
    ElemType data;               //資料域
    struct DouNode* head;        //前驅指標
    struct DouNode* next;        //後繼指標
}DousList, * LinkList;// 結點指標

程式碼解釋:

利用typedef對資料型別進行重新命名,只要在後面遇到的 ElemType和 Status都是整型就夠了。雙連結串列結構體包含三個部分:資料域、前驅指標、後繼指標,與單連結串列的區別就是多了一個前驅指標。然後大括號結束部分也是重新命名,此時DousList和DouNode效果一樣,都是結構體名,然後LinkList是指向結點的指標。

具體使用:

LinkList L,L是一個指標,DousList *P,P也是一個指標,屬於兩種建立方式。

建立雙連結串列

使用兩種正確的建立連結串列形式和一種錯誤的形式,對比著記憶建立方法

傳入一級指標

這種方式並不能成功建立

程式碼演示:

void CreateDouList(LinkList L, int n)
{
    LinkList  ptr;
    int i;
    L = (LinkList)malloc(sizeof(DousList));    //為頭結點申請空間
    L->next = NULL;
    L->head = NULL;
    L->data = n;//L->data記錄結點的個數
    ptr = L;
    for (i = 0; i < n; i++)
    {
        int value = 0;
        scanf("%d",&value);
        LinkList me = (LinkList)malloc(sizeof(DouNode));
        me->data = value;    //節點資料域
        me->next = NULL;
        me->head = NULL;
        ptr->next = me;     
        me->head = ptr;
        ptr = ptr->next;     //尾插法建表
    }
}

程式碼解析: 

這裡的參數列是 LinkList L 和 整型資料 n,L是傳入的連結串列頭結點指標,n是用來記錄插入資料的個數的,在下面的for迴圈用做迴圈的次數。接下來使用malloc函數為L連結串列分配記憶體空間,malloc需要用指標來接收,左邊的括號是分配的指標型別,右邊的括號是分配的記憶體空間大小。分配空間完成之後初始化前驅和後繼指標為空,資料域data記錄資料的個數。ptr指標初始等於L指標,接下來進入n次迴圈,建立待插入結點指標me並進行分配記憶體空間和初始化,最後三行程式碼進行尾插法建立連結串列:

尾插法:

先讓ptr的後繼指標指向me,然後me的head指標指向ptr,這就相當於在連結串列頭把me結點插入連結串列,然後ptr指向這個插入的新結點,這就保證了每次插入的結點都在上一個插入的結點之後。

但是這樣真的在連結串列中插入資料了嗎 ,來看看偵錯結果:

進入遍歷的程式時,讓建立的ptr指標指向L連結串列的後繼,立馬就出現了空指標異常,但是上面明明插入資料了,原因是什麼呢? 很明顯,這裡的連結串列L並未完成插入資料。這是因為我們在建立連結串列的函數裡傳入的只是連結串列的指標L,那麼在函數裡這個指標只是一個副本,在這裡給他增大記憶體空間並不會影響到實參連結串列,這和普通資料型別的值傳遞和地址傳遞的情況一致。

我們利用傳入指標地址來解決這個問題,兩個方法:指標的參照和二級指標

傳入指標的參照

函數的實現部分完全不用修改,只要形參列表加上一個參照符"&"即可。

void CreateDouList(LinkList &L, int n);

檢視偵錯結果:

同樣的偵錯方法,傳入指標的參照之後可以清晰的看到L的data等於5,也就是存了五個資料,然後對於的後繼結點的值都和尾插的結果一致,最後一個結點的後繼指標正好指向NULL,完全符合我們的設計的程式碼。

傳入指標的參照之後,函數裡連結串列的空間變化會導致實參裡的連結串列空間變化,這樣做才能使插入操作完成,將結點插入到連結串列內。

傳入二級指標

這個和指標的參照原理一樣,我主要分享給你們使用的形式

注意呼叫的時候實參要加“&”符,例:CreateDouList(&L,n);

void CreateDouList(LinkList *L, int n)
{
    LinkList  ptr;
    int i;
     *L = (LinkList)malloc(sizeof(DousList));    //為頭結點申請空間
    (*L)->next = NULL;
    (*L)->head = NULL;
    (*L)->data = n;//L->data記錄結點的個數
    ptr = (*L);
    printf("開始插入資料:n");
    for (i = 0; i < n; i++)
    {
        int value = 0;
        scanf("%d",&value);
        LinkList me = (LinkList)malloc(sizeof(DouNode));
        me->data = value;    //節點資料域
        me->next = NULL;
        me->head = NULL;
        ptr->next = me;     
        me->head = ptr;
        ptr = ptr->next;     //尾插法建表
    }
}

這裡形參列表的引數是 LinkList *L,和DousLIst **L效果一樣,是一個二級指標。如果用到指向連結串列的指標就需要一次接參照操作,寫成(*L)的形式。然後再去分配空間、進行初始化、賦值給連結串列指標ptr等操作,這樣連結串列二級指標L的改變也會使實參的連結串列發生改變,可以檢視偵錯結果。

偵錯結果:

以上就是詳解C語言中二級指標與連結串列的應用的詳細內容,更多關於C語言 二級指標 連結串列的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com