0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

單向鏈表中的存值與存址、數(shù)據(jù)與p_next分離問題

AGk5_ZLG_zhiyua ? 來源:未知 ? 作者:佚名 ? 2017-09-19 17:32 ? 次閱讀

周立功教授數(shù)年之心血之作《程序設(shè)計(jì)與數(shù)據(jù)結(jié)構(gòu)》以及《面向AMetal框架與接口編程(上)》,書本內(nèi)容公開后,在電子行業(yè)掀起一片學(xué)習(xí)熱潮。經(jīng)周立功教授授權(quán),本公眾號(hào)特對(duì)《程序設(shè)計(jì)與數(shù)據(jù)結(jié)構(gòu)》一書內(nèi)容進(jìn)行連載,愿共勉之。

第三章為算法與數(shù)據(jù)結(jié)構(gòu),本文為3.2 單向鏈表中的3.2.1 存值與存址和3.2.2 數(shù)據(jù)與p_next分離。

>>> 3.2.1存值與存址

1、存值

在結(jié)構(gòu)體中,雖然不能用“當(dāng)前結(jié)構(gòu)體類型”作為結(jié)構(gòu)體成員的類型,但可以用“指向當(dāng)前結(jié)構(gòu)體類型的指針”作為結(jié)構(gòu)體成員的類型。比如:

其中,slist 是single list 的縮寫,表明該結(jié)點(diǎn)是單向鏈表結(jié)點(diǎn)。由于AMetal平臺(tái)規(guī)定字母大小寫不能混用,且類型名、變量名、函數(shù)名等只能使用小寫字母,宏定義只能使用大寫字母,因此為了與AMetal平臺(tái)保持一致,類型名中的字母全部使用小寫。

由于p_next是指針類型而不是結(jié)構(gòu)體,它所指向的是同一種類型的結(jié)構(gòu)體變量。事實(shí)上,編譯器在確定結(jié)構(gòu)體的長度之前就已經(jīng)知道了指針的長度,因此這種類型的自引用是合法的。p_next不僅是struct _slist_node類型中的一員,而且又指向struct _slist_node類型的數(shù)據(jù),接著開始為這個(gè)結(jié)構(gòu)體創(chuàng)建類型名slist_node_t。即:

AMetal規(guī)定使用typedef定義的新類型名必須以“_t”結(jié)尾,為了與AMetal保持一致,后續(xù)的類型名結(jié)尾為“_t”。但一定要警惕下面這樣的聲明陷阱:

在聲明p_next指針時(shí),typedef還沒有結(jié)束,slist_node_t還不能使用,所以編譯器報(bào)告錯(cuò)誤信息。當(dāng)然,也可以在定義結(jié)構(gòu)體前先用typedef,即可在聲明p_next指針時(shí),使用類型定義slist_node_t。比如:

最后也可以結(jié)合上述2種方法按照以下形式進(jìn)行定義:

即定義了一個(gè)結(jié)構(gòu)體類型,這種方法常用于鏈表(list)、樹(tree)與許多其它的動(dòng)態(tài)數(shù)據(jù)結(jié)構(gòu)。p_next稱為鏈(link),每個(gè)結(jié)構(gòu)將通過p_next鏈接到后面的結(jié)構(gòu),詳見圖 3.1。其中,data用于存放結(jié)點(diǎn)中的數(shù)據(jù),該數(shù)據(jù)是由調(diào)用者(應(yīng)用程序)提供的,p_next用于存放指向鏈表中下一個(gè)結(jié)點(diǎn)的指針(地址)。其中的箭頭表示鏈,p_next的值是下一個(gè)結(jié)點(diǎn)的地址,當(dāng)p_next的值為NULL(0),表示鏈表已經(jīng)結(jié)束。因此可以將鏈表想象為一系列連續(xù)的元素,元素與元素之間的鏈接關(guān)系只是為了確保所有的元素都可以被訪問。如果錯(cuò)誤地丟失了一個(gè)鏈接,則從這個(gè)位置開始往后的所有元素都無法訪問。

圖 3.1 鏈表示意圖

通常需要定義一個(gè)指向鏈表頭結(jié)點(diǎn)的指針p_head,便于從鏈表的頭結(jié)點(diǎn)開始,順序地訪問鏈表中所有的結(jié)點(diǎn)。比如:

