日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

sys/queue.h分析(图片复制不过来,查看原文)

發(fā)布時(shí)間:2023/11/30 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 sys/queue.h分析(图片复制不过来,查看原文) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

這兩天有興趣學(xué)習(xí)使用了下系統(tǒng)頭文件sys/queue.h中的鏈表/隊(duì)列的實(shí)現(xiàn),感覺實(shí)現(xiàn)的很是優(yōu)美,關(guān)鍵是以后再也不需要自己實(shí)現(xiàn)這些基本的數(shù)據(jù)結(jié)構(gòu)了,哈哈!

我的系統(tǒng)環(huán)境是

正好需要使用隊(duì)列,那么本篇就以其中的尾隊(duì)列(tail queue)為例,結(jié)合實(shí)際的測試程序和示意圖(億圖軟件)來說明。

測試程序tailq.c如下:

#include <stdio.h> ?
#include <stdlib.h> ?
#include <sys/queue.h> ?
?
struct _Data { ?
?? ?int???????????????? value; ?
?? ?TAILQ_ENTRY(_Data)? tailq_entry; ?
}; ?
?
int main(int argc, const char *argv[]) ?
{ ?
?? ?/* 1. 初始化隊(duì)列 */ ?
#if 0 ?
?? ?TAILQ_HEAD(tailq_head, _Data)?? head = TAILQ_HEAD_INITIALIZER(head); ?
#else ?
?? ?TAILQ_HEAD(tailq_head, _Data)?? head; ?
?? ?TAILQ_INIT(&head); ?
#endif ?
?? ?int i; ?
?? ?struct _Data *pdata = NULL; ?
?
?? ?/* 2. 在隊(duì)列末尾插入data1 */ ?
?? ?struct _Data *data1 = (struct _Data *)calloc(1, sizeof(struct _Data)); ?
?? ?data1->value = 1; ?
?? ?TAILQ_INSERT_TAIL(&head, data1, tailq_entry); ?
?? ?/* 3. 在隊(duì)列末尾插入data2 */ ?
?? ?struct _Data *data2 = (struct _Data *)calloc(1, sizeof(struct _Data)); ?
?? ?data2->value = 2; ?
?? ?TAILQ_INSERT_TAIL(&head, data2, tailq_entry); ?
?? ?/* 4. 在data1之后插入data3 */ ?
?? ?struct _Data *data3 = (struct _Data *)calloc(1, sizeof(struct _Data)); ?
?? ?data3->value = 3; ?
?? ?TAILQ_INSERT_AFTER(&head, data1, data3, tailq_entry); ?
?? ?/* 5. 在data2之前插入data4 */ ?
?? ?struct _Data *data4 = (struct _Data *)calloc(1, sizeof(struct _Data)); ?
?? ?data4->value = 4; ?
?? ?TAILQ_INSERT_BEFORE(data2, data4, tailq_entry); ?
?? ?/* 6. 在隊(duì)列首部插入data5 */ ?
?? ?struct _Data *data5 = (struct _Data *)calloc(1, sizeof(struct _Data)); ?
?? ?data5->value = 5; ?
?? ?TAILQ_INSERT_HEAD(&head, data5, tailq_entry); ?
?? ?/* 遍歷隊(duì)列 */ ?
?? ?TAILQ_FOREACH(pdata, &head, tailq_entry) { ?
?? ??? ?printf("pdata->value1 = %d\n", pdata->value);????? ?
?? ?} ?
?? ?puts(""); ?
?? ?/* 7. 刪除data5 */ ?
?? ?TAILQ_REMOVE(&head, data5, tailq_entry); ?
?? ?free(data5);?? ?/* TAILQ_REMOVE宏只是從隊(duì)列中刪除該節(jié)點(diǎn),因此還需手動free */
?
?? ?TAILQ_FOREACH(pdata, &head, tailq_entry) { ?
?? ??? ?printf("pdata->value1 = %d\n", pdata->value);????? ?
?? ?} ?
?? ?puts(""); ?
?
?? ?/* 正序遍歷尾隊(duì)列 */ ?
?? ?/* 方法一 */ ?
?? ?TAILQ_FOREACH(pdata, &head, tailq_entry) { ?
?? ??? ?printf("pdata->value1 = %d\n", pdata->value);????? ?
?? ?} ?
?? ?puts(""); ?
?? ?/* 方法二 */ ?
?? ?for (pdata = TAILQ_FIRST(&head); pdata;? ?
?? ??? ??? ??? ??? ?pdata = TAILQ_NEXT(pdata, tailq_entry)) { ?
?? ??? ?printf("pdata->value1 = %d\n", pdata->value);????? ?
?? ?} ?
?
?? ?puts(""); ?
?
?? ?/* 逆序遍歷尾隊(duì)列 */ ?
?? ?/* 方法一 */ ?
?? ?TAILQ_FOREACH_REVERSE(pdata, &head, tailq_head, tailq_entry) { ?
?? ??? ?printf("pdata->value1 = %d\n", pdata->value);????? ?
?? ?} ?
?? ?puts(""); ?
?? ?/* 方法二 */ ?
?? ?for (pdata = TAILQ_LAST(&head, tailq_head); pdata;? ?
?? ??? ??? ?pdata = TAILQ_PREV(pdata, tailq_head, tailq_entry)) { ?
?? ??? ?printf("pdata->value1 = %d\n", pdata->value);????? ?
?? ??? ?TAILQ_REMOVE(&head, pdata, tailq_entry); ?
?? ??? ?free(pdata); ?
?? ?} ?
?
?? ?if (TAILQ_EMPTY(&head)) { ?
?? ??? ?printf("the tail queue is empty now.\n");??? ?
?? ?} ?
?
?? ?exit(EXIT_SUCCESS); ?
}?

