C dictionary 参数如何正确使用?

99ANYc3cd6
预计阅读时长 25 分钟
位置: 首页 参数 正文

C 语言本身没有内置的字典或哈希表这种数据结构,像 Python、JavaScript 等高级语言中的字典是语言内置的,但 C 语言的核心语言只提供了基本的数据类型(如 int, char, float)和几种复合数据类型(如数组、结构体、联合体)。

c dictionary 参数
(图片来源网络,侵删)

在 C 语言中实现“字典”,我们通常需要借助第三方库或者自己动手实现,最常用、最标准的第三方库就是 uthash

下面,我将围绕 uthash 这个库来详细解释如何使用它,特别是如何处理字典的“参数”(即键值对)。


为什么需要字典?字典的核心概念

字典是一种键值对集合,它允许你通过一个唯一的“键”来快速查找、添加、删除和修改一个“值”,这个查找操作的平均时间复杂度是 O(1),非常高效。

  • :通常是唯一的、不可变的值,用于标识数据,可以是字符串、整数等。
  • :与键关联的数据,可以是任意类型,如整数、字符串、结构体,甚至是指向复杂对象的指针。

生活中的例子

c dictionary 参数
(图片来源网络,侵删)
  • 字典:单词是“键”,解释是“值”。
  • 电话簿:姓名是“键”,电话号码是“值”。
  • 学生档案:学号是“键”,学生信息(姓名、班级等)是“值”。

uthash 库简介

uthash 是一个轻量级的、单文件的 C 语言哈希表库,它的优点是:

  • 极其简单:只需要将 uthash.h 这个头文件包含到你的项目中即可,无需复杂的安装或编译步骤。
  • 功能强大:支持添加、查找、删除、替换、排序等常用操作。
  • 性能优异:实现了高效的哈希算法。

如何使用 uthash

  1. 官网 下载 uthash.h 文件。
  2. uthash.h 放在你的项目目录下。
  3. 在你的 C 源文件中包含它:#include "uthash.h"

使用 uthash 创建和操作字典(核心内容)

uthash 的核心思想是将哈希表的功能“注入”到一个普通的 C 结构体中,这个结构体代表字典中的一个条目。

1 定义字典条目结构体

你需要定义一个结构体来表示一个键值对,这个结构体必须:

c dictionary 参数
(图片来源网络,侵删)
  1. 包含你的“键”和“值”字段。
  2. 包含一个 UT_hash_handle 类型的字段(这个字段由 uthash 内部使用,你不需要关心它的具体内容)。

示例 1:字符串键,整数值

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "uthash.h" // 包含 uthash 库
// 定义字典条目的结构体
struct my_dict {
    char *key;              // 键:字符串
    int value;               // 值:整数
    UT_hash_handle hh;      // uthash 需要的句柄
};
// 创建一个全局的哈希表指针,用于管理所有条目
struct my_dict *users = NULL;

示例 2:整数键,结构体指针值

#include "uthash.h"
// 定义值的结构体
struct user_info {
    char name[50];
    int age;
};
// 定义字典条目的结构体
struct int_dict {
    int id;                 // 键:整数
    struct user_info *info; // 值:指向结构体的指针
    UT_hash_handle hh;
};
struct int_dict *user_db = NULL;

2 字典操作函数(增删改查)

uthash 提供了一系列宏来操作哈希表,我们以 struct my_dict 为例。

添加或更新条目

使用 HASH_ADD_KEYPTR 宏,如果键已存在,它会更新对应的值;如果不存在,它会添加一个新条目。

void add_user(const char *key, int value) {
    struct my_dict *s;
    // 1. 检查键是否已存在
    HASH_FIND_STR(users, key, s); // 在 users 表中查找 key,找到后指针存入 s
    if (s == NULL) {
        // 2. 如果不存在,则创建一个新条目
        s = (struct my_dict *)malloc(sizeof(struct my_dict));
        s->key = strdup(key); // 复制字符串,因为原始 key 可能是临时变量
        s->value = value;
        HASH_ADD_KEYPTR(hh, users, s->key, strlen(s->key), s);
        printf("Added: %s -> %d\n", key, value);
    } else {
        // 3. 如果存在,则更新值
        s->value = value;
        printf("Updated: %s -> %d\n", key, value);
    }
}
  • HASH_FIND_STR(users, key, s):在 users 表中查找字符串类型的 key,如果找到,s 指向该条目;否则 sNULL
  • HASH_ADD_KEYPTR(hh, users, s->key, strlen(s->key), s)
    • hhUT_hash_handle 字段的名字。
    • users:哈希表指针。
    • s->key:要添加的键的指针。
    • strlen(s->key):键的长度。
    • s:要添加的结构体指针。

查找条目

使用 HASH_FIND_STR 宏。

