新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 如何定义链表结点的数据结构?

如何定义链表结点的数据结构?

作者:时间:2018-07-25来源:网络收藏

2 {

本文引用地址:http://www.eepw.com.cn/article/201807/383764.htm

3 if (p_pos) { // 找到p_pos指向的结点

4 return p_pos->p_next;

5 }

6 return NULL;

7 }

8

9 slist_node_t *slist_begin_get (slist_head_t *p_head)

10 {

11 return slist_next_get(p_head, p_head);

12 }

13

14 slist_node_t *slist_end_get (slist_head_t *p_head)

15 {

16 return NULL;

17 }

程序中获取的第一个用户结点,其实质上就是头结点的下一个结点,因此可以直接调用slist_next_get()实现。尽管slist_next_get()在实现时并没有用到参数p_head,但还是将p_head参数传进来了,因为实现其它的功能时将会用到p_head参数,比如,判断p_pos是否在链表中。当有了这些接口函数后,即可完成遍历,详见程序清单3.18。

程序清单3.18 使用各个接口函数实现遍历的范例程序

1 slist_node_t *p_tmp = slist_begin_get(head);

2 slist_node_t *p_end = slist_end_get(head);

3 while (p_tmp != p_end){

4 printf(%d , ((slist_int_t *)p_tmp)->data);

5 p_tmp = slist_next_get(head, p_tmp);

6 }

由此可见,slist_begin_get()和slist_end_get()的返回值决定了当前有效结点的范围,其范围为一个半开半闭的空间,即:[begin,end),包括begin,但是不包括end。当begin与end相等时,表明当前链表为空,没有一个有效结点。

在程序清单3.18所示的遍历程序中,只有printf()语句才是用户实际关心的语句,其它语句都是固定的模式,为此可以封装一个通用的遍历函数,便于用户顺序处理与各个相关联的数据。显然,只有使用链表的用户才知道数据的具体含义,对数据的实际处理应该交由用户完成,比如,程序清单3.18中的打印语句,因此访问数据的行为应该由用户定义,定义一个回调函数,通过参数传递给遍历函数,每遍历到一个结点时,都调用该回调函数处理对数据进行处理。遍历链表的函数原型(slist.h)为:

typedef int (*slist_node_process_t) (void *p_arg, slist_node_t *p_node);

int slist_foreach(slist_head_t *p_head,

slist_node_process_t pfn_node_process,

void *p_arg);

其中,p_head指向链表头结点,pfn_node_process为结点处理回调函数。每遍历到一个结点时,都会调用pfn_node_process指向的函数,便于用户根据需要自行处理结点数据。当调用该回调函数时,会自动将用户参数p_arg作为回调函数的第1个参数,将指向当前遍历到的结点的指针作为回调函数的第2个参数。

当遍历到某个结点时,用户可能希望终止遍历,此时只要在回调函数中返回负值即可。一般地,若要继续遍历,函数执行结束后返回0。slist_foreach()函数的实现详见程序清单3.19。

程序清单3.19 遍历链表范例程序

1 int slist_foreach( slist_head_t *p_head,

2 slist_node_process_t pfn_node_process,

3 void *p_arg);

4

5 {

6 slist_node_t *p_tmp, *p_end;

7 int ret;

8

9 if ((p_head == NULL) || (pfn_node_process == NULL)){

10 return -1;

11 }

12 p_tmp = slist_begin_get(p_head);

13 p_end = slist_end_get(p_head);

14 while (p_tmp != p_end){

15 ret = pfn_node_process(p_arg, p_tmp);

16 if (ret 0) return ret; // 不再继续遍历

17 p_tmp = slist_next_get(p_head, p_tmp); // 继续下一个结点

18 }

19 return 0;

20 }

现在可以使用这些接口函数,迭代如程序清单3.14所示的功能,详见程序清单3.20。

程序清单3.20 管理int型数据的范例程序

1 #include

2 #include slist.h

3

4 typedef struct _slist_int {

5 slist_node_t node; // 包含

6 int data; // int类型数据

7 }slist_int_t;

8

9 int list_node_process (void *p_arg, slist_node_t *p_node)

10 {

11 printf(%d , ((slist_int_t *)p_node)->data);

12 return 0;

13 }

14

15 int main(void)

16 {

17 slist_head_t head; // 定义链表头结点

18 slist_int_t nodel, node2, node3;

19 slist_init(head);

20

21 node1.data = 1;

22 slist_add_tail(head, (node1.node));

23 node2.data = 2;

24 slist_add_tail(head, (node2.node));

25 node3.data = 3;

26 slist_add_tail(head, (node3.node));

27 slist_foreach(head, list_node_process, NULL); // 遍历链表,用户参数为NULL

28 return 0;

29 }


上一页 1 2 下一页

评论


相关推荐

技术专区

关闭