添加頭結(jié)點(diǎn)p_head后,完整的鏈表示意圖詳見圖3.2。

圖3.2 添加指向鏈表頭結(jié)點(diǎn)的指針

此時(shí),只要獲取p_head的值,即可依次遍歷(訪問)鏈表的所有結(jié)點(diǎn)。比如:

對(duì)于操作鏈表的函數(shù),必須進(jìn)行測試,以確保在操作空鏈表是也是正確的。如果直接使用p_head訪問各個(gè)結(jié)點(diǎn),當(dāng)遍歷結(jié)束后,則p_head的值為NULL,它不再指向第一個(gè)結(jié)點(diǎn),從而丟失了整個(gè)鏈表,因此必須通過一個(gè)臨時(shí)指針變量訪問鏈表的各個(gè)結(jié)點(diǎn)。比如:

接下來,考慮將結(jié)點(diǎn)添加到鏈表的尾部。在初始狀態(tài)下,鏈表是一個(gè)不包含任何結(jié)點(diǎn)的空表,此時(shí)p_head為NULL,那么新增的結(jié)點(diǎn)就是頭結(jié)點(diǎn),直接修改p_head的值,使其從NULL變?yōu)橹赶蛐陆Y(jié)點(diǎn)的指針,鏈表的變化詳見圖3.3。

圖3.3 鏈表為空時(shí)新增結(jié)點(diǎn)

由于新結(jié)點(diǎn)添加在鏈表的尾部,因此新結(jié)點(diǎn)中p_next的值為NULL,詳見程序清單3.6。

程序清單3.6 新增結(jié)點(diǎn)范例程序(鏈表為空)

現(xiàn)在我們來編寫一個(gè)簡單的示例,驗(yàn)證結(jié)點(diǎn)是否添加成功,詳見程序清單3.7。

程序清單3.7 添加結(jié)點(diǎn)范例程序(1)

如果結(jié)點(diǎn)加入成功,則可以通過printf將數(shù)據(jù)1打印出來。遺憾的是,運(yùn)行該程序后,什么現(xiàn)象都沒有看到。當(dāng)鏈表為空時(shí),添加一個(gè)結(jié)點(diǎn)的核心工作是“修改p_head的值,使其從NULL變?yōu)橹赶蛐陆Y(jié)點(diǎn)的指針”。在調(diào)用slist_add_tail()后,p_head被修改了嗎?

當(dāng)將指針傳遞給函數(shù)時(shí),其傳遞的是值。如果想要修改原指針,而不是指針的副本,則需要傳遞指針的指針。p_head是在主程序中定義的,其后僅僅是將NULL值作為實(shí)參傳遞給了slist_add_tail()的形參。此后p_head與slist_add_tail()再無任何關(guān)聯(lián),因此slist_add_tail()根本不可能修改p_head。要想在調(diào)用時(shí)修改p_head,則必須將該指針的地址傳遞給slist_add_tail(),詳見程序清單3.8。

程序清單3.8 鏈表為空時(shí)新增結(jié)點(diǎn)的范例程序

如程序清單3.9所示的測試程序可以驗(yàn)證添加結(jié)點(diǎn)是否成功,首先初始化鏈表為空,接著傳遞p_head的地址,然后從頭結(jié)點(diǎn)開始,依次訪問各個(gè)結(jié)點(diǎn)。

程序清單3.9 添加結(jié)點(diǎn)范例程序(2)

當(dāng)鏈表不為空時(shí),假定已經(jīng)存在一個(gè)值為data1的結(jié)點(diǎn),再添加一個(gè)值為data2的結(jié)點(diǎn),鏈表的變化詳見圖3.4。

圖3.4 鏈表非空時(shí)新增結(jié)點(diǎn)

其實(shí)現(xiàn)的過程僅需要修改原鏈表尾結(jié)點(diǎn)p_next的值,使其從NULL指針變?yōu)橹赶蛐陆Y(jié)點(diǎn)的指針,詳見程序清單3.10。

程序清單3.10 新增結(jié)點(diǎn)范例程序

現(xiàn)在可以在程序清單3.9的基礎(chǔ)上,添加更多的結(jié)點(diǎn)作為測試程序,詳見程序清單3.11。

