我尝试在一个向量中存储节点指针,但是出现了堆使用后释放错误。

huangapple go评论76阅读模式
英文:

I am trying to store node pointers in a vector and I am having a heap-use-after-free error

问题

我在解决Leetcode问题 206. 反转链表:

> 给定一个单链表的头节点 head,反转该链表并返回反转后的链表

以下是我的代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        vector<ListNode*> addrs;
        ListNode* cur=head;
        if(cur==NULL||cur->next==NULL) return cur;

        // 将所有节点地址按顺序存储
        while(cur!=NULL)
        {
            addrs.push_back(cur);
            cur=cur->next;
        }
        // 反转过程
        for(int i=addrs.size()-1;i>0;i--)
        {
            addrs[i]->next=addrs[i-1];
        }
        return addrs[addrs.size()-1];
    }
};

当我在LeetCode上测试这段代码时,出现了以下错误:

> 错误: AddressSanitizer: 堆使用后释放

我猜测这个错误与向量有关。然而,我不明白为什么会出现这个错误。有人能帮我解释为什么会出现这个错误吗?

英文:

I am solving the Leetcode problem 206. Reverse Linked List:

> Given the head of a singly linked list, reverse the list, and return the reversed list.

Here is my code.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        vector<ListNode*> addrs;
        ListNode* cur=head;
        if(cur==NULL||cur->next==NULL) return cur;

        // storing all addrs in sequence
        while(cur!=NULL)
        {
            addrs.push_back(cur);
            cur=cur->next;
        }
        // reversing process
        for(int i=addrs.size()-1;i>0;i--)
        {
            addrs[i]->next=addrs[i-1];
        }
        return addrs[addrs.size()-1];
    }
};

When I test the code at LeetCode, I get this error:

> ERROR: AddressSanitizer: heap-use-after-free

I am guessing that the error is related to the vector. However I don't get the exact reason why I have this error. Can someone help me why I am getting this error?

答案1

得分: 4

这个错误并不发生在你的代码中,而是发生在LeetCode平台在调用你的函数后执行的清理代码中。

更深层次的原因是你的函数没有设置原始头结点的 next 成员。这个节点已经成为了尾部,所以它的 next 成员应该更新为 nullptr,但你忘记了这样做。因此,你重连的链表没有终点。它在最后两个节点之间形成了一个循环。

因此,当LeetCode想要释放你的链表使用的内存时 -- 未料到它会有一个循环 -- 它会第二次访问一个节点并尝试再次释放它:这会触发异常。

解决方案很简单。在最终的 return 语句之前添加以下代码:

addrs[0]->next = nullptr; 

注意,在你的代码中应该使用 nullptr 而不是 NULL

另外,一个仍然存在的挑战是在不使用O(n)辅助内存的情况下解决这个练习,也就是说,不使用向量。只用几个指针变量是可以做到的。也许你想试一试...

英文:

This error does not occur in your code, but in the cleanup code that the LeetCode platform executes after having called your function.

The deeper cause is that your function does not set the next member of the original head node. This node has become the tail and so its next member should be updated to nullptr, which you forgot to do. By consequence your rewired linked list has no end. It has a cycle between its last two nodes.

And so when LeetCode wants to free up the memory used by your linked list -- not expecting it to have a cycle -- it will visit a node for a second time and try to free it again: this triggers the exception.

The solution is simple. Add this code just before the final return statement:

addrs[0]->next = nullptr; 

Note that you should use nullptr in your code instead of NULL.

Also, a remaining challenge is to solve this exercise without O(n) auxiliary memory, i.e. without the vector. It is possible to do with just a few pointer variables. Maybe you want to try that...

huangapple
  • 本文由 发表于 2023年4月4日 15:57:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75926847.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定