代碼github地址:https://github.com/astrotycoon/sys-queue.h


我們首先來看一下這個(gè)尾隊(duì)列的定義:


注意,其中的tqe_prev指向的不是前一個(gè)元素,而是前一個(gè)元素中的tqe_next,這樣定義的一個(gè)好處就是*tqe_prev就是自身的地址,**tqe_prev就是自身。

好,現(xiàn)在就順著我的測試程序來一步步看如何使用這個(gè)尾隊(duì)列吧!

第一步是初始化步驟。關(guān)于初始化我們有兩種方法:使用宏TAILQ_HEAD_INITIALIZER或者使用宏TAILQ_INIT,這兩者都是可以的,唯一的區(qū)別是傳遞給宏TAILQ_INIT的是地址,而傳遞給宏TAILQ_HEAD_INITIALIZER的不是,這點(diǎn)需要引起我們的注意。


初始化后的數(shù)據(jù)結(jié)構(gòu)怎樣的呢? 我們看下示意圖:


接下來的兩個(gè)步驟(步奏2和步奏3)都是在這個(gè)隊(duì)列的尾部追加元素(data1和data2),使用的是宏TAILQ_INSERT_TAIL:


那么隊(duì)列的變化過程是這樣的,請看示意圖:

接下來的操作是在data1之前插入data3,使用的是宏TAILQ_INSERT_AFTER:


形象的示意圖如下:


整理后的示意圖如下:


緊接著的操作是在data2之前插入data4,使用的是宏TAILQ_INSERT_BEFORE:


形象的示意圖如下:


整理后的示意圖如下:


現(xiàn)在在隊(duì)列首部插入data5,使用的是宏TAILQ_INSERT_HEAD:


形象的示意圖如下:


整理后的示意圖如下:


刪除數(shù)據(jù)data5使用是宏TAILQ_REMOVE:


現(xiàn)在的隊(duì)列布局如下:


好了,基本的操作就這么多,接下來我們看看提供的幾個(gè)數(shù)據(jù)元素訪問方法:


前三個(gè)很簡單,一看就懂,我們重點(diǎn)分析下TAILQ_LAST和TAILQ_PREV。

TAILQ_LAST的目的是獲取隊(duì)列中的最后一個(gè)元素的地址,注意是地址哦!(head)->tqh_last代表的是最后一個(gè)元素中tqe_next的地址,通過強(qiáng)轉(zhuǎn)之后,((struct headname *)((head)->tqh_last))->tqh_last實(shí)際上就是最后一個(gè)元素中的tqe_prev,而文章一開始介紹定義的時(shí)候就說過,*tqe_prev代表的是自身元素的地址,所以TAILQ_LAST最后獲取的就是最后一個(gè)元素的地址,宏TAILQ_PREV的道理是一樣的。

OK,測試程序接下來就是遍歷整個(gè)隊(duì)列,并打印出數(shù)據(jù),可以使用提供的宏TAILQ_FOREACH,也可以使用上述的幾個(gè)訪問方法來遍歷。


好了,其實(shí)本文沒啥內(nèi)容,對我個(gè)人而言就主要是想熟悉下億圖這個(gè)軟件,哈哈

?

?

?

?

?

?

?

總結(jié)

以上是生活随笔為你收集整理的sys/queue.h分析(图片复制不过来,查看原文)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。