程序清單3.11 添加結(jié)點(diǎn)范例程序(3)

通過該程序可以驗(yàn)證結(jié)點(diǎn)添加成功,但仔細(xì)觀察程序清單3.10可以發(fā)現(xiàn),新增一個(gè)結(jié)點(diǎn)時(shí),需要判定當(dāng)前鏈表是否為空,然后再根據(jù)實(shí)際情況作出相應(yīng)的處理。產(chǎn)生條件判斷的原因是鏈表可能為空,沒有一個(gè)有效結(jié)點(diǎn)。如果鏈表初始時(shí)就存在一個(gè)結(jié)點(diǎn)head:

由于這是一個(gè)實(shí)際的結(jié)點(diǎn),不再是指向頭結(jié)點(diǎn)的指針,因此鏈表不可能為空,鏈表示意圖詳見圖 3.5。

圖 3.5 鏈表示意圖

對(duì)于這種類型的鏈表,始終存在一個(gè)無需有效數(shù)據(jù)的頭結(jié)點(diǎn),對(duì)于空鏈表,其至少包含該頭結(jié)點(diǎn),空鏈表示意圖詳見圖3.6。由于在初始化時(shí)不包含其它任何結(jié)點(diǎn),因此p_next的值為NULL。

圖3.6 空鏈表示意圖

當(dāng)需要添加一個(gè)新的結(jié)點(diǎn)時(shí),則從頭結(jié)點(diǎn)開始尋找尾結(jié)點(diǎn)。當(dāng)找到尾結(jié)點(diǎn)時(shí),則修改尾結(jié)點(diǎn)的p_next值,使其從NULL指針變?yōu)橹赶蛐陆Y(jié)點(diǎn)的指針,詳見程序清單3.12。

程序清單3.12 新增結(jié)點(diǎn)范例程序

注意,這里的p_head始終指向存在的頭結(jié)點(diǎn),與程序清單3.6中的p_head意義不同,可以使用如程序清單3.13所示的測試程序?qū)ζ溥M(jìn)行測試,由于初始化時(shí)無后繼結(jié)點(diǎn),因此p_next域的值為NULL。

程序清單3.13 添加結(jié)點(diǎn)范例程序(4)

雖然如程序清單3.12所示的程序不再使用判斷語句,但又帶來了新的問題,頭結(jié)點(diǎn)的data被閑置,僅使用了p_next,則勢必浪費(fèi)內(nèi)存。當(dāng)然,對(duì)于當(dāng)前示例來講data是int類型數(shù)據(jù),僅占用4個(gè)字節(jié),浪費(fèi)4個(gè)字節(jié)或許還能接受,如果data是其它類型呢?

如果鏈表的元素是學(xué)生記錄中的數(shù)據(jù),由于學(xué)生記錄中的數(shù)據(jù)分別為不同類型的數(shù)據(jù),因此結(jié)構(gòu)體是最好的選擇。而作為范例程序無法面面俱到,所以僅以幾個(gè)典型的數(shù)據(jù)為例作為結(jié)構(gòu)體的成員?;诖?,專門為學(xué)生記錄中的數(shù)據(jù)定義一個(gè)結(jié)構(gòu)體類型與新的結(jié)構(gòu)體類型名。其數(shù)據(jù)類型定義如下:

即可用此結(jié)構(gòu)體存儲(chǔ)學(xué)生記錄中的數(shù)據(jù),其成員在內(nèi)存中的存儲(chǔ)關(guān)系詳見圖 3.7。如果將element_type_t聲明與student_t相同的類型,則鏈表數(shù)據(jù)結(jié)構(gòu)為:

圖 3.7

即與應(yīng)用程序相關(guān)的數(shù)據(jù)data的類型為另一個(gè)結(jié)構(gòu)體類型student_t。

此時(shí)只要定義一個(gè)slist_node_t類型的變量node,即可引用結(jié)構(gòu)體的成員:

那么該鏈表各成員在內(nèi)存中的存儲(chǔ)關(guān)系就確定下來了,詳見圖 3.8。如果使用表達(dá)式

圖 3.8

即可通過node變量引用slist_node_t結(jié)構(gòu)體的成員data。此時(shí),只要將node.data看作一個(gè)student_t類型變量,即可使用表達(dá)式

