2017-08-20 53 views
0

我有我自己的執行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

回答

0

是,上面的代碼導致該指針將只是一次初始化(或者,如果將它們設置爲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

因爲這似乎是一個圖書館,你有幾種選擇:

  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。

相關問題