[英]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->key
或tempNode->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.