2011-03-04 60 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