链表为什么会出现空指针的细节讲解
个人主页:欢迎大家光临——>沙漠下的胡杨
各位大帅哥,大漂亮
如果觉得文章对自己有帮助
可以一键三连支持博主
你的每一分关心都是我坚持的动力
![]()
☄: 本期重点:链表的细节讲解
希望大家每天都心情愉悦的学习工作。
目录
首先我们先明白一个问题,左值和左值是什么?
下面用个简单的链表举例子:
链表元素的修改
我们来看一个简单的题吧:
今天我们就讨论下:链表的一些细节,祝各位刷题一次过哦
首先我们先明白一个问题,左值和左值是什么?
详情请阅读这篇文章——》左右值概念
左值:在 "="的左边一般使用的是变量的空间
右值:在 "="的右边一般使用的是变量的数据(值)
下面用个简单的链表举例子:
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;}