最近参考Linux实现的通用双向链表时,因typeof并不是标准c规定的关键字,除GCC编译器外其他编译器未必支持typeof关键字,所以在使用上并不能想Linux所实现的链表哪样灵活,它要求将连接器即链表结构作为用户自定义结构体的第一个元素使用,话不多说,直接上代码,内嵌详细注释。

IList.h

  1. #ifndef _I_LIST_H_2012_11_23_
  2. #define _I_LIST_H_2012_11_23_
  3.  
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7.  
  8. /** \brief 双向链表连接器
  9. * \details 实现用户自定义结构链表的连接器的结构定义,使用注意事项:
  10. 1. 务必将其嵌入到用户自定义结构体元素的顶端;
  11. 2. 务必使用结构类型而非其指针类型嵌入到用户自定义结构体
  12. * \typedef typedef struct _IList IList,*pIList
  13. */
  14. typedef struct _IList
  15. {
  16. struct _IList *_prev;
  17. struct _IList *_next;
  18. }IList, *pIList;
  19.  
  20. /**
  21. \brief 遍历链表所有节点
  22. \details 遍历链表所有节点,在遍历过程中,请勿执行添加、删除操作
  23.  
  24. \param[in] pList 链表对象
  25. \param[out] pLink 节点
  26. */
  27. #define IList_Foreach(pList, pos) \
  28. for ( \
  29. pos = pos = (pList)->_next; \
  30. pos != (pList); \
  31. pos = pos->_next \
  32. )
  33.  
  34. /**
  35. \brief 遍历链表所有节点
  36. \details 安全遍历链表所有节点,在遍历过程中,可以删除节点
  37.  
  38. \param[in] pList 链表对象
  39. \param[out] pLink 节点
  40. */
  41. #define IList_Foreach_Salf(pList, temp, pos) \
  42. for ( \
  43. pos = (pList)->_next, temp = pos->_next; \
  44. pos != (pList); \
  45. pos = temp, temp = pos->_next\
  46. )
  47.  
  48. /**
  49. \brief 链表初始化
  50.  
  51. \param[in] pList 链表对象
  52. */
  53. void IList_Init(pIList pList);
  54.  
  55. /**
  56. \brief 插入新节点
  57. \details 将新节点插入链表指定节点之前
  58.  
  59. \param[in] pList 链表对象
  60. \param[in] pLink 指定节点
  61. \param[in] pNewLink 带插入节点
  62. */
  63. void IList_Insert(pIList pLink, pIList pNewLink);
  64.  
  65. /**
  66. \brief 插入新节点至链表尾部
  67.  
  68. \param[in] pList 链表对象
  69. \param[in] pLink 指定节点
  70. \param[in] pNewLink 带插入节点
  71. */
  72. void IList_Append(pIList pList, pIList pNewLink);
  73.  
  74. /**
  75. \brief 插入新节点至链表尾头部
  76.  
  77. \param[in] pList 链表对象
  78. \param[in] pLink 指定节点
  79. \param[in] pNewLink 带插入节点
  80. */
  81. void IList_Prepend(pIList pList, pIList pNewLink);
  82.  
  83. /**
  84. \brief 删除指定节点
  85.  
  86. \param[in] pList 链表对象
  87. \param[in] pLink 带删除的节点
  88. */
  89. void IList_Remove(pIList pLink);
  90.  
  91. /**
  92. \brief 获取表头节点
  93.  
  94. \param[in] pList 链表对象
  95.  
  96. \return NULL: 链表为空
  97. 其他: 表头节点地址
  98. */
  99. pIList IList_Head(pIList pList);
  100.  
  101. /**
  102. \brief 获取表尾节点
  103.  
  104. \param[in] pList 链表对象
  105.  
  106. \return NULL: 链表为空
  107. 其他: 表尾节点地址
  108. */
  109. pIList IList_Tail(pIList pList);
  110.  
  111. /**
  112. \brief 检测链表是否为空
  113.  
  114. \param[in] pList 链表对象
  115.  
  116. \return 0: 链表非空
  117. 1: 链表为空
  118. */
  119. int IList_IsEmpty(pIList pList);
  120. /**
  121. \brief 获取链表节点数
  122.  
  123. \param[in] pList 链表对象
  124.  
  125. \return 链表节点数
  126. */
  127. int IList_Size(pIList pList);
  128.  
  129. /**
  130. \brief 获取指定节点的后一节点
  131.  
  132. \param[in] pList 链表对象
  133. \param[in] pLink 指定的节点
  134.  
  135. \return NULL: 指定节点为尾节点
  136. 其他: 指定节点后一节点地址
  137. */
  138. pIList IList_Next(pIList pList, pIList pLink);
  139.  
  140. /**
  141. \brief 获取指定节点的前一节点
  142.  
  143. \param[in] pList 链表对象
  144. \param[in] pLink 指定的节点
  145.  
  146. \return NULL: 指定节点为头节点
  147. 其他: 指定节点前一节点地址
  148. */
  149. pIList IList_Prev(pIList pList, pIList pLink);
  150.  
  151. /**
  152. \brief 获取链表中第index个节点
  153.  
  154. \param[in] pList 链表对象
  155. \param[in] index 节点序号,从1计数
  156.  
  157. \return NULL: 指定序号无节点
  158. 其他: 链表中第index所对应的节点
  159. */
  160. pIList IList_Nth(pIList pList, int index);
  161.  
  162. /**
  163. \brief 获取链表中指定节点的序号
  164.  
  165. \param[in] pList 链表对象
  166. \param[in] pLink 指定节点
  167.  
  168. \return NULL: 指定序号无节点
  169. 其他: 链表中第index所对应的节点
  170. */
  171. int IList_Find(pIList pList, pIList pLink);
  172.  
  173. #ifdef __cplusplus
  174. }
  175. #endif
  176.  
  177. #endif//_I_LIST_H_2012_11_23_

