简体   繁体   English

C中的链表:将当前节点分配给临时节点指针时会发生什么?

[英]Linked List in C: What happens when we assign the current node to a temporary node pointer?

I have been given a task to write a function to reverse a doubly-linked list. 我被赋予编写一个逆向双向链表的功能的任务。 I wrote the function and named it reverse() . 我编写了函数并将其命名为reverse() The function is given below: 功能如下:

struct node* reverse(struct node** head_ref){
    struct node *current=*head_ref;
    struct node *tempNode=(struct node *)malloc(sizeof(struct node));
    if(current->next == NULL){
        return current;
    }
    while(current->next != NULL){
        //tempNode=current;
        tempNode->key=current->key;
        tempNode->data=current->data;
        tempNode->next=current->next;
        tempNode->prev=current->prev;
        current->next=current->prev;
        current->prev=tempNode->next;
        current=tempNode->next;
    }
    current->next=current->prev;
    current->prev=NULL;
    *head_ref =current;
    return current;
}

Where the struct node** head_ref parameter takes the reference of the head node &head as an argument. 其中struct node** head_ref参数将头节点&head的引用作为参数。 The function works fine. 该功能工作正常。 But my question here is instead of doing 但是我的问题不是

tempNode->key=current->key;
tempNode->data=current->data;
tempNode->next=current->next;
tempNode->prev=current->prev;

Why can't I just do tempNode=current; 为什么我不能只做tempNode=current; ? When I try doing that instead my function doesn't produce the expected result. 当我尝试这样做时,我的函数无法产生预期的结果。

tempnode = current assign pointer, it means that both tempnode and currect would be pointing to the same address in memory. tempnode = current分配指针,这意味着tempnode和currect都将指向内存中的同一地址。

tempnode = curr; // tempnode = 1036;

  1020   1028   1036   1044
+------+------+------+------+
|      |      | curr |      |
+------+------+------+------+
                 ^
                 |
tempnode ---------

You just need tempnode to have same values so you have to do deep copy , its what exactly you are doing. 您只需要tempnode具有相同的值,因此您必须进行deep copy ,这正是您在做什么。

tempNode->key=current->key;
tempNode->data=current->data;
tempNode->next=current->next;         // You just copy the content of node
tempNode->prev=current->prev;         // But they are in another part of memory

  120    ....   1028   1036   1044
+------+------+------+------+------+
| temp |      | curr |      |      |
+------+------+------+------+------+

They have same values but they are pointing to another address. 它们具有相同的值,但是它们指向另一个地址。

I can see you are overwiting some pointers, you shouldnt do it becouse you are loosing address of allocated memory -> you cant free it anymore. 我可以看到您忽略了一些指针,您不应该这样做,因为您正在丢失分配的内存地址->您不能再释放它。

Store to some temp variable and after you remove it from node, you can free that memory. 将其存储到某个临时变量,然后将其从节点中删除,即可释放该内存。

Note that you really don't need to set tempNode->key or tempNode->data ; 注意,您实际上不需要设置tempNode->keytempNode->data you leave those fields in the current node alone. 您可以将这些字段留在当前节点中。 However, if you did structure assignment ( *tempNode = *current; ) rather than pointer assignment ( tempNode = current; ), you would be OK. 但是,如果您进行了结构分配( *tempNode = *current; )而不是指针分配( tempNode = current; ),那么您会好的。

Note that your code leaks a node every time the list is reversed; 请注意,每次列表反转时,您的代码就会泄漏节点; you don't free the tempNode that you allocate (probably because you've overwritten the allocated space with the pointer assignment). 您不会释放分配的tempNode (可能是因为您已经用指针分配覆盖了分配的空间)。 It would be better not to use malloc() for such a small structure; 最好不要对如此小的结构使用malloc() simply use struct node tempNode; 只需使用struct node tempNode; and then tempNode = *current; 然后tempNode = *current; and reference members by tempNode.next etc. There's then no need to free it. 并通过tempNode.next等引用成员。则无需释放它。

In fact, given that there's really no need to copy the key and data, I'd probably use struct node *old_next = current->next; 实际上,鉴于确实不需要复制密钥和数据,我可能会使用struct node *old_next = current->next; and struct node *old_prev = current->prev; struct node *old_prev = current->prev; and then flip the links: current->prev = old_next; current->next = old_prev; current = old_next; 然后翻转链接: current->prev = old_next; current->next = old_prev; current = old_next; current->prev = old_next; current->next = old_prev; current = old_next; , as in the code shown. ,如显示的代码所示。 Keeping track of old_curr so that the correct value can be 'returned' (assigned to the pointer in the calling code via head_ref ) is the other wrinkle in this code. 跟踪old_curr以便可以“返回”正确的值(通过head_ref分配给调用代码中的指针)是此代码中的另一个head_ref Note that it manages to avoid special-casing the empty list and the one-entry list. 注意,它设法避免对空白列表和单项列表进行特殊的装箱。

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

struct node
{
    int key;
    int data;
    struct node *prev;
    struct node *next;
};

