ImageVerifierCode 换一换
格式:DOCX , 页数:13 ,大小:256.43KB ,
资源ID:2900296      下载积分:12 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/2900296.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(Linux学习分析listh 之 函数部分.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

Linux学习分析listh 之 函数部分.docx

1、Linux学习分析listh 之 函数部分Linux学习-分析list.h 之 函数部分 分类: Linux C 2010-08-31 09:57 1073人阅读 评论(3) 收藏 举报 在Linux中,最常见也是最经典的数据结构就是其中的双向链表,而对双向链表的各种操作都存储在list.h头文件中,最近仔细看了一下这个头文件,把我对它的理解记录下来,算是一个学习笔记吧。我看的是2.6.35.4版本的内核源代码,list.h在include/linux下存放,相对于一些其他的内核原文件来说,list.h算是比较小的了,而且只有700多行,主要是因为这个文件算是一个纯C文件,就是它是单纯的用C语

2、言来对双向链表进行操作,看起来也比较容易。 在list.h中,定义了如下一个数据结构:1. structlist_head2. structlist_head*next,*prev;3. ;这是一个双向链表,但是不存储数据,只是做一个相互连接的作用,定义了一个指向后一元素的指针和指向前一元素的指针。定义这样一个没有存储数据的数据结构,我觉得好处是可以广泛嵌套使用,把它当做一座桥,只是连接,然后再配合上其他变量来存储数据,一起形成一个结构体,这样后面对其操作就可以通用了,不必换一种数据就换一堆操作了。 对于双向链表的初始化,list.h中给出了两个方法,一个是宏定义的方法,另一个是函数的方法:1

3、. #defineLIST_HEAD_INIT(name)&(name),&(name) 2. #defineLIST_HEAD(name)/ 3. structlist_headname=LIST_HEAD_INIT(name)4. staticinlinevoidINIT_LIST_HEAD(structlist_head*list)5. 6. list-next=list;7. list-prev=list;8. 前两个宏定义要结合起来看,第二个宏定义是一个结构体的赋初值,再看第一个宏定义,就是说把name这个list_head类型的结构体的第一个元素赋值为name的地址,第二个元素也赋

4、值为name的地址,再结合上面的结构体的定义,就是说把name-next和name-prev都赋值为name自己,也就是指向自身,这样就是初始化好了一个双向链表的结点。而第二种用函数的方法就是直接把我上面的分析转换成代码的形式了,意思和功能是一样的。 对于链表的操作不过是“增删改查”几种,双向链表也不例外。 一、在进行增加操作时,list.h中的代码如下:1. staticinlinevoid_list_add(structlist_head*new,2. structlist_head*prev,3. structlist_head*next)4. 5. next-prev=new;6. n

5、ew-next=next;7. new-prev=prev;8. prev-next=new;9. 10. staticinlinevoidlist_add(structlist_head*new,structlist_head*head)11. 12. _list_add(new,head,head-next);13. 14. staticinlinevoidlist_add_tail(structlist_head*new,structlist_head*head)15. 16. _list_add(new,head-prev,head);17. 总共定义了三个函数,大致一看,后两个是调用

6、了第一个函数。对于第一个函数,首先分析它的参数是什么,第一个参数new,是一个类型为list_head的指针,指向要增加的结点,而prev和next也都是list_head类型的指针,顾名思义,就是指向增加的位置的前面和后面的结点,在函数内部,首先是把要增加位置的后面的结点的prev元素赋值为new,再把new的next元素指向后面结点,意思是先把后面的结点与新增结点相连;然后是把new的prev元素指向前面结点,再把前面结点的next赋值为new,意思是把前面的结点与新增结点相连。对于第二个函数,分析其调用_list_add()是的实参,第二个为head,第三个为head-next,也就是说

7、要把新增结点加到head之后,head-next之前,也就是增加一个结点到头结点后,类似于单链表的头插法。对于第三个函数,它调用_list_add()时,第二个参数为head-prev,第三个为head,就是要把新增结点加到head-prev之后,head之前,对于双向链表来说,head-prev正是链表的最后一个结点,所以这个函数的功能就是在链表的最后增加新结点,类似于单链表的尾插法。 二、对于删除操作,list.h的代码如下:1. staticinlinevoid_list_del(structlist_head*prev,structlist_head*next)2. 3. next-p

8、rev=prev;4. prev-next=next;5. 6. staticinlinevoidlist_del(structlist_head*entry)7. 8. _list_del(entry-prev,entry-next);9. entry-next=LIST_POISON1;10. entry-prev=LIST_POISON2;11. 12. staticinlinevoidlist_del_init(structlist_head*entry)13. 14. _list_del(entry-prev,entry-next);15. INIT_LIST_HEAD(entry)

9、;16. 同样也是定义了三个函数,而后两个函数也是调用了第一个函数。先看第一个函数,简单地说一下,就是把要删除的这个结点后面的结点的prev指向要删除结点的前面的结点,在把要删除的这个结点的前面的结点的next指向要删除的后面的那个结点,说的比较复杂,但是理解起来应该不难,简而言之,就是把要删除的这个的前后相连,就把它自己分离出来了。但是光把前后结点相连还没有彻底完成删除,还要对待删除结点进行一些操作,后面的两个函数的不同点就是处理这个待删除节点的操作时不一样的。先解释第三个函数的操作,INIT_LIST_HEAD(entry),就是前面说到过的那个初始化函数,作用是把entry的prev和n

10、ext都指向它自身,就不会让它们乱指,也是一种安全的删除方式。再看看第二个函数它是分别将next和prev赋值为LIST_POISON1和LIST_POISON2,这两个是宏定义的常量,在include/linux/poison.h中定义的,源代码如下:1. /*2. *Thesearenon-NULLpointersthatwillresultinpagefaults3. *undernormalcircumstances,usedtoverifythatnobodyuses4. *non-initializedlistentries.5. */6. #defineLIST_POISON1(

11、void*)0x00100100+POISON_POINTER_DELTA) 7. #defineLIST_POISON2(void*)0x00200200+POISON_POINTER_DELTA)大概意思就是一个常人基本不能用的一个地址,就相当于把prev和next屏蔽掉,不能通过它在切入到链表中,但是它属于不安全的方式。 三、对于修改操作,在list.h中是用替换的方式来的,源代码如下:1. staticinlinevoidlist_replace(structlist_head*old,2. structlist_head*new)3. 4. new-next=old-next;5.