IList.c

  1. #include <stdio.h>
  2. #include "iList.h"
  3.  
  4. void IList_Init(pIList pList)
  5. {
  6. pList->_prev = pList;
  7. pList->_next = pList;
  8. }
  9.  
  10. void IList_Insert(pIList pLink, pIList pNewLink)
  11. {
  12. pNewLink->_prev = pLink->_prev;
  13. pNewLink->_next = pLink;
  14. pNewLink->_prev->_next = pNewLink;
  15. pNewLink->_next->_prev = pNewLink;
  16. }
  17.  
  18. void IList_Append(pIList pList, pIList pNewLink)
  19. {
  20. IList_Insert(pList, pNewLink);
  21. }
  22.  
  23. void IList_Prepend(pIList pList, pIList pNewLink)
  24. {
  25. IList_Insert(pList->_next, pNewLink);
  26. }
  27.  
  28. void IList_Remove(pIList pLink)
  29. {
  30. pLink->_prev->_next = pLink->_next;
  31. pLink->_next->_prev = pLink->_prev;
  32. }
  33.  
  34. pIList IList_Head(pIList pList)
  35. {
  36. return pList->_next != pList ? pList->_next : NULL;
  37. }
  38.  
  39. pIList IList_Tail(pIList pList)
  40. {
  41. return pList->_prev != pList ? pList->_prev : NULL;
  42. }
  43.  
  44. int IList_IsEmpty(pIList pList)
  45. {
  46. return pList->_next == pList;
  47. }
  48.  
  49. int IList_Size(pIList pList)
  50. {
  51. int count = ;
  52. pIList temp = NULL;
  53.  
  54. if (pList->_next == pList)
  55. return ;
  56.  
  57. IList_Foreach(pList, temp)
  58. {
  59. count ++;
  60. }
  61.  
  62. return count;
  63. }
  64.  
  65. pIList IList_Next(pIList pList, pIList pLink)
  66. {
  67. return pLink->_next != pList ? pLink->_next : NULL;
  68. }
  69.  
  70. pIList IList_Prev(pIList pList, pIList pLink)
  71. {
  72. return pLink->_prev != pList ? pLink->_prev : NULL;
  73. }
  74.  
  75. pIList IList_Nth(pIList pList, int index)
  76. {
  77. pIList pLink = NULL;
  78. int count = ;
  79.  
  80. IList_Foreach(pList, pLink)
  81. {
  82. count ++;
  83. if (count == index)
  84. return pLink;
  85. }
  86.  
  87. return NULL;
  88. }
  89.  
  90. int IList_Find(pIList pList, pIList pLink)
  91. {
  92. pIList pTemp = NULL;
  93. int index = ;
  94.  
  95. pTemp = IList_Head(pList);
  96.  
  97. while ((pTemp != NULL) && (pTemp != pLink))
  98. {
  99. index++;
  100. pTemp = IList_Next(pList, pTemp);
  101. }
  102.  
  103. if (pTemp == NULL)
  104. return (-);
  105. else
  106. return (index);
  107. }

