我们阅读一下contiki的源码,list.c(路径是./core/lib/list.h).
#include "lib/list.h"
#define NULL 0
struct list {
struct list *next;
};
这就是核心结构体了,发现了吗?没有数据域,成员就是一个指针。其实这个有点类似Linux里面的链表,对,就是嵌入在结构体里面的那个list.我们继续往下看。
void
list_init(list_t list)
{
*list = NULL;
}
初始化函数,这里要说明的是,list_t 就是void**类型。
在头文件中,有这样的定义:
#define LIST_CONCAT2(s1, s2) s1##s2
#define LIST_CONCAT(s1, s2) LIST_CONCAT2(s1, s2)
#define LIST(name) \
static void *LIST_CONCAT(name,_list) = NULL; \
static list_t name = (list_t)&LIST_CONCAT(name,_list)
其实就是定义一个链表(假设name是hello). 有个变量叫hello_list, 其实是一个void*类型的指针,初始化为NULL,这个链表的名字叫hello, hello是指向hello_list的二级指针。
这里的list是没有头节点的,*hello就得到了第一个元素。因为每个元素都是指针,那么初始化的时候,第一个元素自然为NULL了,表示链表为空。
void *
list_head(list_t list)
{
return *list;
}
返回链表的第一个元素。
void *
list_tail(list_t list)
{
struct list *l;
if(*list == NULL) {
return NULL;
}
for(l = *list; l->next != NULL; l = l->next);
return l;
}
返回链表的最后一个元素。
void
list_remove(list_t list, void *item)
{
struct list *l, *r;
if(*list == NULL) {
return;
}
r = NULL;//r用来保存前一个元素
for(l = *list; l != NULL; l = l->next) {
if(l == item) {
if(r == NULL) {//说明要删除的元素恰好是第一个
/* First on list */
*list = l->next;
} else {
/* Not first on list */
r->next = l->next;
}
l->next = NULL;
return;
}
r = l;
}
}
删除某个元素。(千万要记住,这个链表的元素就是指针!)
void
list_add(list_t list, void *item)
{
struct list *l;
/* Make sure not to add the same element twice */
list_remove(list, item);
((struct list *)item)->next = NULL;
l = list_tail(list);//得到最后一个元素
if(l == NULL) {
*list = item;
} else {
l->next = item;
}
}
把元素追加到末尾。
void
list_push(list_t list, void *item)
{
/* Make sure not to add the same element twice */
list_remove(list, item);
((struct list *)item)->next = *list;
*list = item;
}
头插元素。
void *
list_chop(list_t list)
{
struct list *l, *r;
if(*list == NULL) {
return NULL;
}
if(((struct list *)*list)->next == NULL) {//说明只有一个元素
l = *list;
*list = NULL;
return l;
}
for(l = *list; l->next->next != NULL; l = l->next);//查找到倒数第二个元素
r = l->next;
l->next = NULL;
return r;
}
”弹出“最末尾的一个元素。
void *
list_pop(list_t list)
{
struct list *l;
l = *list;
if(*list != NULL) {
*list = ((struct list *)*list)->next;
}
return l;
}
“弹出”第一个元素。
其他函数代码都很简单,我们不再赘述。
有的朋友不禁要问了,这样的一个链表,怎么用呢?答案下次揭晓,下次我们结合内存管理,举例说明这个链表的用法。