C语言uthash添加整型数组为哈希键时触发段错误的问题咨询
问题根因
你的段错误和用int数组作为键本身无关,核心是uthash的用法存在错误,同时有会触发随机崩溃的隐患:
- 最常见的崩溃诱因:
HASH_ADD系列宏不会主动校验键是否重复,如果你插入两个键完全一致的节点,会直接破坏哈希表内部的双向链表结构,后续任意哈希操作都可能触发段错误,很多人调试时会误将崩溃位置定位到相邻的代码行。 - 用法不规范问题:uthash所有操作宏的第二个参数必须是固定的哈希表头指针,该指针初始值必须为NULL,uthash会在插入第一个节点、删除最后一个节点时自动修改它的值,不要手动给这个指针赋值非节点地址,所有增删查操作都要传入这个头指针。
- 补充:固定长度数组作为键的写法本身合法,uthash默认会用
memcmp做键比较、内置字节哈希函数计算哈希值,不需要额外自定义哈希/比较逻辑,传入sizeof(int)*26作为键长的写法是正确的。
修正后的可运行代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "uthash.h" struct record { int key[26]; UT_hash_handle hh; }; int main() { // hash_head是固定的哈希表头指针,初始必须为NULL struct record *hash_head = NULL, *tmp = NULL, *res = NULL; struct record find; // 添加第一条记录 tmp = (struct record *)malloc(sizeof(struct record)); memset(tmp, 0, sizeof(struct record)); tmp->key[0] = 2; tmp->key[3] = 3; tmp->key[7] = 7; // 插入前先查重,避免破坏表结构 HASH_FIND(hh, hash_head, tmp->key, sizeof(int)*26, res); if (res == NULL) { HASH_ADD(hh, hash_head, key, sizeof(int)*26, tmp); } else { free(tmp); // 键重复时释放新建节点,避免内存泄漏 } // 添加第二条记录 tmp = (struct record *)malloc(sizeof(struct record)); memset(tmp, 0, sizeof(struct record)); tmp->key[0] = 2; tmp->key[3] = 3; tmp->key[7] = 8; HASH_FIND(hh, hash_head, tmp->key, sizeof(int)*26, res); if (res == NULL) { HASH_ADD(hh, hash_head, key, sizeof(int)*26, tmp); } else { free(tmp); } // 查找记录 memset(&find, 0, sizeof(struct record)); find.key[0] = 2; find.key[3] = 3; find.key[7] = 7; HASH_FIND(hh, hash_head, find.key, sizeof(int)*26, res); if (res) { printf("found, key[7] = %d\n", res->key[7]); } else { printf("Not found\n"); } // 用完释放所有节点,避免内存泄漏 struct record *cur, *next; HASH_ITER(hh, hash_head, cur, next) { HASH_DEL(hash_head, cur); free(cur); } return 0; }
uthash使用注意点
- 不同键类型优先用对应宏减少出错:键为int类型用
HASH_ADD_INT,键为'\0'结尾的字符串用HASH_ADD_STR,这两个不需要手动传入键长;只有固定长度结构体、数组等二进制块作为键时,才用通用HASH_ADD,必须准确传入键的字节长度。 - 新节点malloc后必须将整个内存块清零,保证
UT_hash_handle成员初始值全为0,否则插入时会因为内部脏值触发崩溃。 - 不要手动修改已加入哈希表节点的
UT_hash_handle成员,不要不经过HASH_DEL就直接释放表中节点,否则会破坏表结构。
内容的提问来源于stack exchange,提问作者sachu
相关产品推荐
相关产品推荐

