尽管进行了相应的更正,为什么指向指针的指针与指针的处理方式不同

Why is a pointer to pointer treated differently than a pointer in spite of corresponding corrections

我正在尝试从双向链表中删除一个节点。函数 deleteNode() 将接收链表的头部和要删除的节点。但是,根据我是将要删除的节点作为指针还是指向指针的指针传递,代码的行为会有所不同(尽管在语法中进行了相应的更正)。

这是我的双向链表节点结构 -

struct DNode {
int val;
struct DNode* next;
struct DNode* prev;
DNode(int val) { //constructor
    this->val = val;
    next = NULL;
    prev = NULL;
}
};

下面的代码工作得很好:

void deleteNode(struct DNode** head, struct DNode* deleteMe) {
//head is pointer to pointer, deleteMe is pointer

if(!(*head) || !deleteMe) {
    cout<<"\nDeletion not possible";
    return;
}

if(deleteMe->prev != NULL)
    deleteMe->prev->next = deleteMe->next;

if(deleteMe->next != NULL)
    deleteMe->next->prev = deleteMe->prev;

if(deleteMe == *head)
    *head = deleteMe->next;

delete deleteMe;
}

对应的驱动代码-

/*at this point, I have pushed elements into the Linked List to make it 4->3->2->1, where 4 is 
the head*/
deleteNode(&head, head);      
deleteNode(&head, head->next); 
deleteNode(&head, head->next); 

但是,当我将两个参数作为指向指针的指针发送时,我在 运行 时遇到崩溃:

void deleteNode(struct DNode** head, struct DNode** deleteMe) {

if(!(*head) || !(*deleteMe)) {
    cout<<"\nDeletion not possible";
    return;
}

if((*deleteMe)->prev != NULL)
    (*deleteMe)->prev->next = (*deleteMe)->next;

if((*deleteMe)->next != NULL)
    (*deleteMe)->next->prev = (*deleteMe)->prev;

if(*deleteMe == *head)
    *head = (*deleteMe)->next;

delete *deleteMe;
}

对应驱动代码:

/*at this point, I have pushed elements into the Linked List to make it 4->3->2->1, where 4 is 
the head*/
deleteNode(&head, &head);      
deleteNode(&head, &head->next);
deleteNode(&head, &head->next);

PS - 这不完全是删除的问题:

如果您在错误代码中注释行 delete *deleteMe,代码将 运行 但输出会不同。

工作代码的输出:3

注释删除行后错误代码的输出:3->1

在这里,当你传递 &head&head 时,

if(*deleteMe == *head)
    *head = (*deleteMe)->next;

*deleteMe*head是同一个对象(你传入地址的那个对象),赋值后还是同一个对象
(即相当于*head = (*head)->next;*deleteMe = (*deleteMe)->next。)

所以这个,

delete *deleteMe;

在这种情况下与 delete *head 相同,然后事情就开始了。

在第一种情况下,*headdeleteMe是不同的对象,因此分配给*head不会影响deleteMe

作为示例,这就是发生的情况(“main_head”是 main 中的变量)。

当你进入函数时,出现这种情况:

  head
   |
   v          +---+   +---+
main_head---->|  ---->| ----> ...
   ^          +---+   +---+
   |                    ^
 deleteMe               |
                  (*deleteMe)->next

赋值后*head = (*deleteMe)->next:

  head    +-------------+
   |      |             |
   |      |             v
   v      |   +---+   +---+
main_head-+   |  ---->| ----> ...
   ^          +---+   +---+
   |
 deleteMe

你可以看到 headdeleteMe 仍然指向 mainhead,那是你赋值的对象。

使用工作代码,您可以从这里开始:

  head        
   |           
   v          +---+   +---+
main_head---->|  ---->| ----> ...
              +---+   +---+
                ^       ^
                |       |
            deleteMe   deleteMe->next

最后是

  head    +-------------+
   |      |             |
   |      |             v
   v      |   +---+   +---+
main_head-+   |  ---->| ----> ...
              +---+   +---+
                ^       ^
                |       |
            deleteMe   deleteMe->next