引用student_t結(jié)構(gòu)體成員data的成員name(學(xué)生記錄中的數(shù)據(jù))。

當(dāng)鏈表中的數(shù)據(jù)從int類型變?yōu)閟tudent_t時(shí),浪費(fèi)的空間將是student_t類型的大小。這里僅僅是一個(gè)示例,學(xué)生記錄可能包含更多其它的信息,比如,學(xué)號(hào)、年級(jí)、血型、宿舍號(hào)等,則頭結(jié)點(diǎn)浪費(fèi)的空間將會(huì)更大。

同時(shí),這里也隱含了一個(gè)問題,數(shù)據(jù)類型的改變將導(dǎo)致程序行為的改變,使得該程序無法做到通用,必須在編譯前確定好數(shù)據(jù)類型,則程序不能以通用庫的形式發(fā)布。如果要使代碼通用,就要使用能接受任意數(shù)據(jù)類型的void *。

2、存址

為了通用還是在鏈表中存放void *類型的元素,即可用鏈表存儲(chǔ)用戶傳入的任意指針類型數(shù)據(jù),則鏈表結(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)定義如下:

其中,結(jié)點(diǎn)的數(shù)據(jù)域類型為void *類型指針,data指向用戶數(shù)據(jù),結(jié)點(diǎn)中的數(shù)據(jù)是由調(diào)用者(應(yīng)用程序)提供的用戶數(shù)據(jù)。

雖然void *看起來是一個(gè)指針,其本質(zhì)上則是一個(gè)整數(shù),因?yàn)樵诖蠖鄶?shù)編譯器中指針與int占用的存儲(chǔ)空間大小一樣,所以通用鏈表是一個(gè)結(jié)點(diǎn)數(shù)據(jù)域類型為int型的鏈表,只不過結(jié)點(diǎn)的數(shù)據(jù)域中存儲(chǔ)的是與應(yīng)用程序關(guān)聯(lián)的用戶數(shù)據(jù)的地址。

假設(shè)存儲(chǔ)在struct _student結(jié)構(gòu)體學(xué)生記錄中的數(shù)據(jù)就是用戶數(shù)據(jù),那么只要將存儲(chǔ)學(xué)生記錄的結(jié)構(gòu)體變量的地址傳遞給鏈表結(jié)點(diǎn)的數(shù)據(jù)域就行了,即p->data指向用戶數(shù)據(jù)的結(jié)構(gòu)體存儲(chǔ)空間,詳見圖 3.9。如果void *指針指向的不是結(jié)構(gòu)體或者字符串,而是int型之類的簡單類型,那么只要在使用時(shí)進(jìn)行強(qiáng)制類型轉(zhuǎn)換即可。

圖 3.9 data指向用戶數(shù)據(jù)

如果為了使鏈表數(shù)據(jù)與學(xué)生記錄結(jié)構(gòu)體關(guān)聯(lián),則必須先定義一個(gè)學(xué)生記錄,然后將鏈表結(jié)點(diǎn)中的void *指針指向該學(xué)生記錄。與之前直接將學(xué)生結(jié)構(gòu)體作為鏈表結(jié)點(diǎn)的數(shù)據(jù)成員的鏈表相比,每個(gè)結(jié)點(diǎn)都會(huì)多耗費(fèi)一個(gè)void *指針的空間。雖然一個(gè)結(jié)點(diǎn)耗費(fèi)的空間并不多,但如果結(jié)點(diǎn)很多,其浪費(fèi)的內(nèi)存還是相當(dāng)可觀的,特別是在一些內(nèi)存資源本身就很緊張的嵌入式系統(tǒng)中。

顯然,要想節(jié)省內(nèi)存空間,則不能定義void *類型指針,必須將數(shù)據(jù)(比如,學(xué)生記錄)和鏈表結(jié)點(diǎn)的p_next放在一起,但這樣做則無法做到重用鏈表程序。

分析當(dāng)前鏈表結(jié)點(diǎn)的定義,其主要包含兩個(gè)部分:鏈表關(guān)心的p_next指針和用戶關(guān)心的data數(shù)據(jù)?;仡櫲绯绦蚯鍐?.12所示的slist_add_tail()函數(shù),沒有出現(xiàn)任何訪問data的代碼,從而說明data與鏈表無關(guān)。既然如此,是否可以將它們分離呢?

