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

IList.h

 #ifndef _I_LIST_H_2012_11_23_
#define _I_LIST_H_2012_11_23_ #ifdef __cplusplus
extern "C" {
#endif /** \brief 双向链表连接器
* \details 实现用户自定义结构链表的连接器的结构定义,使用注意事项:
1. 务必将其嵌入到用户自定义结构体元素的顶端;
2. 务必使用结构类型而非其指针类型嵌入到用户自定义结构体
* \typedef typedef struct _IList IList,*pIList
*/
typedef struct _IList
{
struct _IList *_prev;
struct _IList *_next;
}IList, *pIList; /**
\brief 遍历链表所有节点
\details 遍历链表所有节点,在遍历过程中,请勿执行添加、删除操作 \param[in] pList 链表对象
\param[out] pLink 节点
*/
#define IList_Foreach(pList, pos) \
for ( \
pos = pos = (pList)->_next; \
pos != (pList); \
pos = pos->_next \
) /**
\brief 遍历链表所有节点
\details 安全遍历链表所有节点,在遍历过程中,可以删除节点 \param[in] pList 链表对象
\param[out] pLink 节点
*/
#define IList_Foreach_Salf(pList, temp, pos) \
for ( \
pos = (pList)->_next, temp = pos->_next; \
pos != (pList); \
pos = temp, temp = pos->_next\
) /**
\brief 链表初始化 \param[in] pList 链表对象
*/
void IList_Init(pIList pList); /**
\brief 插入新节点
\details 将新节点插入链表指定节点之前 \param[in] pList 链表对象
\param[in] pLink 指定节点
\param[in] pNewLink 带插入节点
*/
void IList_Insert(pIList pLink, pIList pNewLink); /**
\brief 插入新节点至链表尾部 \param[in] pList 链表对象
\param[in] pLink 指定节点
\param[in] pNewLink 带插入节点
*/
void IList_Append(pIList pList, pIList pNewLink); /**
\brief 插入新节点至链表尾头部 \param[in] pList 链表对象
\param[in] pLink 指定节点
\param[in] pNewLink 带插入节点
*/
void IList_Prepend(pIList pList, pIList pNewLink); /**
\brief 删除指定节点 \param[in] pList 链表对象
\param[in] pLink 带删除的节点
*/
void IList_Remove(pIList pLink); /**
\brief 获取表头节点 \param[in] pList 链表对象 \return NULL: 链表为空
其他: 表头节点地址
*/
pIList IList_Head(pIList pList); /**
\brief 获取表尾节点 \param[in] pList 链表对象 \return NULL: 链表为空
其他: 表尾节点地址
*/
pIList IList_Tail(pIList pList); /**
\brief 检测链表是否为空 \param[in] pList 链表对象 \return 0: 链表非空
1: 链表为空
*/
int IList_IsEmpty(pIList pList);
/**
\brief 获取链表节点数 \param[in] pList 链表对象 \return 链表节点数
*/
int IList_Size(pIList pList); /**
\brief 获取指定节点的后一节点 \param[in] pList 链表对象
\param[in] pLink 指定的节点 \return NULL: 指定节点为尾节点
其他: 指定节点后一节点地址
*/
pIList IList_Next(pIList pList, pIList pLink); /**
\brief 获取指定节点的前一节点 \param[in] pList 链表对象
\param[in] pLink 指定的节点 \return NULL: 指定节点为头节点
其他: 指定节点前一节点地址
*/
pIList IList_Prev(pIList pList, pIList pLink); /**
\brief 获取链表中第index个节点 \param[in] pList 链表对象
\param[in] index 节点序号,从1计数 \return NULL: 指定序号无节点
其他: 链表中第index所对应的节点
*/
pIList IList_Nth(pIList pList, int index); /**
\brief 获取链表中指定节点的序号 \param[in] pList 链表对象
\param[in] pLink 指定节点 \return NULL: 指定序号无节点
其他: 链表中第index所对应的节点
*/
int IList_Find(pIList pList, pIList pLink); #ifdef __cplusplus
}
#endif #endif//_I_LIST_H_2012_11_23_

IList.c

 #include <stdio.h>
#include "iList.h" void IList_Init(pIList pList)
{
pList->_prev = pList;
pList->_next = pList;
} void IList_Insert(pIList pLink, pIList pNewLink)
{
pNewLink->_prev = pLink->_prev;
pNewLink->_next = pLink;
pNewLink->_prev->_next = pNewLink;
pNewLink->_next->_prev = pNewLink;
} void IList_Append(pIList pList, pIList pNewLink)
{
IList_Insert(pList, pNewLink);
} void IList_Prepend(pIList pList, pIList pNewLink)
{
IList_Insert(pList->_next, pNewLink);
} void IList_Remove(pIList pLink)
{
pLink->_prev->_next = pLink->_next;
pLink->_next->_prev = pLink->_prev;
} pIList IList_Head(pIList pList)
{
return pList->_next != pList ? pList->_next : NULL;
} pIList IList_Tail(pIList pList)
{
return pList->_prev != pList ? pList->_prev : NULL;
} int IList_IsEmpty(pIList pList)
{
return pList->_next == pList;
} int IList_Size(pIList pList)
{
int count = ;
pIList temp = NULL; if (pList->_next == pList)
return ; IList_Foreach(pList, temp)
{
count ++;
} return count;
} pIList IList_Next(pIList pList, pIList pLink)
{
return pLink->_next != pList ? pLink->_next : NULL;
} pIList IList_Prev(pIList pList, pIList pLink)
{
return pLink->_prev != pList ? pLink->_prev : NULL;
} pIList IList_Nth(pIList pList, int index)
{
pIList pLink = NULL;
int count = ; IList_Foreach(pList, pLink)
{
count ++;
if (count == index)
return pLink;
} return NULL;
} int IList_Find(pIList pList, pIList pLink)
{
pIList pTemp = NULL;
int index = ; pTemp = IList_Head(pList); while ((pTemp != NULL) && (pTemp != pLink))
{
index++;
pTemp = IList_Next(pList, pTemp);
} if (pTemp == NULL)
return (-);
else
return (index);
}