12、new-next-prev=new;6. new-prev=old-prev;7. new-prev-next=new;8. 9. staticinlinevoidlist_replace_init(structlist_head*old,10. structlist_head*new)11. 12. list_replace(old,new);13. INIT_LIST_HEAD(old);14. 修改比较简单,就是把要修改的那个结点的prev和next赋值给新的结点,然后把原来前后的结点对应的next和prev再指向新结点,这就是第一个函数的作用,就是用来修改指向的,而对于修改过的那个结点

13、要做类似于删除的操作,在第二个函数中体现,与上文提到的删除一样,使用INIT_LIST_HEAD()函数,把原来的结点的prev和next都指向自己,安全删除。 四、对于移动操作,在list.h中的定义如下:1. staticinlinevoidlist_move(structlist_head*list,structlist_head*head)2. 3. _list_del(list-prev,list-next);4. list_add(list,head);5. 6. staticinlinevoidlist_move_tail(structlist_head*list,7. structlist_head*head)8. 9. _list_del(list-prev,list-next);10. list_add_tail(list,head);11. 定义了两个函数,但是函数体中的东西都是很眼熟的,我就不多说了,宏观上说一下,第一个函数是把一个结点移动到头结点之后,使用的方法就是把待移动结点从原来位置分离出来(使用_list_del函数),然后在把它增加到头结点后(使用list_add函数);第二个函数是把一个结点移动到最后,使用的方法也是先把待移动结点从原

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1