C语言通用队列实现:能否脱离外部地址存储任意数据类型对象?
泛型队列独立持有任意类型数据的实现方案
你当前实现的泛型队列存在的核心问题是:节点仅存储了外部传入的指针地址,没有对指针指向的数据做独立拷贝。一旦外部对应内存的内容被修改、或者内存被回收,队列中存储的引用就会失效,无法满足队列自管理数据的设计目标。
C语言是静态类型语言,运行时无法自动识别传入数据的类型和大小,要实现队列内部存储数据实体本身,只需要在队列操作接口中显式传入待存储数据的字节长度,队列内部就可以根据长度申请对应大小的堆内存,把外部传入的数据完整拷贝到队列自有的内存空间,彻底和外部内存解耦。
结构与接口调整
- 队列节点新增两个字段:一个指向队列自有存储内存的
void*指针,一个记录当前存储数据长度的size_t变量,方便后续内存管理 - 修改
enqueue接口入参,新增待存储数据的字节长度参数,替代原来仅接收外部指针的设计 - 入队流程中,单独为每个节点的存储内容申请对应长度的堆内存,通过
memcpy完成数据的独立拷贝
调整后的完整可运行代码
#include <stdlib.h> #include <string.h> typedef struct Node { void *data_storage; // 队列专属的数据存储内存 size_t data_size; // 记录存储数据的字节长度,用于内存管理 struct Node *next; } Node; typedef struct Queue { Node *front; Node *back; } Queue; Queue* initializeQueue() { Queue *queue = (Queue*)malloc(sizeof(Queue)); // 增加内存申请失败的边界判断 if (queue == NULL) return NULL; queue->front = NULL; queue->back = NULL; return queue; } void enqueue(Queue *queue, const void *data, size_t data_size) { // 边界参数校验 if (queue == NULL || data == NULL || data_size == 0) return; // 申请新节点内存 Node *new_node = (Node*)malloc(sizeof(Node)); if (new_node == NULL) return; // 为节点申请和待存数据等长的专属存储内存 new_node->data_storage = malloc(data_size); if (new_node->data_storage == NULL) { free(new_node); return; } // 把外部传入的数据完整拷贝到队列自有内存,和外部内存脱钩 memcpy(new_node->data_storage, data, data_size); new_node->data_size = data_size; new_node->next = NULL; // 原有入队逻辑保持不变 if (queue->front == NULL) { queue->front = new_node; queue->back = new_node; } else { queue->back->next = new_node; queue->back = new_node; } }
效果验证
使用之前提到的char变量入队的场景,调用方式调整为:
char key = '-'; // 显式告知队列当前数据的长度为char类型的字节大小 enqueue(queue, &key, sizeof(char));
入队完成后,无论外部的key变量是被修改值、还是离开作用域被回收,队列内部存储的都是独立拷贝的完整数据,不会出现悬空引用问题。这套方案同样兼容int、结构体、字符串等任意数据类型的存储。
配套注意事项
- 实现出队和队列销毁逻辑时,需要先释放每个节点对应的
data_storage内存,再释放节点本身,避免内存泄漏 - 入队时会对传入数据做一次完整的字节拷贝,如果存储的是体积较大的结构体,需要根据实际场景权衡拷贝开销
内容的提问来源于stack exchange,提问作者Luiz。
相关产品推荐
相关产品推荐

