> 文档中心 > 链表为什么会出现空指针的细节讲解

链表为什么会出现空指针的细节讲解


  个人主页:欢迎大家光临——>沙漠下的胡杨

  各位大帅哥,大漂亮

 如果觉得文章对自己有帮助

 可以一键三连支持博主

 你的每一分关心都是我坚持的动力

 

 ☄: 本期重点:链表的细节讲解

  希望大家每天都心情愉悦的学习工作。 


                              目录                            

首先我们先明白一个问题,左值和左值是什么? 

 下面用个简单的链表举例子:

链表元素的修改

我们来看一个简单的题吧


                 今天我们就讨论下:链表的一些细节,祝各位刷题一次过哦                     

首先我们先明白一个问题,左值和左值是什么?

详情请阅读这篇文章——》左右值概念

左值:在 "="的左边一般使用的是变量的空间

右值:在 "="的右边一般使用的是变量的数据(值)

 下面用个简单的链表举例子:

int main(){struct ListNode* n1 = (struct ListNode*)malloc(sizeof(struct ListNode));assert(n1);struct ListNode* n2 = (struct ListNode*)malloc(sizeof(struct ListNode));assert(n2);struct ListNode* n3 = (struct ListNode*)malloc(sizeof(struct ListNode));assert(n3);n1->val = 1;n2->val = 2;n3->val = 3;n1->next = n2;n2->next = n3;n3->next = NULL;return 0;}

代码附上啦 ~!

我们开始分析,链表本质我们是把一些结构体,通过结构体的自引用的形式给串联起来了,其中结构体又分为两部分,一个是数据域,一个是指针域(存放下一个结点的位置)

而我们常常会对指针域的部分,进行相关操作。

比如 n1->next = n2。

这个时候我们就要深刻的明白左右值的问题。n2是使用的空间还是内容呢?

我们调试下观看:

 这里我们知道了,n1->val 在表达式中使用的是空间,n2->val 和 n3->val同理。

在n1->next = n2中,n1->next呢?我们接着看图。

这里我们通过对结构体变量取地址和对结构体整体取地址可以看出,其实n1->next 的内容就是n2结构体整体的地址,n1->next = n2这个表达式中,在这里 n1->next 使用的是空间,n2使用的是 数据 ,n2的数据其实就是n2整个结构体的地址。同理n2->next = n3一样。在n3->next = NULL中,n3->next指向的为NULL,其实是把 0 地址赋值n3->next了。

链表元素的修改

链表的结构我们已经清楚啦,那么我们做题时经常会遇到一些需要进行链表结点的修改,我们修改时要注意哪些细节呢?

先看下上面链表展开的图吧:

 我们可以看出这个结构是一环套一环的,如果修改的话,稍微不注意就会找不到链表,或者陷入死循环啦。

就比如我想修改 n2 的指向,我直接把 n2 指向其他地方可以吗?

这一定是不可以的,因为 n2 的指向还指向着 n3 的,我们把n2的指向改变啦,那么n3是不是就丢啦,还有的小伙伴说我们可以通过 n1 找到啊,其实在我们修改n2时,n1中的n2也修改啦,所以直接改变指向后,我们是不能找到n3啦。

                      那我们怎么做呢?                          

这时候就要有临时变量来存储 n2的指向啦,n2的指向是什么呢?n2->next 其实就是n3结构体的地址。

看个图来理解下:

 这其实就是插入一个结点,但是往往在这里会有问题。

会忘记要不要创建临时变量?(防止结点覆盖找不到后续结点)

这个n2->next为什么和n3是等价的?(调试可以看出,上面有图)

这个结点为啥不直接指向n3?(n3已经丢失啦,临时变量存的是n3)

 

同样的我们删除链表元素时也要注意这一点,如果是尾部删除就好点,把上一个结点置NULL,然后free掉,其他部位删除还是要考虑一下删除后是够能够找到下一个结点,否则就是写代码一时爽,调试代码痛苦一下午。

看个图吧:

我们来看一个简单的题吧:

反转链表_牛客题霸_牛客网

 比较简单的翻转链表,我们来简单分析下吧:

首先我们可以不用上哨兵位的头结点来解决,如图:

 

刚开始时的图片和结束的图片已奉上了。 可先写一下代码哦。

需要注意一点的是,如果传进来的为NULL,或者head->next = NULL,表示链表只有一个或者没有元素,直接返回就好啦。

代码如下:

struct ListNode* reverseList2(struct ListNode* head){if (head == NULL || head->next == NULL){return head;}struct ListNode *tail = NULL;struct ListNode *phead = head;while (phead){struct ListNode *tmp = phead->next;phead->next = tail;tail = phead;phead = tmp;}return tail;}

                      如果感觉有用的请给出你们宝贵的三连吧                          

找手机网游