低级错误之遍历链表时删除节点

首先感谢一下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;
}

深深地记住这个吧,小错不小伤神儿.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

袁保康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值