C++ c+中的内存分配+;使用分离函数

C++ c+中的内存分配+;使用分离函数,c++,pointers,memory,dynamic,reference,C++,Pointers,Memory,Dynamic,Reference,我有cplusplus代码来制作单链表 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) {} }; 使用以下功能: static void push_l

我有cplusplus代码来制作单链表

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) {}
};
使用以下功能:

static void push_list(struct ListNode*& _head, int _val)
{

    if (NULL == _head)
        _head = new ListNode(_val);

    else{
        ListNode* tmp = _head->next;
        while (tmp != NULL)
            tmp = tmp->next;
        tmp = new ListNode(_val);
    }
}
但是,它只分配一个元素,head->next保持为空

函数的调用如下所示:

static void MakeList(void)
{
    ListNode* l1 = NULL;
    push_list(l1, 1);
    push_list(l1, 2);
    push_list(l1, 3);
    push_list(l1, 4);
}
您的
推送列表()
实现错误

\u head
为空时,您将创建一个新节点并将其分配给
\u head
。好的,到目前为止

但是在随后的调用中,当
\u head
不为null时,您将
\u head->next
分配给
tmp
,并且当列表有1个节点时,
\u head->next
将为null。因此,您的
虽然
循环没有做任何事情,但将
tmp
设置为null(即使列表中有多个节点,您的循环最终将到达最后一个节点,并将
tmp
设置为其
下一个
,因此无论是否输入循环
tmp
都将始终为null)。然后创建一个新节点,并将其仅分配给
tmp
,而不是分配给列表中最后一个节点的
next
字段。因此,您泄漏了新节点,
\u head->next
在下次调用
push\u list()
时保持空值,从而一次又一次地导致相同的问题

要解决此问题,需要调整循环以查找列表中的最后一个节点,然后可以将新节点分配给最后一个节点的
next
字段,例如:

静态无效推送列表(ListNode*&\u head,int\u val)
{
如果(!\u头)
_head=新的ListNode(_val);
否则{
ListNode*tmp=\u head;//下一步!
而(tmp->next){//next;
}
//tmp现在指向最后一个节点,而不是null!
tmp->next=新列表节点(_val);
}
}

push_list()
然后可以通过使用稍微不同、更优化的循环策略进一步简化:

静态无效推送列表(ListNode*&\u head,int\u val)
{
ListNode**tmp=&_头;
而(*tmp){
tmp=&(*tmp)->下一步;
}
*tmp=新的ListNode(_val);
}
此循环查找第一个为null的
ListNode*
指针,然后为该指针分配一个新节点。这样,您就不必单独处理头部。
\u头
本身将为空,或者列表中最后一个节点的
下一个
字段将为空。第一个可用的空值是您要插入新节点的位置。

您的
推送列表()
实现错误

\u head
为空时,您将创建一个新节点并将其分配给
\u head
。好的,到目前为止

但是在随后的调用中,当
\u head
不为null时,您将
\u head->next
分配给
tmp
,并且当列表有1个节点时,
\u head->next
将为null。因此,您的
虽然
循环没有做任何事情,但将
tmp
设置为null(即使列表中有多个节点,您的循环最终将到达最后一个节点,并将
tmp
设置为其
下一个
,因此无论是否输入循环
tmp
都将始终为null)。然后创建一个新节点,并将其仅分配给
tmp
,而不是分配给列表中最后一个节点的
next
字段。因此,您泄漏了新节点,
\u head->next
在下次调用
push\u list()
时保持空值,从而一次又一次地导致相同的问题

要解决此问题,需要调整循环以查找列表中的最后一个节点,然后可以将新节点分配给最后一个节点的
next
字段,例如:

静态无效推送列表(ListNode*&\u head,int\u val)
{
如果(!\u头)
_head=新的ListNode(_val);
否则{
ListNode*tmp=\u head;//下一步!
而(tmp->next){//next;
}
//tmp现在指向最后一个节点,而不是null!
tmp->next=新列表节点(_val);
}
}

push_list()
然后可以通过使用稍微不同、更优化的循环策略进一步简化:

静态无效推送列表(ListNode*&\u head,int\u val)
{
ListNode**tmp=&_头;
而(*tmp){
tmp=&(*tmp)->下一步;
}
*tmp=新的ListNode(_val);
}

此循环查找第一个为null的
ListNode*
指针,然后为该指针分配一个新节点。这样,您就不必单独处理头部。
\u头
本身将为空,或者列表中最后一个节点的
下一个
字段将为空。第一个可用的空值是您要插入新节点的位置。

您应该使用调试器逐步完成代码。这将有助于您理解为什么代码与预期不符时,
tmp
仅在列表末尾包含
NULL
指针的副本。更改此副本的值不会更改存储在链接列表末尾的原始值。因此,您可能希望使
tmp
成为双指针或指针的引用,就像您使用
\u head
参数一样;std::vector.在旁注中,您不应该将
NULL
nullptr
混合在一起。因为您有可用的
NULL ptr
,所以应该在任何地方都使用它,而不是使用
NULL
nullptr
被发明来代替NULL。您应该使用调试器逐步检查代码。这将有助于您理解为什么代码与预期不符时,
tmp
仅在列表末尾包含
NULL
指针的副本。更改此副本的值不会更改存储在链接列表末尾的原始值。因此,您可能希望使
tmp
成为双指针或引用