C语言中double与复杂类型的泛型实现问题求助
你遇到的问题本质是栈变量的地址在循环中被复用——每次循环里的double x都在栈上的同一个位置,所以你存在数组里的所有&x都是同一个指针,最后自然只会输出循环最后一次的x值。
下面是几个可行的解决方法,按通用性和可靠性排序:
方案1:堆分配独立存储(通用且可靠)
既然栈变量地址会复用,那就给每个元素在堆上分配独立内存,把值存进去,再将堆指针存入数组。同时需要给你的数组库加一个销毁回调函数,让自动释放逻辑能正确释放这些堆内存。
修改数组库的关键部分
首先扩展array结构体,增加销毁回调:
#include <stdlib.h> // 销毁回调的类型定义 typedef void (*array_dtor_t)(void* elem); typedef struct { void** elements; usize length; usize capacity; array_dtor_t destructor; // 新增:元素销毁函数 } array; // 修改create函数,接受销毁回调参数 array create(usize init_size, array_dtor_t dtor) { array a = {0}; a.capacity = init_size > 0 ? init_size : 4; a.elements = malloc(a.capacity * sizeof(void*)); a.destructor = dtor; return a; } // 在自动释放的构造函数中,遍历元素调用销毁回调 __attribute__((constructor)) static void auto_free_arrays() { // 假设你用全局链表管理所有创建的array for (array* curr = global_array_list; curr; curr = curr->next) { if (curr->destructor) { for (usize i = 0; i < curr->length; i++) { curr->destructor(curr->elements[i]); } } free(curr->elements); free(curr); } }
修改double类型的使用代码
#include "kstring.h" #include "array.h" // 针对double类型的销毁函数 void destroy_double_elem(void* elem) { free(elem); } int main(int argc, const string* argv) { array a = create(0, destroy_double_elem); for (usize i = 1; i < argc; i++) { double x = parse(argv[i]); // 分配堆内存存储double值 double* elem_ptr = malloc(sizeof(double)); *elem_ptr = x; append(&a, (type)elem_ptr); } for (usize i = 0; i < a.length; i++) print("%lf\n", *((double*)(a.elements[i]))); }
这样每个元素都有独立的堆地址,不会被循环覆盖,自动释放时也能正确回收内存。
方案2:用Union统一存储基本类型(减少堆开销)
如果你的数组主要存储基本类型(int、double、指针等),可以用union实现值和指针的统一存储,避免堆分配。这种方案的前提是类型大小不超过void*的宽度(64位系统下是8字节,刚好覆盖大部分基本类型)。
修改数组库的关键部分
typedef union { void* ptr; // 存指针类型(比如字符串) int i; // 存int double d; // 存double usize u; // 存无符号整数 char raw[sizeof(void*)]; // 存不超过指针大小的小结构体 } array_elem_t; typedef struct { array_elem_t* elements; usize length; usize capacity; // 同样可以加销毁回调,处理需要堆释放的指针类型 void (*destructor)(array_elem_t elem); } array; // create函数调整为返回这种结构 array create(usize init_size, void (*dtor)(array_elem_t)) { array a = {0}; a.capacity = init_size > 0 ? init_size : 4; a.elements = malloc(a.capacity * sizeof(array_elem_t)); a.destructor = dtor; return a; }
修改double类型的使用代码
#include "kstring.h" #include "array.h" int main(int argc, const string* argv) { array a = create(0, NULL); // 基本类型不需要销毁回调 for (usize i = 1; i < argc; i++) { double x = parse(argv[i]); array_elem_t elem; elem.d = x; append(&a, elem); // append函数需要调整为接受array_elem_t } for (usize i = 0; i < a.length; i++) print("%lf\n", a.elements[i].d); }
这个方案对基本类型更高效,不需要堆分配,但如果要存超过指针大小的结构体,还是得回到方案1,用堆指针存在ptr字段并配合销毁回调。
方案3:强制值转void*(移植性差,不推荐通用场景)
如果你的目标平台上,double的大小等于void*的大小(比如64位系统),可以用memcpy直接把值复制到void*变量中,避免指针:
#include "kstring.h" #include "array.h" int main(int argc, const string* argv) { array a = create(0); for (usize i = 1; i < argc; i++) { double x = parse(argv[i]); void* elem; memcpy(&elem, &x, sizeof(elem)); append(&a, elem); } for (usize i = 0; i < a.length; i++) { double x; memcpy(&x, &a.elements[i], sizeof(x)); print("%lf\n", x); } }
这种方法完全依赖平台的类型大小匹配,移植性很差,只适合特定场景临时用,不适合作为通用库的方案。
内容的提问来源于stack exchange,提问作者KianFakheriAghdam
相关产品推荐
相关产品推荐