>>> 3.2.2 數(shù)據(jù)與p_next分離

由于鏈表只關(guān)心p_next指針,因此完全沒有必要在鏈表結(jié)點(diǎn)中定義數(shù)據(jù)域,那么只保留p_next指針就好了。鏈表結(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)(slist.h)定義如下:

由于結(jié)點(diǎn)中沒有任何數(shù)據(jù),因此節(jié)省了內(nèi)存空間,其示意圖詳見圖3.10。

圖3.10 鏈表示意圖

當(dāng)用戶需要使用鏈表管理數(shù)據(jù)時(shí),僅需關(guān)聯(lián)數(shù)據(jù)和鏈表結(jié)點(diǎn),最簡單的方式是將數(shù)據(jù)和鏈表結(jié)點(diǎn)打包在一起。以int類型數(shù)據(jù)為例,首先將鏈表結(jié)點(diǎn)作為它的一個(gè)成員,再添加與用戶相關(guān)的int類型數(shù)據(jù),該結(jié)構(gòu)體定義如下:

由此可見,無論是什么數(shù)據(jù),鏈表結(jié)點(diǎn)只是用戶數(shù)據(jù)記錄的一個(gè)成員。當(dāng)調(diào)用鏈表接口時(shí),僅需將node的地址作為鏈表接口參數(shù)即可。在定義鏈表結(jié)點(diǎn)的數(shù)據(jù)結(jié)構(gòu)時(shí),由于僅刪除了data成員,因此還是可以直接使用原來的slist_add_tail()函數(shù),管理int型數(shù)據(jù)的范例程序詳見程序清單3.14。

程序清單3.14 管理int型數(shù)據(jù)的范例程序

由于用戶需要初始化head為NULL,且遍歷時(shí)需要操作各個(gè)結(jié)點(diǎn)的p_next指針。而將數(shù)據(jù)和p_next分離的目的就是使各自的功能職責(zé)分離,鏈表只需要關(guān)心p_next的處理,用戶只關(guān)心數(shù)據(jù)的處理。因此,對(duì)于用戶來說,鏈表結(jié)點(diǎn)的定義就是一個(gè)“黑盒子”,只能通過鏈表提供的接口訪問鏈表,不應(yīng)該訪問鏈表結(jié)點(diǎn)的具體成員。

為了完成頭結(jié)點(diǎn)的初始賦值,應(yīng)該提供一個(gè)初始化函數(shù),其本質(zhì)上就是將頭結(jié)點(diǎn)中的p_next成員設(shè)置為NULL。鏈表初始化函數(shù)原型為:

由于頭結(jié)點(diǎn)的類型與其它普通結(jié)點(diǎn)的類型一樣,因此很容易讓用戶誤以為,這是初始化所有結(jié)點(diǎn)的函數(shù)。實(shí)際上,頭結(jié)點(diǎn)與普通結(jié)點(diǎn)的含義是不一樣的,由于只要獲取頭結(jié)點(diǎn)就可以遍歷整個(gè)鏈表,因此頭結(jié)點(diǎn)往往是被鏈表的擁有者持有,而普通結(jié)點(diǎn)僅僅代表單一的一個(gè)結(jié)點(diǎn)。為了避免用戶將頭結(jié)點(diǎn)和其它結(jié)點(diǎn)混淆,需要再定義一個(gè)頭結(jié)點(diǎn)類型(slist.h):

基于此,將鏈表初始化函數(shù)原型(slist.h)修改為:

其中,p_head指向待初始化的鏈表頭結(jié)點(diǎn),slist_init()函數(shù)的實(shí)現(xiàn)詳見程序清單3.15。

程序清單3.15 鏈表初始化函數(shù)

在向鏈表添加結(jié)點(diǎn)前,需要初始化頭結(jié)點(diǎn)。即:

由于重新定義了頭結(jié)點(diǎn)的類型,因此添加結(jié)點(diǎn)的函數(shù)原型也應(yīng)該進(jìn)行相應(yīng)的修改。即:

