如何无引用复制队列结构体?解决display清空原队列问题
问题描述
我写了一个display函数用来展示队列内容:
void display(queue_t* s) { queue_t* c = s; int i = c->size; while (i > 0) { const char* elem = dequeue(c).value; printf("Item n°%d : %s\n",i,elem); i--; }; };
其中queue_t定义如下:
typedef struct queue { node_t* head; node_t* tail; int size; } queue_t;
dequeue函数负责从队列移除节点并释放内存,功能正常。
原本希望display函数不删除队列内容就能展示,但测试发现如果在手动调用dequeue删元素前调用display,原队列会被清空。我以为queue_t* c = s;会复制队列,让c和s完全无关,显然不是这样。
如何把s的内容复制到c中,让两个变量完全独立?
补充:最小可复现示例(MWE)
头文件 queue.h
#ifndef QUEUE_H #define QUEUE_H #include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include <string.h> typedef struct element { bool type; const char* value; } element_t; typedef struct node { element_t content; struct node* previous; struct node* next; } node_t; typedef struct queue { node_t* head; node_t* tail; int size; } queue_t; queue_t* init_queue(void); node_t* init_node(element_t e); void queue(queue_t* s, element_t e); element_t dequeue(queue_t* s); void display(queue_t* s); #endif
源文件 queue.c
#include "queue.h" queue_t* init_queue(void) { queue_t* new = (queue_t*)malloc(sizeof(queue_t)); new->head = NULL; new->tail = NULL; new->size = 0; return new; }; node_t* init_node(element_t e) { node_t* new = (node_t*)malloc(sizeof(node_t)); new->content = e; new->next = NULL; new->previous = NULL; return new; }; void queue(queue_t* s, element_t e) { node_t* n = init_node(e); if (s->size == 0) { s->head = n; s->tail = n; s->size = 1; } else { n->previous = s->tail; s->tail = n; s->size++; }; }; element_t dequeue(queue_t* s) { if (s->size == 0) { element_t empty; empty.type = true; empty.value = "0"; return empty; } if (s->size == 1) { element_t c = s->head->content; node_t* old = s->head; s->head = NULL; s->size = 0; s->tail = NULL; free(old); return c; } else { element_t c = s->tail->content; node_t* old = s->tail; s->tail = s->tail->previous; s->tail->next = NULL; s->size--; free(old); return c; }; }; void display(queue_t* s) { queue_t* c = s; int i = c->size; while (i > 0) { const char* elem = dequeue(c).value; printf("Item n°%d : %s\n",i,elem); i--; }; };
测试文件 test.c
#include <stdio.h> #include <stdbool.h> #include <stdlib.h> #include "queue.h" int main(void) { element_t e1 = {.type = false, .value = "1"}; element_t e2 = {.type = false, .value = "5"}; element_t e3 = {.type = false, .value = "10"}; queue_t* test = init_queue(); queue(test,e1); queue(test,e2); queue(test,e3); display(test); element_t e4 = dequeue(test); printf("%s\n",e4.value); element_t e5 = dequeue(test); printf("%s\n",e5.value); element_t e6 = dequeue(test); printf("%s\n",e6.value); element_t e7 = dequeue(test); printf("%s\n",e7.value); return 0; }
编译运行命令
gcc -g -std=c99 -Wall -o test.o -c test.c gcc -g -std=c99 -Wall -o queue.o -c queue.c gcc -g -std=c99 -Wall -o test queue.o test.o
解决方案
问题根源
queue_t* c = s;只是让指针c和s指向同一块内存地址,并没有复制队列的实际内容。所以调用dequeue(c)本质上还是操作原队列,自然会把原队列的元素删掉。
实现队列复制
要让两个队列完全独立,需要实现一个深拷贝函数,把原队列的每个节点都复制一份,创建新的队列结构。同时为了避免内存泄漏,还要实现队列销毁函数。
步骤1:添加函数声明
在queue.h中添加以下函数声明:
// 复制队列 queue_t* copy_queue(queue_t* s); // 销毁队列 void destroy_queue(queue_t* s);
步骤2:实现复制函数
在queue.c中实现copy_queue:
queue_t* copy_queue(queue_t* s) { if (s == NULL || s->size == 0) { return init_queue(); } queue_t* new_queue = init_queue(); node_t* current = s->head; // 遍历原队列的每个节点,逐个复制到新队列 while (current != NULL) { queue(new_queue, current->content); current = current->next; } return new_queue; }
步骤3:实现销毁函数
在queue.c中实现destroy_queue,避免内存泄漏:
void destroy_queue(queue_t* s) { if (s == NULL) { return; } // 逐个删除节点释放内存 while (s->size > 0) { dequeue(s); } // 释放队列本身的内存 free(s); }
步骤4:修改display函数
修改display函数,先复制原队列,对复制的队列进行展示操作,最后销毁复制的队列,这样原队列完全不受影响:
void display(queue_t* s) { queue_t* copy = copy_queue(s); int i = copy->size; while (i > 0) { const char* elem = dequeue(copy).value; printf("Item n°%d : %s\n", i, elem); i--; } // 销毁复制的队列,释放内存 destroy_queue(copy); }
测试验证
编译运行原测试代码,现在调用display(test)后,原队列的元素依然存在,后续调用dequeue能正常取出"10"、"5"、"1",最后输出"0"。
内容的提问来源于stack exchange,提问作者Elyo
相关产品推荐
相关产品推荐

