You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无引用复制队列结构体?解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 07:35:22