詳解C語(yǔ)言中二級(jí)指針與鏈表的應(yīng)用
前言
這篇文章即將解決你看不懂或者不會(huì)寫鏈表的基本操作的問題,對(duì)于初學(xué)者而言,有很多地方肯定是費(fèi)解的。比如函數(shù)的參數(shù)列表的多樣化,動(dòng)態(tài)分配內(nèi)存空間函數(shù)malloc等,其實(shí)這些知識(shí)和指針聯(lián)系緊密,尤其是二級(jí)指針。那么開始好好的學(xué)習(xí)這篇文章吧!
二級(jí)指針講解
簡(jiǎn)述:其實(shí)就是一個(gè)指針指向另一個(gè)指針的地址。
我們都知道指針指向地址,但是指針自身也是一個(gè)變量,當(dāng)然也可以被二級(jí)指針?biāo)赶颉?/p>
語(yǔ)法:形如 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 的地址為: %d\n", &x); printf("q 指向的地址為:%d\n", q); printf("*p的值為: %d\n", *p); //p指向指針q的地址,那么*p是解引用操作, //就等于了q本身 printf("x 的值為: %d\n", x); printf("q 存取的值為: %d\n", *q); printf("**p的值為: %d\n", **p); //**p相當(dāng)于解引用解了兩次,第一次先得到q本身, //第二次得到q指向地址的值 return 0; }
運(yùn)行結(jié)果:
鏈表的應(yīng)用
這里以帶頭結(jié)點(diǎn)的雙鏈表為例
定義雙鏈表的結(jié)構(gòu)體
typedef int ElemType;//將整型數(shù)據(jù)重命名為int typedef int Status;//整型重命名為Status //雙鏈表的數(shù)據(jù)結(jié)構(gòu)定義 typedef struct DouNode { ElemType data; //數(shù)據(jù)域 struct DouNode* head; //前驅(qū)指針 struct DouNode* next; //后繼指針 }DousList, * LinkList;// 結(jié)點(diǎn)指針
代碼解釋:
利用typedef對(duì)數(shù)據(jù)類型進(jìn)行重命名,只要在后面遇到的 ElemType和 Status都是整型就夠了。雙鏈表結(jié)構(gòu)體包含三個(gè)部分:數(shù)據(jù)域、前驅(qū)指針、后繼指針,與單鏈表的區(qū)別就是多了一個(gè)前驅(qū)指針。然后大括號(hào)結(jié)束部分也是重命名,此時(shí)DousList和DouNode效果一樣,都是結(jié)構(gòu)體名,然后LinkList是指向結(jié)點(diǎn)的指針。
具體使用:
LinkList L,L是一個(gè)指針,DousList *P,P也是一個(gè)指針,屬于兩種創(chuàng)建方式。
創(chuàng)建雙鏈表
使用兩種正確的創(chuàng)建鏈表形式和一種錯(cuò)誤的形式,對(duì)比著記憶創(chuàng)建方法
傳入一級(jí)指針
這種方式并不能成功創(chuàng)建
代碼演示:
void CreateDouList(LinkList L, int n) { LinkList ptr; int i; L = (LinkList)malloc(sizeof(DousList)); //為頭結(jié)點(diǎn)申請(qǐng)空間 L->next = NULL; L->head = NULL; L->data = n;//L->data記錄結(jié)點(diǎn)的個(gè)數(shù) ptr = L; for (i = 0; i < n; i++) { int value = 0; scanf("%d",&value); LinkList me = (LinkList)malloc(sizeof(DouNode)); me->data = value; //節(jié)點(diǎn)數(shù)據(jù)域 me->next = NULL; me->head = NULL; ptr->next = me; me->head = ptr; ptr = ptr->next; //尾插法建表 } }
代碼解析:
這里的參數(shù)列表是 LinkList L 和 整型數(shù)據(jù) n,L是傳入的鏈表頭結(jié)點(diǎn)指針,n是用來記錄插入數(shù)據(jù)的個(gè)數(shù)的,在下面的for循環(huán)用做循環(huán)的次數(shù)。接下來使用malloc函數(shù)為L(zhǎng)鏈表分配內(nèi)存空間,malloc需要用指針來接收,左邊的括號(hào)是分配的指針類型,右邊的括號(hào)是分配的內(nèi)存空間大小。分配空間完成之后初始化前驅(qū)和后繼指針為空,數(shù)據(jù)域data記錄數(shù)據(jù)的個(gè)數(shù)。ptr指針初始等于L指針,接下來進(jìn)入n次循環(huán),創(chuàng)建待插入結(jié)點(diǎn)指針me并進(jìn)行分配內(nèi)存空間和初始化,最后三行代碼進(jìn)行尾插法建立鏈表:
尾插法:
先讓ptr的后繼指針指向me,然后me的head指針指向ptr,這就相當(dāng)于在鏈表頭把me結(jié)點(diǎn)插入鏈表,然后ptr指向這個(gè)插入的新結(jié)點(diǎn),這就保證了每次插入的結(jié)點(diǎn)都在上一個(gè)插入的結(jié)點(diǎn)之后。
但是這樣真的在鏈表中插入數(shù)據(jù)了嗎 ,來看看調(diào)試結(jié)果:
進(jìn)入遍歷的程序時(shí),讓創(chuàng)建的ptr指針指向L鏈表的后繼,立馬就出現(xiàn)了空指針異常,但是上面明明插入數(shù)據(jù)了,原因是什么呢? 很明顯,這里的鏈表L并未完成插入數(shù)據(jù)。這是因?yàn)槲覀冊(cè)趧?chuàng)建鏈表的函數(shù)里傳入的只是鏈表的指針L,那么在函數(shù)里這個(gè)指針只是一個(gè)副本,在這里給他增大內(nèi)存空間并不會(huì)影響到實(shí)參鏈表,這和普通數(shù)據(jù)類型的值傳遞和地址傳遞的情況一致。
我們利用傳入指針地址來解決這個(gè)問題,兩個(gè)方法:指針的引用和二級(jí)指針
傳入指針的引用
函數(shù)的實(shí)現(xiàn)部分完全不用修改,只要形參列表加上一個(gè)引用符"&"即可。
void CreateDouList(LinkList &L, int n);
查看調(diào)試結(jié)果:
同樣的調(diào)試方法,傳入指針的引用之后可以清晰的看到L的data等于5,也就是存了五個(gè)數(shù)據(jù),然后對(duì)于的后繼結(jié)點(diǎn)的值都和尾插的結(jié)果一致,最后一個(gè)結(jié)點(diǎn)的后繼指針正好指向NULL,完全符合我們的設(shè)計(jì)的代碼。
傳入指針的引用之后,函數(shù)里鏈表的空間變化會(huì)導(dǎo)致實(shí)參里的鏈表空間變化,這樣做才能使插入操作完成,將結(jié)點(diǎn)插入到鏈表內(nèi)。
傳入二級(jí)指針
這個(gè)和指針的引用原理一樣,我主要分享給你們使用的形式
注意調(diào)用的時(shí)候?qū)崊⒁?ldquo;&”符,例:CreateDouList(&L,n);
void CreateDouList(LinkList *L, int n) { LinkList ptr; int i; *L = (LinkList)malloc(sizeof(DousList)); //為頭結(jié)點(diǎn)申請(qǐng)空間 (*L)->next = NULL; (*L)->head = NULL; (*L)->data = n;//L->data記錄結(jié)點(diǎn)的個(gè)數(shù) ptr = (*L); printf("開始插入數(shù)據(jù):\n"); for (i = 0; i < n; i++) { int value = 0; scanf("%d",&value); LinkList me = (LinkList)malloc(sizeof(DouNode)); me->data = value; //節(jié)點(diǎn)數(shù)據(jù)域 me->next = NULL; me->head = NULL; ptr->next = me; me->head = ptr; ptr = ptr->next; //尾插法建表 } }
這里形參列表的參數(shù)是 LinkList *L,和DousLIst **L效果一樣,是一個(gè)二級(jí)指針。如果用到指向鏈表的指針就需要一次接引用操作,寫成(*L)的形式。然后再去分配空間、進(jìn)行初始化、賦值給鏈表指針ptr等操作,這樣鏈表二級(jí)指針L的改變也會(huì)使實(shí)參的鏈表發(fā)生改變,可以查看調(diào)試結(jié)果。
調(diào)試結(jié)果:
以上就是詳解C語(yǔ)言中二級(jí)指針與鏈表的應(yīng)用的詳細(xì)內(nèi)容,更多關(guān)于C語(yǔ)言 二級(jí)指針 鏈表的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
c語(yǔ)言函數(shù)如何求兩個(gè)數(shù)的最大值
這篇文章主要介紹了c語(yǔ)言函數(shù)如何求兩個(gè)數(shù)的最大值問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12C++修煉之構(gòu)造函數(shù)與析構(gòu)函數(shù)
本章節(jié)我們將學(xué)習(xí)類的6個(gè)默認(rèn)成員函數(shù)中的構(gòu)造函數(shù)與析構(gòu)函數(shù),并對(duì)比C語(yǔ)言階段的內(nèi)容來學(xué)習(xí)它們的各自的特性,感興趣的同學(xué)可以參考閱讀2023-03-03C++設(shè)計(jì)模式之簡(jiǎn)單工廠模式的實(shí)現(xiàn)示例
這篇文章主要給大家介紹了關(guān)于C++設(shè)計(jì)模式之簡(jiǎn)單工廠模式的相關(guān)資料,簡(jiǎn)單工廠模式,主要用于創(chuàng)建對(duì)象,添加類時(shí),不會(huì)影響以前的系統(tǒng)代碼,需要的朋友可以參考下2021-06-06MFC控件之CListCtrl的應(yīng)用實(shí)例教程
這篇文章主要介紹了MFC控件中CListCtrl的應(yīng)用方法,包括了針對(duì)表格的一些操作,是MFC中比較重要的一個(gè)控件類,需要的朋友可以參考下2014-08-08C++關(guān)鍵字volatile學(xué)習(xí)筆記
這篇文章主要為大家介紹了C++關(guān)鍵字volatile學(xué)習(xí)筆記,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10