其中,p_head指向鏈表頭結(jié)點(diǎn),p_node為新增的結(jié)點(diǎn),slist_add_tail()函數(shù)的實(shí)現(xiàn)詳見程序清單3.16。

程序清單3.16 新增結(jié)點(diǎn)范例程序

同理,當(dāng)前鏈表的遍歷采用的還是直接訪問結(jié)點(diǎn)成員的方式,其核心代碼如下:

這里主要對(duì)鏈表作了三個(gè)操作:(1)得到第一個(gè)用戶結(jié)點(diǎn);(2)得到當(dāng)前結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn);(3)判斷鏈表是否結(jié)束,與結(jié)束標(biāo)記(NULL)比較。

基于此,將分別提供三個(gè)對(duì)應(yīng)的接口來實(shí)現(xiàn)這些功能,避免用戶直接訪問結(jié)點(diǎn)成員。它們的函數(shù)原型為(slist.h):

其實(shí)現(xiàn)代碼詳見程序清單3.17。

程序清單3.17 遍歷相關(guān)函數(shù)實(shí)現(xiàn)

程序中獲取的第一個(gè)用戶結(jié)點(diǎn),其實(shí)質(zhì)上就是頭結(jié)點(diǎn)的下一個(gè)結(jié)點(diǎn),因此可以直接調(diào)用slist_next_get()實(shí)現(xiàn)。盡管slist_next_get()在實(shí)現(xiàn)時(shí)并沒有用到參數(shù)p_head,但還是將p_head參數(shù)傳進(jìn)來了,因?yàn)閷?shí)現(xiàn)其它的功能時(shí)將會(huì)用到p_head參數(shù),比如,判斷p_pos是否在鏈表中。當(dāng)有了這些接口函數(shù)后,即可完成遍歷,詳見程序清單3.18。

程序清單3.18 使用各個(gè)接口函數(shù)實(shí)現(xiàn)遍歷的范例程序

由此可見,slist_begin_get()和slist_end_get()的返回值決定了當(dāng)前有效結(jié)點(diǎn)的范圍,其范圍為一個(gè)半開半閉的空間,即:[begin,end),包括begin,但是不包括end。當(dāng)begin與end相等時(shí),表明當(dāng)前鏈表為空,沒有一個(gè)有效結(jié)點(diǎn)。

在程序清單3.18所示的遍歷程序中,只有printf()語句才是用戶實(shí)際關(guān)心的語句,其它語句都是固定的模式,為此可以封裝一個(gè)通用的遍歷函數(shù),便于用戶順序處理與各個(gè)鏈表結(jié)點(diǎn)相關(guān)聯(lián)的數(shù)據(jù)。顯然,只有使用鏈表的用戶才知道數(shù)據(jù)的具體含義,對(duì)數(shù)據(jù)的實(shí)際處理應(yīng)該交由用戶完成,比如,程序清單3.18中的打印語句,因此訪問數(shù)據(jù)的行為應(yīng)該由用戶定義,定義一個(gè)回調(diào)函數(shù),通過參數(shù)傳遞給遍歷函數(shù),每遍歷到一個(gè)結(jié)點(diǎn)時(shí),都調(diào)用該回調(diào)函數(shù)處理對(duì)數(shù)據(jù)進(jìn)行處理。遍歷鏈表的函數(shù)原型(slist.h)為:

其中,p_head指向鏈表頭結(jié)點(diǎn),pfn_node_process為結(jié)點(diǎn)處理回調(diào)函數(shù)。每遍歷到一個(gè)結(jié)點(diǎn)時(shí),都會(huì)調(diào)用pfn_node_process指向的函數(shù),便于用戶根據(jù)需要自行處理結(jié)點(diǎn)數(shù)據(jù)。當(dāng)調(diào)用該回調(diào)函數(shù)時(shí),會(huì)自動(dòng)將用戶參數(shù)p_arg作為回調(diào)函數(shù)的第1個(gè)參數(shù),將指向當(dāng)前遍歷到的結(jié)點(diǎn)的指針作為回調(diào)函數(shù)的第2個(gè)參數(shù)。

當(dāng)遍歷到某個(gè)結(jié)點(diǎn)時(shí),用戶可能希望終止遍歷,此時(shí)只要在回調(diào)函數(shù)中返回負(fù)值即可。一般地,若要繼續(xù)遍歷,函數(shù)執(zhí)行結(jié)束后返回0。slist_foreach()函數(shù)的實(shí)現(xiàn)詳見程序清單3.19。