struct my_dict *find_user(const char *key) {
    struct my_dict *s;
    HASH_FIND_STR(users, key, s); // 查找逻辑与上面相同
    return s; // 返回找到的条目指针,如果没找到则为 NULL
}

删除条目

使用 HASH_DEL 宏。注意:删除后需要手动释放内存!

void delete_user(const char *key) {
    struct my_dict *s = find_user(key); // 先找到
    if (s != NULL) {
        HASH_DEL(users, s); // 从哈希表中移除
        free(s->key);       // 释放键的内存
        free(s);            // 释放结构体本身的内存
        printf("Deleted: %s\n", key);
    }
}

遍历所有条目

使用 HASH_ITER 宏。

void print_all_users() {
    struct my_dict *s, *tmp;
    HASH_ITER(hh, users, s, tmp) {
        // s 是当前条目
        // tmp 是下一个条目的备份,用于安全地删除当前条目
        printf("Key: %s, Value: %d\n", s->key, s->value);
    }
}

清空整个字典

void free_all_users() {
    struct my_dict *current_user, *tmp;
    HASH_ITER(hh, users, current_user, tmp) {
        HASH_DEL(users, current_user);  // 先从表中移除
        free(current_user->key);       // 再释放内存
        free(current_user);
    }
}

完整示例代码

下面是一个完整的、可运行的示例,展示了上述所有操作。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "uthash.h"
// 1. 定义字典条目结构体
struct my_dict {
    char *key;
    int value;
    UT_hash_handle hh;
};
// 全局哈希表指针
struct my_dict *users = NULL;
// 2. 定义操作函数
void add_user(const char *key, int value) {
    struct my_dict *s;
    HASH_FIND_STR(users, key, s);
    if (s == NULL) {
        s = (struct my_dict *)malloc(sizeof(struct my_dict));
        s->key = strdup(key);
        s->value = value;
        HASH_ADD_KEYPTR(hh, users, s->key, strlen(s->key), s);
        printf("Added: %s -> %d\n", key, value);
    } else {
        s->value = value;
        printf("Updated: %s -> %d\n", key, value);
    }
}
struct my_dict *find_user(const char *key) {
    struct my_dict *s;
    HASH_FIND_STR(users, key, s);
    return s;
}
void delete_user(const char *key) {
    struct my_dict *s = find_user(key);
    if (s != NULL) {
        HASH_DEL(users, s);
        free(s->key);
        free(s);
        printf("Deleted: %s\n", key);
    }
}
void print_all_users() {
    struct my_dict *s, *tmp;
    printf("--- All Users ---\n");
    HASH_ITER(hh, users, s, tmp) {
        printf("Key: %s, Value: %d\n", s->key, s->value);
    }
    printf("-----------------\n");
}
void free_all_users() {
    struct my_dict *current_user, *tmp;
    HASH_ITER(hh, users, current_user, tmp) {
        HASH_DEL(users, current_user);
        free(current_user->key);
        free(current_user);
    }
}
// 3. 主函数
int main() {
    // 添加/更新
    add_user("Alice", 25);
    add_user("Bob", 30);
    add_user("Charlie", 35);
    print_all_users();
    // 更新
    add_user("Alice", 26);
    print_all_users();
    // 查找
    struct my_dict *found = find_user("Bob");
    if (found) {
        printf("Found Bob, his age is: %d\n", found->value);
    } else {
        printf("Bob not found.\n");
    }
    // 删除
    delete_user("Charlie");
    print_all_users();
    // 查找不存在的键
    struct my_dict *not_found = find_user("David");
    if (!not_found) {
        printf("David not found, as expected.\n");
    }
    // 清空内存
    free_all_users();
    // 验证是否已清空
    print_all_users(); // 应该没有任何输出
    return 0;
}
操作 uthash 关键点
定义 struct my_dict { ... UT_hash_handle hh; }; 必须包含 UT_hash_handle 字段
添加/更新 HASH_ADD_KEYPTR(hh, table, key_ptr, key_len, item_ptr) 如果键存在则更新,否则添加
查找 HASH_FIND_STR(table, key_ptr, item_ptr_out) 根据键查找,结果通过指针返回
删除 HASH_DEL(table, item_ptr) 删除后必须手动 free() 内存
遍历 HASH_ITER(hh, table, current_item, tmp_item) 使用临时指针 tmp 保证安全遍历
清空 HASH_ITER 循环内调用 HASH_DELfree() 遍历并释放每个条目的内存

通过 uthash,你就可以在 C 语言中轻松、高效地使用字典数据结构来管理参数和键值对数据。

-- 展开阅读全文 --
头像
便宜的OPPO智能手机性价比如何?
« 上一篇 今天
TensorFlow如何实现参数共享?
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

最近发表

标签列表

目录[+]