C语言如何调整哈希表大小?柔性数组成员赋值不生效问题
问题核心原因
你遇到的所有问题都源于对**C语言柔性数组成员(Flexible Array Member)**的特性理解有误:
- 柔性数组是结构体末尾的特殊数组成员,
sizeof(struct table)计算时不会包含它的存储空间,它的内存直接跟在结构体分配的内存块之后,不是独立的指针变量。 - 你不能对柔性数组成员直接赋值,它本身没有独立的存储空间存储地址,访问时的地址由结构体基地址直接偏移得到,是固定的,这就是
table->array = new_table->array报错invalid use of flexible array member的直接原因。
为什么*table = *new_table后size正常、array内容不对
结构体赋值*a = *b只会复制sizeof(结构体类型)大小的内存:
- 你的
sizeof(struct table)只包含int size的4字节(32位环境)或8字节(64位环境),所以赋值时只会把new_table的size成员复制到旧table里,柔性数组的内容完全不会被复制。 - 另外你原来的
create_table实现本身就是错的:你只给结构体分配了sizeof(struct table)的空间,完全没有预留柔性数组的存储空间,你访问array[i]本质是越界访问内存,new_table能正常访问完全是未定义行为下的巧合。
修复方案
方案1:把柔性数组改成指针(更适合哈希表resize场景)
柔性数组不能修改指向,不适合需要频繁更换数组大小的场景,直接把array改成二级指针即可:
struct table { int size; key_value **array; // 改成指针,不是数组 }; struct table *create_table(int size) { struct table *table = malloc(sizeof(struct table)); table->size = size; // 单独给指针数组分配空间 table->array = calloc(size, sizeof(key_value*)); return table; }
改完之后你既可以直接赋值*table = *new_table,也可以单独修改table->array指针。注意使用时要先释放旧array的内存避免泄漏,new_table本身的结构体空间用完也要释放。
方案2:坚持用柔性数组的正确写法
如果一定要用柔性数组,分配结构体空间时要把数组的内存一起算进去:
struct table *create_table(int size) { // 总大小 = 结构体本身大小 + size个key_value指针的大小 struct table *table = calloc(1, sizeof(struct table) + size * sizeof(key_value*)); table->size = size; return table; }
但这种场景下resize不能直接修改旧table的内容,需要调整resize函数的实现,返回新的table指针让调用方替换旧指针:
struct table* resize_table(struct table *old_table, int new_size) { struct table *new_table = create_table(new_size); // 你的原有元素迁移逻辑 for(int i = 0; i < old_table->size; i++) { key_value *p = old_table->array[i]->next; while(has_next(p)) { insert(new_table, p->key, p->value); p = p->next; } } free(old_table); // 释放旧表内存 return new_table; } // 调用时写法: // my_table = resize_table(my_table, 128);
内容的提问来源于stack exchange,提问作者Blue
相关产品推荐
相关产品推荐