IListTest.c

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "iList.h"
  5.  
  6. typedef struct _Student
  7. {
  8. IList _list;
  9.  
  10. int _id;
  11. char *name;
  12. }Student, *pStudent;
  13.  
  14. int main(int argc, char *argv[])
  15. {
  16. int i = ;
  17. int num = ;
  18. int count = ;
  19. pStudent temp= NULL;
  20. pIList list, link;
  21.  
  22. if (argc > )
  23. num = atoi(argv[]);
  24.  
  25. list = (IList *)malloc(sizeof(IList));
  26. if (!list)
  27. {
  28. printf("Error in malloc.\n");
  29. return -;
  30. }
  31. memset(list, , sizeof(IList));
  32.  
  33. IList_Init(list);
  34. for (i = ; i < num; i ++)
  35. {
  36. temp = malloc(sizeof(Student));
  37. if (!temp)
  38. return -;
  39. memset(temp, , sizeof(Student));
  40. temp->_id = i + ;
  41. IList_Append(list, &temp->_list);
  42. //IList_Prepend(list, &temp->_list);
  43. }
  44.  
  45. IList_Foreach(list, link)
  46. {
  47. temp = (pStudent)link;
  48. printf("%d\t", temp->_id);
  49. }
  50. printf("\n");
  51.  
  52. printf("Input the num(1 ~ %d) that you want to:\n", IList_Size(list));
  53. scanf("%d", &count);
  54. link = IList_Nth(list, count);
  55. printf("Num %d id: %d\n", count, ((pStudent)link)->_id);
  56. printf("Id %d num: %d\n", ((pStudent)link)->_id, IList_Find(list, link));
  57.  
  58. printf("List count: %d\n", IList_Size(list));
  59. /*for (link = IList_Head(list);!IList_IsEmpty(list);)
  60. {
  61. pIList tLink = link;
  62. link = IList_Next(list, link);
  63. IList_Remove(tLink);
  64. free(tLink);
  65. }*/
  66. do
  67. {
  68. pIList n, pos;
  69. IList_Foreach_Salf(list, n, pos)
  70. {
  71. IList_Remove(pos);
  72. free(pos);
  73. }
  74. } while ();
  75. printf("List count: %d\n", IList_Size(list));
  76.  
  77. free(list);
  78.  
  79. return ;
  80. }

