在寫乙個小工具的時候,需要用到對ini檔案的管理。為了讓這個小工具在linux也適用,所以在寫程式的時候沒有使用mfc提供的類庫,也沒有使用windows提供的ini操作函式,直接拿標準c寫了乙個。
在操作ini的過程中,我拿兩種雙向鍊錶來描述乙個ini檔案,也就意味著,要針對每種鍊錶都寫一套插入、刪除之類的操作函式,格外麻煩。索性,就寫了乙個通用的雙向鍊錶管理程式,省的以後麻煩。
這個「通用」的雙向鍊錶管理程式的思路是:
每種雙向鍊錶的節點結構體裡,雖然有太多的不一樣,但是next和prev指標肯定是要有的,所以,就可以制定乙個只包含next和prev成員的基礎雙向鍊錶節點結構體型別,如下:
1:struct basic_nod_t ;
這樣,只要是具備prev和next指標的節點,都可以強制轉換為這種通用型的結構。當然,前提是,乙個具體的節點結構體在定義的時候,需要讓prev和next做為結構體的第乙個和第二個成員,這種強制轉換才會有效果。比如,現在有乙個用來儲存使用者資訊的節點結構體:
1:struct user_info_t ;
因為user_info_t結構體的前兩個成員也是prev和next指標,那麼,當嘗試把user_info_t結構體強制轉換為basic_nod_t時,basic_nod_t內的prev和next成員即為user_info_t的對應成員。
這樣一來,通用型的管理程式就有機會實現了。因為對鍊錶的插入、刪除等操作,在一般情況下,只會牽扯到對prev和next指標的修改,所以,不管具體的結構體長什麼樣子,只要你有prev和next,我就可以操作!
來個具體的**吧,拿插入節點為例:
1:void add_node_to(void **head, void **tail, void *node, void *to, int before_or_after)
2:
13:else
if(before_or_after == 0)
14:
27: }
28:else
if(before_or_after == 1)
29:
41: }
函式在傳參的時候,採用了void指標型別,因為在實際使用過程中,節點結構體的定義並不一致。
其中,函式的head和tail引數,用來表示鍊錶的頭節點和尾節點。因為在插入節點的過程中,可能會修改head和tail,所以,這裡在傳參的時候,採用的是void**這種指標的指標的形式,用來表示,head和tail這兩個指標將來是要被修改的。
在add_node_to函式內部,會首先將傳進來的引數轉換為basic_nod_t型別,此時,節點內的prev和next指標就可以被操作了。
ok,再來個刪除節點的:
1:void del_node(void **head, void **tail, void *node)
2:
10:if(n == *t)
11:
14:if(n->prev != null)
15: n->prev->next = n->next;
16:if(n->next != null)
17: n->next->prev = n->prev;
18: }
還有移動節點:
1:void move_node(void **head, void **tail, void *moved, void *to, int before_or_after)
2:
最後再來個鍊錶排線的(這裡使用的是最簡單的氣泡排序):
1:void sort_list(void **head, void **tail, cmp_func nodcmp)
2:
18:else
19:
23:if(nod2 == null)
24:
29: }
30: }
31: }
在排序的時候,由於通用管理程式並不知道排序的依據和演算法,所以,需要提供給他乙個nodcmp函式來完成兩個節點大小的計算工作。cmp_func的定義如下:
1: typedef int (*cmp_func)(void *t1, void *t2);
基本搞定,呵呵~~
使用起來也非常簡單,仍然拿那個使用者資訊鍊錶user_info_t為例:
1:// 定義鍊錶的頭和尾指標, 初始情況下,鍊錶為空
2:struct user_info_t *head = null;
3:struct user_info_t *tail = null;
4:// 首先建立乙個節點
5: user_info_t *node = (struct user_info_t *)malloc(sizeof(struct user_info_t));
6:// 然後初始化節點的一些必要資訊
7: node->username = (char *)malloc(strlen("test") + 1);
8: strcpy(node->username, "test");
9: node->passwd = (char *)malloc(strlen("admin") + 1);
10: strcpy(node->passwd, "admin");
11:// 然後將節點插入鍊錶中
12: add_node(&head, &tail, node);
13:// 同樣的方法還可以插入更多的節點;
14: add_node(&head, &tail, node);
15:// 刪除節點也同樣方便
16: del_node(&head, &tail, node);
17:// 注意,鍊錶管理程式並不會幫助你釋放空間,所以,如果節點是在堆中分配的,那麼記得在從鍊錶中剔除節點後,將節點占用的空間釋放
18: free(node->username);
19: free(node->passwd);
20: free(node);
21: // 搞定
乙個通用的雙向鍊錶管理程式
在寫乙個小工具的時候,需要用到對ini檔案的管理。為了讓這個小工具在linux也適用,所以在寫程式的時候沒有使用mfc提供的類庫,也沒有使用windows提供的ini操作函式,直接拿標準c寫了乙個。在操作ini的過程中,我拿兩種雙向鍊錶來描述乙個ini檔案,也就意味著,要針對每種鍊錶都寫一套插入 刪...
雙向鍊錶練手程式
看了 系統程式設計師成長計畫 開始的時候,要求練習雙向鍊錶。以下為自己寫的練習程式 include includetypedef int elemtype element type typedef struct dulnode dulnode,dulinklist int m 0 about ins...
mysql 雙向鍊錶 雙向鍊錶
雙向鍊錶是鍊錶變型,相比於單鏈表導航或者是向前和向後的兩種方式。以下是重要的術語來理解雙向鍊錶的概念 link 鍊錶的每個鏈路儲存資料稱為乙個元素。linkedlist linkedlist包含連線鏈結到名為首先第乙個鏈結,並稱為最後的最後乙個鏈結 last 雙向鍊錶表示 按照如上圖中所示,以下是要...