首先感谢一下CSDN居然与时俱进地支持了Markdown编写博客,这也是第一篇基于Markdown写的博客. 很多特性还不会用,看来是要学习一下了.
接下来进入正题,这次的错误纠结了三天,还是老样子,搞不出来就会觉得老天是在捉弄我吗?我真不觉得哪里出错了.但是最终的问题解决后,又会笑自己犯的错误是多么的低级.其实从某种讲这个也算是疑点难点.
错误出在了数据结构,一直也没有系统地学习过数据结构.感觉这个东西离我比较远,离我比较近的东西还有很多呢.其中具体的问题是出在了[遍历链表时删除节点],我使用的是list_for_each,结果老是有异灵事件,明明就一个节点,但是就是会有遍历出第二个,且第二个还是非法的,导致在使用的过程中出现段错误.最后才明白,如果在要遍历的过程中删除节点,那么需要使用list_for_each_safe来保证不会出现段错误.
#include <stdlib.h>
#include <string.h>
#include "list.h"
struct student //代表一个实际节点的结构
{
char name[100];
int num;
struct list_head list; //内核链表里的节点结构 用于链表的操作后面的entry 的实现就要用到该结构
};
struct student *pstudent;
struct student *tmp_student;
struct list_head student_list;
struct list_head *pos;
struct list_head *pos_tmp;
void mylist_exit(void) {
int i;
// /* 实验:将for换成list_for_each来遍历删除结点,观察要发生的现象,并考虑解决办法 */
// for (i = 0; i < 5; i++) {
// //额,删除节点,只要传个内核链表节点就行了
// list_del(&(pstudent[i].list));
// }
list_for_each_safe(pos, pos_tmp, &student_list) //list_for_each用来遍历链表,这是个宏定义
//pos在上面有定义
{
//list_entry用来提取出内核链表节点对应的实际结构节点,即根据struct list_head来提取struct student
//第三个参数list就是student结构定义里的属性list
//list_entry的原理有点复杂,也是linux内核的一个经典实现,这个在上面那篇链接文章里也有讲解
tmp_student = list_entry(pos, struct student, list);
printf("student %d name: %s\n", tmp_student->num, tmp_student->name);
list_del(&(tmp_student->list));
//打印一些信息,以备验证结果
}
//释放空间
printf("mylist_exit!\n");
free(pstudent);
}
int main(void) {
int i = 0;
//初始化一个链表,其实就是把student_list的prev和next指向自身
INIT_LIST_HEAD(&student_list);
pstudent = malloc(sizeof(struct student) * 5);//向内核申请5个student结构空间
memset(pstudent, 0, sizeof(struct student) * 5); //清空,这两个函数可以由kzalloc单独做到
for (i = 0; i < 5; i++) { //为结构体属性赋值
sprintf(pstudent[i].name, "Student%d", i + 1);
pstudent[i].num = i + 1;
//加入链表节点,list_add的话是在表头插入,list_add_tail是在表尾插入
list_add(&(pstudent[i].list), &student_list);//参数1是要插入的节点地址,参数2是链表头地址
}
list_for_each(pos,&student_list) //list_for_each用来遍历链表,这是个宏定义
//pos在上面有定义
{
//list_entry用来提取出内核链表节点对应的实际结构节点,即根据struct list_head来提取struct student
//第三个参数list就是student结构定义里的属性list
//list_entry的原理有点复杂,也是linux内核的一个经典实现,这个在上面那篇链接文章里也有讲解
tmp_student = list_entry(pos,struct student, list);
//打印一些信息,以备验证结果
printf("student %d name: %s\n", tmp_student->num, tmp_student->name);
}
mylist_exit();
return 0;
}
深深地记住这个吧,小错不小伤神儿.