通用链表实现(参考Linux List)的更多相关文章

  1. 通用双向链表的设计(参考Linux系统中的实现)

    通常我们设计设计链表都是将数据域放在里面,这样每次需要使用链表的时候都需要实现一个链表,然后重新实现它的相关操作,这里参考Linux系统中的设计实现了一个通用的双向链表,只需要在你的结构里面有一个这个 ...

  2. 拒绝造轮子!如何移植并使用Linux内核的通用链表(附完整代码实现)

    在实际的工作中,我们可能会经常使用链表结构来存储数据,特别是嵌入式开发,经常会使用linux内核最经典的双向链表 list_head.本篇文章详细介绍了Linux内核的通用链表是如何实现的,对于经常使 ...

  3. C语言实现通用链表初步(一)

    注意:本文讨论的是无头单向非循环链表. 假设不采用Linux内核链表的思路,怎样用C语言实现通用链表呢? 一种常用的做法是: typedef int element_t; struct node_in ...

  4. C 封装一个通用链表 和 一个简单字符串开发库

    引言 这里需要分享的是一个 简单字符串库和 链表的基库,代码也许用到特定技巧.有时候回想一下, 如果我读书的时候有人告诉我这些关于C开发的积淀, 那么会走的多直啊.刚参加工作的时候做桌面开发, 服务是 ...

  5. Linux内核链表-通用链表的实现

    最近编程总想着参考一些有名的开源代码是如何实现的,因为要写链表就看了下linux内核中对链表的实现. 链表是一种非常常见的数据结构,特别是在动态创建相应数据结构的情况下更是如此,然而在操作系统内核中, ...

  6. C语言实现通用链表初步(四)----双向链表

    在前面的文章中,我们讨论了如何实现通用类型的链表,方法是用void *类型的指针,指向数据.那么还有其他的方法吗(不考虑内核链表)? 答案是肯定的.用零长数组也可以实现. struct node_in ...

  7. 链表的艺术——Linux内核链表分析

    引言: 链表是数据结构中的重要成员之中的一个.因为其结构简单且动态插入.删除节点用时少的长处,链表在开发中的应用场景许多.仅次于数组(越简单应用越广). 可是.正如其长处一样,链表的缺点也是显而易见的 ...

  8. MySql通用二进制版本在Linux(Ubuntu)下安装与开启服务

    安装mysql前可能需要其他软件的依赖,请先执行下面命令安装mysql的依赖软件 shell> apt-cache search libaio # search for info shell&g ...

  9. C语言实现通用链表初步(三)----单元测试

    前两节,我们已经完成了链表的一些操作,快来测试一下吧. 这里使用的单元测试工具名字叫"check". START_TEST(my_slist_1) { struct student ...

随机推荐

  1. 如何防止ASP.NET网站遭受CSRF的攻击

    转载地址: http://www.cnblogs.com/shanyou/p/5038794.html?hmsr=toutiao.io&utm_medium=toutiao.io&ut ...

  2. CENTOS LINUX查询内存大小、频率

    more /proc/meminfo dmidecode [root@barcode-mcs ~]# dmidecode -t memory linux下查看主板内存槽与内存信息 1.查看内存槽数.那 ...

  3. effective c++ (一)

    条款01:把C++看作一个语言联邦 C++是一种多重范型编程语言,一个同时支持过程(procedural),面向对象(object-oriented),函数形式(functional),泛型形式(ge ...

  4. 用DependanceProperty做Dynamic换Icon

    1:做Icon用Canvas还是DrawingBrush? Canvas的例子:

  5. CentOS 使用yum命令安装出现错误提示”could not retrieve mirrorlist http://mirrorlist.centos.org ***”

    刚安装完CentOS,使用yum命令安装一些常用的软件,使用如下命令:yum –y install gcc. 提示如下错误信息: Loaded plugins: fastestmirror, refr ...

  6. javascript 汉字生成拼音

    在网上下载的一个汉字生成拼音的js,很有用,大家一起分享! var PinYin = {"a":"/u554a/u963f/u9515","ai&qu ...

  7. CMSIS Example - Mail and Timer

    #include <stdint.h> #include "bsp-fifisdr.h" #include "lpclib.h" #include ...

  8. uva331 - Mapping the Swaps

    Mapping the Swaps Sorting an array can be done by swapping certain pairs of adjacent entries in the ...

  9. 玩转iOS开发 - 多线程开发

    前言 本文主要介绍iOS多线程开发中使用的主要技术:NSOperation, GCD. NSThread, pthread. 内容依照开发中的优先推荐使用的顺序进行介绍,涉及多线程底层知识比較多的NS ...

  10. jQuery对象入门级介绍

    你是否曾经见过像  $(".cta").click(function(){})这样的JavaScrip代码?或许你还会思考下 $('#X') 是什么,如果看到这些你都觉得摸不着头脑 ...