You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言实现字符串为键、函数为值的字典,用于Allegro游戏开发

实现方案建议

1. 基础哈希表结构设计

针对你需要的「字符串为键、函数指针为值」的映射需求,可采用链地址法解决哈希冲突的哈希表实现,结构定义参考如下:

// 可根据你的游戏回调签名调整通用函数指针定义
typedef void (*GameAction)(void* args);

// 哈希节点:存储单组键值对
typedef struct HashNode {
    char* key;          // 字符串键,可存动作名、皮肤ID等
    GameAction value;   // 对应执行的函数指针
    struct HashNode* next; // 链表处理哈希冲突
} HashNode;

// 哈希表主体
typedef struct HashTable {
    int bucket_count;   // 总桶数,建议取大于预计键数量1.5倍的质数
    HashNode** buckets; // 桶数组
} HashTable;

该实现逻辑简单,对游戏场景的性能需求完全足够,你熟悉动态内存管理的话可以快速完成开发。

2. 核心哈希函数实现

游戏场景不需要加密级哈希,推荐用性能高、短字符串碰撞率低的DJB2哈希:

unsigned int hash(const char* key, int bucket_count) {
    unsigned long hash_val = 5381;
    int c;
    while ((c = *key++))
        hash_val = ((hash_val << 5) + hash_val) + c; // 等价于 hash_val *33 +c
    return hash_val % bucket_count;
}

3. 核心操作接口实现

哈希表初始化

HashTable* hash_table_create(int bucket_count) {
    HashTable* table = malloc(sizeof(HashTable));
    table->bucket_count = bucket_count;
    table->buckets = calloc(bucket_count, sizeof(HashNode*));
    return table;
}

键值对插入/覆盖

void hash_table_put(HashTable* table, const char* key, GameAction action) {
    unsigned int idx = hash(key, table->bucket_count);
    // 先查找已存在的键,存在则直接覆盖值(适配皮肤切换逻辑)
    HashNode* cur = table->buckets[idx];
    while (cur) {
        if (strcmp(cur->key, key) == 0) {
            cur->value = action;
            return;
        }
        cur = cur->next;
    }
    // 不存在则新建节点头插
    HashNode* new_node = malloc(sizeof(HashNode));
    new_node->key = strdup(key);
    new_node->value = action;
    new_node->next = table->buckets[idx];
    table->buckets[idx] = new_node;
}

这里的覆盖逻辑正好适配你的皮肤需求:同一个动作键比如"player_jump",换皮肤时直接插入新的跳跃动画函数即可自动覆盖旧逻辑,不需要修改任何调用代码。

函数查询调用

void hash_table_invoke(HashTable* table, const char* key, void* args) {
    unsigned int idx = hash(key, table->bucket_count);
    HashNode* cur = table->buckets[idx];
    while (cur) {
        if (strcmp(cur->key, key) == 0) {
            cur->value(args); // 直接执行对应函数
            return;
        }
        cur = cur->next;
    }
    // 可选添加找不到键的默认处理,比如日志打印、执行兜底动作
}

4. 游戏场景使用示例

原来的多层if判断逻辑:

if (strcmp(action_name, "jump") == 0) {
    default_jump(args);
} else if (strcmp(action_name, "attack") == 0) {
    default_attack(args);
} // ... 更多动作判断

改造后:

// 初始化阶段注册所有默认动作
hash_table_put(action_map, "jump", default_jump);
hash_table_put(action_map, "attack", default_attack);
hash_table_put(action_map, "walk", default_walk);

// 执行动作时一行代码搞定,无任何if判断
hash_table_invoke(action_map, action_name, args);

// 切换皮肤时直接覆盖对应动作即可
hash_table_put(action_map, "jump", skin2_jump);
hash_table_put(action_map, "attack", skin2_attack);

调用逻辑完全不需要调整,适配性极强。

5. 优化建议

  • 如果你的动作总数少于30个,甚至可以不用哈希表,直接做{键, 函数指针}的结构体数组,遍历查询即可,实现更简单,性能也完全满足小游戏需求
  • 函数指针的签名可以根据实际需求调整,比如添加返回值、改为Allegro事件/位图参数都可以,只需要修改GameAction的定义
  • 可增加懒加载逻辑,皮肤对应的动作函数仅在第一次使用时注册,降低启动内存占用

内容的提问来源于stack exchange,提问作者Gabriel Lüders

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 23:36:04