IListTest.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "iList.h" typedef struct _Student
{
IList _list; int _id;
char *name;
}Student, *pStudent; int main(int argc, char *argv[])
{
int i = ;
int num = ;
int count = ;
pStudent temp= NULL;
pIList list, link; if (argc > )
num = atoi(argv[]); list = (IList *)malloc(sizeof(IList));
if (!list)
{
printf("Error in malloc.\n");
return -;
}
memset(list, , sizeof(IList)); IList_Init(list);
for (i = ; i < num; i ++)
{
temp = malloc(sizeof(Student));
if (!temp)
return -;
memset(temp, , sizeof(Student));
temp->_id = i + ;
IList_Append(list, &temp->_list);
//IList_Prepend(list, &temp->_list);
} IList_Foreach(list, link)
{
temp = (pStudent)link;
printf("%d\t", temp->_id);
}
printf("\n"); printf("Input the num(1 ~ %d) that you want to:\n", IList_Size(list));
scanf("%d", &count);
link = IList_Nth(list, count);
printf("Num %d id: %d\n", count, ((pStudent)link)->_id);
printf("Id %d num: %d\n", ((pStudent)link)->_id, IList_Find(list, link)); printf("List count: %d\n", IList_Size(list));
/*for (link = IList_Head(list);!IList_IsEmpty(list);)
{
pIList tLink = link;
link = IList_Next(list, link);
IList_Remove(tLink);
free(tLink);
}*/
do
{
pIList n, pos;
IList_Foreach_Salf(list, n, pos)
{
IList_Remove(pos);
free(pos);
}
} while ();
printf("List count: %d\n", IList_Size(list)); free(list); return ;
}

通用链表实现(参考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. C语言中返回字符串函数的四种实现方法 2015-05-17 15:00 23人阅读 评论(0) 收藏

    C语言中返回字符串函数的四种实现方法 分类: UNIX/LINUX C/C++ 2010-12-29 02:54 11954人阅读 评论(1) 收藏 举报 语言func存储 有四种方式: 1.使用堆空 ...

  2. ubuntu 14.04 64位系统编译RT288x_SDK

    sudo apt-get install gcc g++ binutils patch bzip2 flex bison make autoconf gettext texinfo unzip sha ...

  3. easyui反选全选和全不选代码以及方法的使用

    首先要说明的是,onclick="javascript:这里能写方法的名字,也能写一段JS的代码,但是方法名字要带括号.",其次就是onclick=“这里写的方法名必须存在于本页面 ...

  4. Spring Bean生命周期

    1.Bean的建立:BeanFactory容器寻找Bean的定义信息,读取Bean定义文件,并将其实例化,生成各个Bean实例.2.属性注入:使用依赖注入,Spring按照Bean定义信息配置Bean ...

  5. Android学习过程中遇到的问题

    1.使用在Activity布局之上重叠显示操作栏,第一次使用出现错误信息. 错误信息如下:java.lang.RuntimeException:Ubable to start activity Com ...

  6. Git版本管理:Windows下Git配置与使用指南

    简要介绍:Git是一个开源的分布式版本控制系统,用以有效.高速的处理从很小到非常大的项目版本管理. 一.安装 软件:msysGit-fullinstall-1.8.1.2 打开之后设置安装路径,默认为 ...

  7. JS阻塞的问题

    常见问题    http://www.zhihu.com/question/23101413   阻塞特性:        JS 有个很无语的阻塞特性,就是当浏览器在执行JS 代码时,不能同时做其他任 ...

  8. as3.0:文字 效果

    //文字描边效果var tf1 = _root.createTextField("tf1", _root.getNextHighestDepth(), 10, 10, 0, 0); ...

  9. PostQuitMessage, PostThreadMessage( WM_QUIT )

    http://blogs.msdn.com/b/oldnewthing/archive/2005/11/04/489028.aspx Why is there a special PostQuitMe ...

  10. Apache、Tomcat、JBoss、Weblogic四个常用的JavaEE服务器

    Apache全球应用最广泛的http服务器,免费,出自apache基金组织 Tomcat应用也算非常广泛的web 服务器,支持部分j2ee,免费,出自 apache基金组织 JBoss开源的应用服务器 ...