问题
垂悬指针问题,这个问题的定义我是知道的。通常是说当指向某块内存的指针被释放之后,需要及时置空。否则,如果不置空,当下次不小心访问到时,会导致错误。当然,这个问题说起来很简单。觉得也没什么太大的问题,但是指针这一块确实得非常小心,从下面我范的这个问题说起。
下面这段代码是我刷leetcode的时候的一段代码,主要删除链表中重复的元素。当然下面的代码是正确的。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
if(!head) return NULL;
ListNode* ret = head;
ListNode* pre = NULL;
while( head ){
if(head->val == val)
{
ListNode* cur = head;
if(pre)
pre->next = head->next;
head = head->next;
}
else
{
head = head->next;
ret = head; // 这里没有,一直RE
}
delete cur;
}
else
{
pre = head;
head = head->next;
}
}
return ret;
}
};
但是,我第一次写的时候,在注释处的代码是没有的,也就是说我忘了更新ret的值。代码就一直RE。
那么我们仔细分析一下这个问题,对于ret的更新,是在头结点被删除的时候才会。那么如果不更新会导致什么结果呢?对于头结点来说,ret和head都指向他,程序在执行循环的时候,发现头结点的值和val一样,所以考虑删除这个节点,那么此时 delete head.会释放这段空间,由于head又指向了下一个节点,所以并不会出现垂悬指针问题。但是本题的问题出现的非常隐蔽,当多个指针指向一块内存时,此时用head释放了该处内存,但是ret任然指向这块内存。所以,最后返回的时候,对ret的访问会导致RE。因为ret在之前应该被置位垂悬指针,否则访问后就会出现错误。本题就是栽在了这个上面。
所以,当多个指针指向同一块内存时,务必保证当这块内存释放时,一定要把指向这块内存的所有指针都置空。