C語言的那些小秘密之鍊錶

2022-10-09 22:24:11 字數 2995 閱讀 9152

大多數的讀者在學習程式語言的時候都不喜歡那些枯燥的文字描述,包括我自己在開始學習程式設計的時候也是這樣,對於**的熱情遠遠高於文字,所以我在我寫東西的時候也不喜歡用枯燥的文字描述來向讀者講解,更喜歡用**加上適當的文字描述的方式進行講解,因為有些東西可能用枯燥的文字描述半天還不如實實在在的給讀者呈現出一段簡單的**,讓讀者理解得更加的透徹些。但是並不是說文字描述就沒用,文字描述也很重要,只是絕大部分讀者都更加的希望直接達到最終的效果,都想跳過那些中間的步驟。接下來我們接著上一篇部落格《c語言的那些小秘密之鍊錶(三)》的內容繼續講解linux核心雙向迴圈鍊錶。

[cpp] view plaincopystatic inline int list_empty(const struct list_head *head)

static inline int list_empty_careful(const struct list_head *head)

執行結果為:

[html] view plaincopyroot@ubuntu:/home/paixu/dlist_node# ./a

student num: 5 student name: stu5

student num: 4 student name: stu4

student num: 3 student name: stu3

student num: 2 student name: stu2

student num: 1 student name: stu1

使用list_empty()檢測,鍊錶非空

使用list_empty_careful()檢測,鍊錶非空

看看**就知道如何使用了,接下來看看鍊錶的合成。

[html] view plaincopystatic inline void __list_splice(struct list_head *list,

struct list_head *head)

在這種情況下會丟棄list所指向的頭結點,因為兩個鍊錶有兩個頭結點,所以我們必須要去掉其中乙個頭結點。只要list非空鏈,head無任何限制,該函式就能實現鍊錶的合併。

[cpp] view plaincopystatic inline void list_splice_init(struct list_head *list,

struct list_head *head)

}以上函式的功能是將乙個鍊錶list的有效資訊合併到另外乙個鍊錶head後,重新初始化被去掉的空的煉表頭。這樣的描述可能不是太好理解,接下來看看一段**。

[html] view plaincopy#include

#include

#include "

typedef struct _stu

stu;

int main()

printf("stu_list 鍊錶\n");

list_for_each(pos,&stu_list)

printf("stu_list2 鍊錶\n");

list_for_each(pos,&stu_list2)

printf("stu_list鍊錶和stu_list2 鍊錶合併以後\n");

list_splice(&stu_list2,&stu_list);

list_for_each(pos,&stu_list)

free(pstu);

return 0;

}  執行結果為:

[html] view plaincopyroot@ubuntu:/home/paixu/dlist_node# ./a

stu_list 鍊錶

student num: 3 student name: stu3

student num: 2 student name: stu2

student num: 1 student name: stu1

stu_list2 鍊錶

student num: 6 student name: stu6

student num: 5 student name: stu5

student num: 4 student name: stu4

stu_list鍊錶和stu_list2 鍊錶合併以後

student num: 6 student name: stu6

student num: 5 student name: stu5

student num: 4 student name: stu4

student num: 3 student name: stu3

student num: 2 student name: stu2

student num: 1 student name: stu1

有了直觀的**和執行結果,理解起來也更加的容易了。

有了上面的這些操作,但是我們還一直沒有講到我們最終所關心的宿主結構,那麼接下來我們一起來看看我們該如何取出宿主結構的指標呢?這也是我認為linux核心雙向迴圈鍊錶實現最為巧妙的地方了。

[cpp] view plaincopy#define list_entry(ptr, type, member) \

((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

看看上面的**,發現乙個很熟悉的身影(unsigned long)(&((type *)0)->member)),這個我在前一篇部落格《c語言的那些小秘密之位元組對齊》中已經講解過了,多以在此就不再做過多的講解,如果有不明白的讀者可以回過去看看講解再回過來閱讀。通過(unsigned long)(&((type *)0)->member))我們得出了成員變數member的偏移量,而ptr為指向member的指標,因為指標型別不同的原因,所以我們再次要先進行(char*)的轉換之後再進行計算。所以我們用ptr減去member的偏移量就得到了宿主結構體的指標,這就是乙個非常巧妙的地方,這也就使得linux核心雙向迴圈鍊錶能夠區別於傳統鍊錶的關鍵所在。

可能看到這兒的時候讀者已經感覺非常的枯燥了,但是別放棄,堅持看完,因為雖然這樣的講解枯燥了點,但是非常有用。所以堅持堅持吧!

談談學習中的那些小事

今天我講話的主題是針對即將高考的高三同學,但也請高一高二的同學認真聽,因為你們兩年或者一年後也將面臨高考,希望你們以高三學生積極的學習狀態為榜樣,努力學習,待到來年高考時創出佳績,實現你們的人生夢想。今天高一高二的同學不僅要聽,也要拿出實際行動來支援高三同學的高考備考,我倡議我們高一高二的同學們給高...

實習總結報告 實習那些小事

羅蘭英 化環學院 白駒過隙,時光總是在不知不覺中匆匆而過。為期差不多兩個月的實習生活結束了,在實習期間,有過歡笑,有過心酸,但我們都在不經意中收穫著 感動著 收穫的不僅是教學經驗 班主任工作經驗,更多的是作為一名教師如何讓自己的學生因為你的存在而感到幸福,還收穫了乙份份雖然認識短暫但卻真摯的友誼。雖...

保養實木辦公家具有那些小技巧

眾所周知錯誤的保養方式只能讓表面變得乾淨漂亮,卻存在著巨大的問題,隨著時間的流逝,而出現無法彌補的情況。所以選用正確的保養方法,才能保持乾淨 亮麗。以下是美高家具結合自身經驗為您提供幾種高效實用的保養方法!保養小技巧之所用方法 1 醋 用半杯清水加入水量四分之一的醋,用軟布蘸此溶液擦試實木辦公家具,...