HOWTO · C
在 C 语言中实现字典
本文介绍了如何在 C 语言中实现字典。
本页内容
ISO C 没有内置的字典类型。如果目标环境提供 POSIX hsearch 接口,就可以使用其中的哈希表例程存储和检索键值条目。下面的示例会创建一张表、插入两个条目、查找一个已存在的键和一个不存在的键、检查返回的指针,并释放该表。这只是实现字典的一种方式,并不涵盖所有可能的设计。
使用 POSIX hsearch 例程在 C 中实现字典
hcreate、hsearch 和 hdestroy 是在 <search.h> 中声明的 POSIX 例程,不属于 ISO C 标准库。它们是否可用取决于目标操作系统和 C 库,因此在使用示例之前,请先确认你的环境提供此接口。hcreate 和 hsearch 的 POSIX 规范定义了该接口,可用于查阅相关要求。此处没有提供具体的平台或库版本信息。
使用 hcreate 和 hsearch 创建哈希表并添加条目
调用一次 hcreate,即可按指定容量创建哈希表。创建成功时,它返回非零值;无法创建表时返回零。ENTRY 包含一个 char * 类型的键和一个 void * 类型的数据指针。向 hsearch 传入一个 ENTRY 和一个 ACTION 值:ENTER 表示插入,FIND 表示查找。调用成功时会返回指向条目的指针;失败时则返回 NULL。
运行以下示例:
本节中的代码以及显示的标签或输出仍为英文。
#define _XOPEN_SOURCE 700
#include <search.h>
#include <stdio.h>
int main(void) {
if (hcreate(4) == 0) {
fputs("could not create table\n", stderr);
return 1;
}
ENTRY item = {"language", "C"};
if (hsearch(item, ENTER) == NULL) {
fputs("could not insert language\n", stderr);
hdestroy();
return 1;
}
item.key = "standard";
item.data = "POSIX";
if (hsearch(item, ENTER) == NULL) {
fputs("could not insert standard\n", stderr);
hdestroy();
return 1;
}
ENTRY query = {"language", NULL};
ENTRY *found = hsearch(query, FIND);
if (found == NULL) {
puts("language: not found");
} else {
printf("language: %s\n", (char *)found->data);
}
query.key = "compiler";
found = hsearch(query, FIND);
if (found == NULL) {
puts("compiler: not found");
} else {
printf("compiler: %s\n", (char *)found->data);
}
hdestroy();
return 0;
}
language: C
compiler: not found
输出块中的 compiler: not found 是保留原样的英文提示,意思是“未找到编译器”。
查找键并处理缺失条目
第一次 FIND 调用查找程序已插入且值为 C 的 language;第二次查找程序未插入的 compiler。程序在读取 data 前会检查每个结果,因此结果为 NULL 时会安全地进入“未找到”分支。如果本应存在的键查找结果为 NULL,示例也会避免解引用该指针,并报告查找结果。你可以根据应用需求调整提示消息或返回策略。
插入无法完成时,hsearch 也会返回 NULL,因此应在继续执行前检查每次 ENTER 调用的结果。示例通过向 stderr 写入诊断信息、释放已创建的表并返回失败状态,来处理创建和插入失败。应在每项操作后立即进行这些检查,确保后续代码只有在确认指针有效后才读取条目。
释放哈希表并了解其限制
不再需要哈希表时,调用 hdestroy。它会释放哈希表,但调用者仍需负责条目所引用的动态分配键或值存储;请保留这些指针,并单独释放自己拥有的内存。示例使用的是字符串字面量,因此没有这类内存需要释放。这里展示的 POSIX 接口不提供删除单个条目的操作。创建表时应选择足够的容量:请求的容量会传给 hcreate,而此处展示的接口流程没有提供调整表大小的操作。