在C中使用HashMap来存储字符串 - 整数映射一次,并用于整个程序运行

问题描述:

我有我自己的执行C hash_map_t结构,我可以使用如下?在C中使用HashMap来存储字符串 - 整数映射一次,并用于整个程序运行

// string value allocator 

allocator_t *str_value_allocator; 
allocator_init(&str_value_allocator, string_allocate_handler, string_deallocate_handler); 
str_hash_map_init(&str_hash_map, str_value_allocator, 5); 

str_hash_map_put(str_hash_map, test_key, test_val, strlen(test_val)); 
str_hash_map_get(str_hash_map, test_key, NULL) 
str_hash_map_remove(str_hash_map, test_key) 

str_hash_map_free(str_hash_map); 

我想用此散列映射函数象下面这样:

void handle_keyboard_input(char **tokens, size_t num_tokens) { 

    char *virtual_key_name = strtok(tokens[1], " "); 
    size_t num_flags = 0; 
    char **modifier_flags = str_split(tokens[2], ", ", &num_flags); 

    // map virtual_key_name (char *) to virtual_key code (int) 
    // foreach modifier flag (char *) map to modifier flag code (int) 
} 

我能为KEY_NAME创建2个hash_maps - > key_code映射和flag_name - > flag_code映射。问题是我不希望每次调用请求处理程序函数时创建此标志,但只有一个数据结构实例从函数的第一次调用开始,并且在连续的函数调用中,我希望重新使用此数据结构(数据存储)已经创建。

我的hash_map是在堆上创建的,因此不可能像在库源代码文件内某处的数组那样分配它。

在Java甚至C++中,我可以创建一些单例模式或静态成员,但是这种概念在C语言中不可用。也许我可以在程序启动的某个地方在程序启动时创建这个hash_map,但我怎样才能传递对程序使用的库的引用。

我最近的想法是使用static hash_map_t variable inside my handle_keyboard_input function,并以某种方式初始化它只有当它是NULL(第一个函数调用),并且如果在连续调用中变量不是NULL,只是重用以前初始化的hash_map_t结构。

这个问题最好的解决方法是什么?

UPDATE

我可以用这样的代码?

static str_hash_map_t *virtual_keys_map = NULL; 
static str_hash_map_t *modifier_flags_map = NULL; 

if (virtual_keys_map == NULL) { 
    virtual_keys_map_init(&virtual_keys_map); 
} 

if (modifier_flags_map == NULL) { 
    modifier_flags_map_init(&modifier_flags_map); 
} 
+0

函数中的静态(指针)变量也是单例。或者,甚至更简单一个全局变量。 – wildplasser

+0

所以我可以像我的更新部分中使用这样的代码? –

+0

启动时分配这些结构有什么问题?在调用每个单独的函数之前,我没有意义检查NULL。如果您想自动执行此操作,dll库也可以公开init函数。 – Groo

是,上面的代码导致该指针将只是一次初始化(或者,如果将它们设置为NULL,条件会true,它会再次INIT),留在记忆即使你的函数外。

变量的使用期限从程序流第一次遇到声明开始,到程序结束时结束 - 换句话说,它们是全局变量。

此变量的名称只能在函数内访问,并且没有链接。

如果您认为您需要全局访问的变量,仍然需要非常小心。 Read here

static str_hash_map_t *virtual_keys_map = NULL; 
static str_hash_map_t *modifier_flags_map = NULL; 

if(virtual_keys_map == NULL) { 
    virtual_keys_map_init(&virtual_keys_map); 
} 
if(modifier_flags_map == NULL) { 
    modifier_flags_map_init(&modifier_flags_map); 
} 

因为这似乎是一个图书馆,你有几种选择:

  1. 你可以让你的库更“面向对象”和用户做正确的实例。例如,你有你的ADT struct definedKeyboardHandler,然后你handle_keyboard_input会是这个样子,而不是:

    void KH_handle_input(KeyboardHandler self, char **tokens, size_t num_tokens); 
    

    这意味着呼叫者现在是负责做这单件的实例:

    // caller must get the ADT instance at some point, and you don't care when 
    KeyboardHandler kh = KH_init(); 
    KH_handle_input(kh, some_tokens, num_tokens); 
    
    // some other part can be initialized later 
    MouseHandler mh = MH_init(); 
    MH_handle_input(mh, some_tokens, num_tokens); 
    
  2. 可以为both Windows and POSIX dll创建库初始值设定项。所以你可以让它自动完成。如果你的函数想要使用这个可能未初始化的哈希表(或许它是一个单一的函数,但无论如何),似乎你将不得不做出这个“检查”。在这种情况下,我至少会重构它到一个单独的功能:

    void handle_keyboard_input(char **tokens, size_t num_tokens) { 
        initialize_hashes_if_needed(); 
        // ...and then the rest of the function    
    } 
    

    的原因是你不希望有修改几个功能,如果你决定有别的东西,需要被malloced。