static struct node *reverse(struct node **head_ref)
{
    struct node *current = *head_ref;
    struct node *old_curr = 0;
    while (current != 0)
    {
        struct node *old_next = current->next;
        struct node *old_prev = current->prev;
        current->prev = old_next;
        current->next = old_prev;
        old_curr = current;
        current = old_next;
    }
    *head_ref = old_curr;
    return current;
}

static struct node *create(int key, int data)
{
    struct node *p = malloc(sizeof(*p));
    if (p != 0)
    {
        p->key = key;
        p->data = data;
        p->next = 0;
        p->prev = 0;
    }
    return p;
}

static struct node *insert_head(struct node *head, int key, int data)
{
    struct node *n = create(key, data);
    assert(n != 0);
    if (head != 0)
        head->prev = n;
    n->next = head;
    return n;
}

static void print_list(const char *tag, struct node *head)
{
    printf("%s: [", tag);
    const char *pad = "";
    while (head != 0)
    {
        printf("%s(%d => %d)", pad, head->key, head->data);
        pad = ",";
        head = head->next;
    }
    printf("]\n");
}

static void free_list(struct node *head)
{
    while (head != 0)
    {
        struct node *next = head->next;
        free(head);
        head = next;
    }
}

int main(void)
{
    for (int size = 0; size < 10; size++)
    {
        struct node *list = 0;
        for (int i = 0; i < size; i++)
            list = insert_head(list, i, (7 * i + 4 + size) % 10);
        print_list("New list", list);
        reverse(&list);
        print_list("Rev list", list);
        free_list(list);
    }
    return 0;
}

When run, the program produces the output: 运行时,程序将产生输出:

New list: []
Rev list: []
New list: [(0 => 5)]
Rev list: [(0 => 5)]
New list: [(1 => 3),(0 => 6)]
Rev list: [(0 => 6),(1 => 3)]
New list: [(2 => 1),(1 => 4),(0 => 7)]
Rev list: [(0 => 7),(1 => 4),(2 => 1)]
New list: [(3 => 9),(2 => 2),(1 => 5),(0 => 8)]
Rev list: [(0 => 8),(1 => 5),(2 => 2),(3 => 9)]
New list: [(4 => 7),(3 => 0),(2 => 3),(1 => 6),(0 => 9)]
Rev list: [(0 => 9),(1 => 6),(2 => 3),(3 => 0),(4 => 7)]
New list: [(5 => 5),(4 => 8),(3 => 1),(2 => 4),(1 => 7),(0 => 0)]
Rev list: [(0 => 0),(1 => 7),(2 => 4),(3 => 1),(4 => 8),(5 => 5)]
New list: [(6 => 3),(5 => 6),(4 => 9),(3 => 2),(2 => 5),(1 => 8),(0 => 1)]
Rev list: [(0 => 1),(1 => 8),(2 => 5),(3 => 2),(4 => 9),(5 => 6),(6 => 3)]
New list: [(7 => 1),(6 => 4),(5 => 7),(4 => 0),(3 => 3),(2 => 6),(1 => 9),(0 => 2)]
Rev list: [(0 => 2),(1 => 9),(2 => 6),(3 => 3),(4 => 0),(5 => 7),(6 => 4),(7 => 1)]
New list: [(8 => 9),(7 => 2),(6 => 5),(5 => 8),(4 => 1),(3 => 4),(2 => 7),(1 => 0),(0 => 3)]
Rev list: [(0 => 3),(1 => 0),(2 => 7),(3 => 4),(4 => 1),(5 => 8),(6 => 5),(7 => 2),(8 => 9)]

Note that I had to create 34 lines of support code for a 16-line function. 请注意,我必须为16行功能创建34行支持代码。 Granted, it wasn't all that hard, but an MCVE ( Minimal, Complete, Verifiable Example ) would have provided that infrastructure so I didn't have to do it. 当然,这并不困难,但是MCVE( 最小,完整,可验证的示例 )将提供该基础结构,因此我不必这样做。 Please remember to create an MCVE in future. 请记住,以后要创建MCVE。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在链表中添加节点时使用双指针的原因是什么? - What is the reason for using a double pointer when adding a node in a linked list? 带有指向C中结构的指针的链表节点 - Linked list node with pointer to struct in C 链表:如何删除最后一个节点,在单个链表中我们有指向最后一个节点的指针 - linked list : how to delete last node, where we have pointer to last node in a single linked list 使用指向C中指针的指针删除链表中的节点 - remove a node in linked list using pointer to pointer in C 当我们在C中取消引用NULL指针时,操作系统会发生什么? - What happens in OS when we dereference a NULL pointer in C? C删除链表为空时的节点 - C remove node for a linked list when this is empty C中的指针行为:在节点之后初始化链接列表头 - Pointer Behaviour in C: Initializing Linked List Head after Node 创建链表时为什么要使用节点指针? - Why to use node pointer when creating a linked list? 当给出指向节点的指针时,删除单链表中的节点。 分配指针不起作用 - Deletion of node in singly linked list when pointer to the node is given. Assigning pointer doesn't work 为什么我无法将分配了 memory 的结构节点指针分配给先前值为 null 的结构节点指针以生成链表? - Why i am not able to assign a struct node pointer with allocated memory to a struct node pointer with previous value of null for making a linked list?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM