2011-03-04 104 views
10

如果我有一組小字符串值,並且我想獲取一個數值來表示它們,那麼通過查找表執行此操作的最佳方法是什麼?C中字符串的值查找表?

如果我只需要做瞪了一眼,我知道最佳的解決方案將只是一系列的if語句:

if (strcmp(str, "foo") == 0) 
    tmp = FOO; 
else if (strcmp(str, "bar") == 0) 
    tmp = BAR; 

但是,我問這個是因爲這些小的字符串值表示的屬性在我用C編寫的一個小項目中,屬性可以是隻讀或讀寫(現在不寫,現在可能永遠不會寫)。

因此,我目前所做的只是確保工作是有一個查找功能,包括像上面這樣的if-then子句來查找哪些值是隻讀的,以及查找哪些值被讀取的第二個函數-寫。但是這對我來說很大很醜。

我在想,有三個功能。一個函數是查找函數,它返回一個int值,它是字符串的數字形式。但是這個查找函數也可以採用一個標誌來確定它是否獲取一個只讀值或一個讀寫值。如果寫操作是在真正只讀的值上完成的,則該函數將返回-EINVAL(或其他等價物)。

另外兩個函數,現在仍然是讀取和寫入,只是調用這個查找函數,傳遞一個值的字符串,以及確定它們是用於讀取還是寫入的標誌。我不知道這是如何在C中模擬的(如果可以模擬的話),並且搜索谷歌對所有內容農場來說都是一團糟(並且給我C++/C#的答案) 。

因此,這是如何,我認爲它會看起來:

int lookup_func(const char *name, const char *flag) { 
    int tmpval = 0; 

    /* code to do the lookup. */ 

    if (tmpval == 0) 
     return -EINVAL; 
    else 
     return tmpval; 
} 

int get_readonly_bit(const char *name) { 
    return lookup_func(name, "ro"); 
} 

int get_readwrite_bit(const char *name) { 
    return lookup_func(name, "rw") 
} 

的思考?我們的想法是通過不重複這兩個函數的if-then分支來減少代碼大小,這些函數在總體設計上略有不同,並且只是讓某種查找函數找出這個值服務的函數。

+0

+1爲常量,正確性... *但標誌是一個int(或枚舉)* – pmg

+0

你想要的[哈希函數(http://en.wikipedia.org/wiki/Hash_function更好)。取決於你的字符串值,它可能就像返回第一個字母的值一樣簡單...... – pmg

+0

@pmg:仍然有幾個字符串具有相同散列的概率。小,但它是:) –

回答

6

你不認爲只是放一張桌子嗎?如果有很多屬性,哈希表也很好。

int lookup(const char *name) 
{ 
    typedef struct item_t { const char *name; int writable; int value; } item_t; 
    item_t table[] = { 
    { "foo", 0, FOO }, 
    { "bar", 1, BAR }, 
    { NULL, 0, 0 } 
    }; 
    for (item_t *p = table; p->name != NULL; ++p) { 
     if (strcmp(p->name, prop_name) == 0) { 
      return p->value; 
     } 
    } 
    return -EINVAL; 
}
+0

很好的解決方案。如果你只關心「大而醜」的代碼,這應該做的,對吧?如果表格很長,並且你的程序做了很多查找,我會試着去處理這個for-loop:例如尋找適用於字符串的二進制搜索實現,並且當然是用c編寫的。 – AudioDroid

+1

@AudioDroid:它是什麼大而醜陋的?這很簡單,可以理解,而且很強大,我已經看到它在很多地方使用。該算法是O(n),這可能是長列表的問題。但是,這是否是一個問題應該通過性能分析來確定,而不是猜測。 – JeremyP

+0

我個人不鼓勵這種解決方案,除了微不足道的列表。以這種方式使用字符串時,區域設置和區分大小寫的問題可能會有問題。此外,效率值得懷疑。strcmp意味着當一個散列鍵的一個比較就足夠時,重複比較的序列。當比較哈希與strcmp的性能時,哈希方法表現出除了普通列表之外的更好性能(以我的經驗)。 – Throwback1986