程序清單3.19 遍歷鏈表范例程序

現(xiàn)在可以使用這些接口函數(shù),迭代如程序清單3.14所示的功能,詳見程序清單3.20。

程序清單3.20 管理int型數(shù)據(jù)的范例程序

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    568

    瀏覽量

    40030
  • 程序設(shè)計(jì)
    +關(guān)注

    關(guān)注

    3

    文章

    261

    瀏覽量

    30317
  • 周立功
    +關(guān)注

    關(guān)注

    38

    文章

    130

    瀏覽量

    37438
  • 鏈表
    +關(guān)注

    關(guān)注

    0

    文章

    80

    瀏覽量

    10520

原文標(biāo)題:周立功:輕松掌握單向鏈表中的存值與存址、數(shù)據(jù)與p_next分離

文章出處:【微信號(hào):ZLG_zhiyuan,微信公眾號(hào):ZLG致遠(yuǎn)電子】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    FPGA的設(shè)計(jì)為什么避免使用鎖

    前言 在FPGA的設(shè)計(jì),避免使用鎖器是幾乎所有FPGA工程師的共識(shí),Xilinx和Altera也在手冊中提示大家要慎用鎖器,除非你明確知道你確實(shí)需要一個(gè)latch來解決問題。而且目前網(wǎng)上大多數(shù)
    的頭像 發(fā)表于 11-16 11:42 ?8187次閱讀
    FPGA的設(shè)計(jì)<b class='flag-5'>中</b>為什么避免使用鎖<b class='flag-5'>存</b>器

    C語言單向鏈表

    strName[16];//用指針的話會(huì)出訪問沖突異常 struct NODE *next;};//創(chuàng)建一個(gè)具有n個(gè)節(jié)點(diǎn)的鏈表,從鍵盤輸入數(shù)據(jù)將其初始化,并返回鏈表的首節(jié)點(diǎn)指針str
    發(fā)表于 05-22 15:53

    C語言學(xué)習(xí)筆記一:單向鏈表動(dòng)態(tài)數(shù)據(jù)結(jié)構(gòu)

    申請;(3)數(shù)組的元素順序關(guān)系由元素在數(shù)組的位置(即下標(biāo))確定,鏈表的結(jié)點(diǎn)順序關(guān)系由結(jié)點(diǎn)所包含的指針來體現(xiàn)。對(duì)于不是固定長度的列表,用可能最大長度的數(shù)組來描述,會(huì)浪費(fèi)許多內(nèi)存空間
    發(fā)表于 06-06 17:09

    請問FPGA用什么數(shù)據(jù)

    FPGA運(yùn)行時(shí)需要用外部存儲(chǔ)器一些采樣數(shù)據(jù):一組臨時(shí)存儲(chǔ)即可,幾十k字節(jié);另一組長期掉電不能丟失,也有幾十k字節(jié);分別用什么存儲(chǔ)器?FPGA開發(fā)板上有三個(gè)片子:SDRAM、FLASH、EEPROM(I2C),用起來有什么區(qū)別
    發(fā)表于 03-28 12:03

    器的缺點(diǎn)和優(yōu)點(diǎn)

    器(latch)---對(duì)脈沖電平敏感,在時(shí)鐘脈沖的電平作用下改變狀態(tài)鎖器是電平觸發(fā)的存儲(chǔ)單元,數(shù)據(jù)存儲(chǔ)的動(dòng)作取決于輸入時(shí)鐘(或者使能)信號(hào)的電平,僅當(dāng)鎖
    發(fā)表于 04-23 03:35

    玩轉(zhuǎn)C語言鏈表-鏈表各類操作詳解

    ));  }  p2->next = NULL; //此句就是根據(jù)單向鏈表的最后一個(gè)節(jié)點(diǎn)要指向NULL  free(p1); //
    發(fā)表于 09-18 13:30

    器的相關(guān)資料下載

    P0口作為分時(shí)復(fù)用接口,既要作為數(shù)據(jù)總線口,又要作為地址總線口 輸出的低8位地需要用8位鎖器鎖 ALE的下降沿將
    發(fā)表于 12-13 08:23

    數(shù)據(jù) 采--傳系統(tǒng)(FPGA)

    更長時(shí)間的觀測數(shù)據(jù)。 另外,NVME SSD硬盤為雙向全雙工方式,讀盤與存盤互不影響。在高速存盤的同時(shí)即可將盤數(shù)據(jù)高速讀出。在一些高校研究領(lǐng)域,該系統(tǒng)還可以用于近存儲(chǔ)計(jì)算、算一體等
    發(fā)表于 12-16 11:33

    器的作用是什么?

    ; i<9; i++) { LE = 0;//輸出使能,鎖器不輸出數(shù)據(jù) P0 = LedOut; LE = 1;//輸出使能,鎖器將8位數(shù)
    發(fā)表于 10-26 07:18

    器,鎖器是什么意思

    器,鎖器是什么意思 鎖器定義一位鐘控D觸發(fā)器只能傳送或存儲(chǔ)一位二進(jìn)制數(shù)據(jù),而在實(shí)際工作往往是一次傳送或
    發(fā)表于 03-09 09:44 ?1.2w次閱讀

    周立功新著內(nèi)容分享:雙向鏈表是什么?

    單向鏈表的添加、刪除操作,都必須找到當(dāng)前結(jié)點(diǎn)的上一個(gè)結(jié)點(diǎn),以便修改上一個(gè)結(jié)點(diǎn)的p_next指針完成相應(yīng)的操作。
    的頭像 發(fā)表于 09-22 18:24 ?5929次閱讀

    器詳解

    P0口作為分時(shí)復(fù)用接口,既要作為數(shù)據(jù)總線口,又要作為地址總線口 輸出的低8位地需要用8位鎖器鎖 ALE的下降沿將
    發(fā)表于 11-26 20:51 ?11次下載
    鎖<b class='flag-5'>存</b>器詳解

    Hadoop大數(shù)據(jù)分離方案:計(jì)算層無縫對(duì)接存儲(chǔ)系統(tǒng)

    Hadoop的誕生改變了企業(yè)對(duì)數(shù)據(jù)的存儲(chǔ)、處理和分析的過程,加速了大數(shù)據(jù)的發(fā)展。隨著大數(shù)據(jù)系統(tǒng)建設(shè)的深入,企業(yè)的數(shù)據(jù)基礎(chǔ)設(shè)施易出現(xiàn)計(jì)算資源浪費(fèi)、存儲(chǔ)性能低、管理成本過高等挑戰(zhàn)。相比
    的頭像 發(fā)表于 12-26 14:45 ?1198次閱讀
    Hadoop大<b class='flag-5'>數(shù)據(jù)</b><b class='flag-5'>存</b>算<b class='flag-5'>分離</b>方案:計(jì)算層無縫對(duì)接存儲(chǔ)系統(tǒng)

    Apache Doris巨大飛躍:分離新架構(gòu)介紹

    歷史上,數(shù)據(jù)分析需求的不斷提升(更大的數(shù)據(jù)規(guī)模、更快的處理速度、更低的使用成本)和計(jì)算基礎(chǔ)設(shè)施的不斷進(jìn)化(從專用的高端硬件、到低成本的商用硬件、到云計(jì)算服務(wù)),這兩大因素推動(dòng)數(shù)據(jù)倉庫的架構(gòu)大體經(jīng)歷了三個(gè)時(shí)代:軟硬一體的一體機(jī)時(shí)代
    的頭像 發(fā)表于 08-04 11:17 ?982次閱讀
    Apache Doris巨大飛躍:<b class='flag-5'>存</b>算<b class='flag-5'>分離</b>新架構(gòu)介紹

    LinkedBlockingQueue基于單向鏈表的實(shí)現(xiàn)

    的 LinkedBlockingQueue。它的底層基于單向鏈表實(shí)現(xiàn)。 先看一看它的 Node 內(nèi)部類和主要屬性、構(gòu)造函數(shù)。 Node static class Node E > { E item; Node next; Nod
    的頭像 發(fā)表于 10-13 11:41 ?541次閱讀
    LinkedBlockingQueue基于<b class='flag-5'>單向</b><b class='flag-5'>鏈表</b>的實(shí)現(xiàn)