C按值查找字符串

时间:2015-05-21 05:04:21

标签: c

我需要将值转换为人类可读的字符串。通常对于 I 定义的东西,我会使用从零开始的值,并创建一个简单的字符串数组,其值为索引。

static const char *foo[] = { "foo", "bar", "etc" };
if (val < 3) printf("%s\n", foo[val]);

对于这种情况,我的值不是从0开始,它们之间存在一些差距。有没有一个很好的方法来做到这一点,而不必手动编码索引的一堆空字符串没有匹配的值/字符串对?

static const char *foo[] = { "", "", "", "foo", "", "bar", "", "", "etc" };

4 个答案:

答案 0 :(得分:7)

从C99开始,您可以使用designated initialisers

static const char *foo[] = { 
   [3] = "foo", 
   [5] = "bar",
   [8] = "etc"
};

这相当于您发布的数组定义,并将生成包含9个条目的数组。结构体的初始化有类似的语法:

struct Person joe = {
    .name = "Joe", .age = 24, .favcolor = "mauve"
};

请注意,这只是一个C功能和will not work in C++

答案 1 :(得分:3)

如果没有太多间隙,您可以将每个连续序列编码为单独的数组,然后进行一些边界检查以找到要使用的合适序列。这是一个快速而肮脏的例子:

#include <stdio.h>
#include <stdlib.h>

static const int array_first_indices[] = {3, 15, 28, 32};
static const char * array0[] = {"foo"};
static const char * array1[] = {"bar", "baz"};
static const char * array2[] = {"bloop", "blorp", "blat"};
static const char * array3[] = {"glop", "slop", "bop"};

#define check_array(whichArray, idx) { \
   unsigned int relIdx = idx - array_first_indices[whichArray]; \
   if (relIdx < (sizeof(array##whichArray)/sizeof(const char *))) \
      return array##whichArray[relIdx]; \
   }

const char * LookupWord(int idx)
{
   check_array(0, idx);
   check_array(1, idx);
   check_array(2, idx);
   check_array(3, idx);
   return NULL;
}

int main(int args, char ** argv)
{
   for (int i=0; i<50; i++) printf("   LookupWord(%i) = %s\n", i, LookupWord(i));
   return 0;
}

对于完全通用的查找机制,您可能需要使用像哈希表或树这样的数据结构;这些数据结构的C实现是可用的,但如果您可以选择使用C ++,那么使用该语言的数据结构会更容易,因为它们是由标准库提供的。

答案 2 :(得分:1)

创建一个将ID映射到字符串的排序数组,并使用bsearch()函数查找字符串:

#include <stdio.h>
#include <stdlib.h>

struct id_msg_map {
    int id;
    char const* str;
};


int comp_id_string( const void* key, const void* element)
{
    int key_id     = ((struct id_msg_map*) key)->id;
    int element_id = ((struct id_msg_map*) element)->id;

    if (key_id < element_id) return -1;
    if (key_id > element_id) return  1;
    return 0;
}

static struct id_msg_map msg_map[] = {
    {3, "message 3"} ,
    {12, "message 12"},
    {100, "message 100"},
    {32000, "message 32000"},
};

#define ELEMENTS_OF(x) (sizeof(x) / sizeof((x)[0]))
char const* get_msg(int x)
{
    struct id_msg_map key = {x};
    struct id_msg_map* msg = bsearch(&key, msg_map, ELEMENTS_OF(msg_map), sizeof(msg_map[0]), comp_id_string);

    if (!msg) return "invalid msg id";

    return msg->str;
}

void test_msg(int x)
{
    printf("The message for ID %d: \"%s\"\n", x, get_msg(x));
}

int main(void)
{
    test_msg(0);
    test_msg(3);
    test_msg(100);
    test_msg(-12);
    return 0;
}

答案 3 :(得分:0)

可以使用指定的初始化工具,如M. Oehm's post中所述,但是这会默默地引入您之前提到的相同差距(隐式0值)。当您知道0永远不会是实际选择,表格没有动态变化(特别是大小)以及表格的大小很小时,该选项最合适。

如果表格特别大,但从未添加或删除项目,则可以在键/值对样式结构上使用qsortbsearch。例如:

struct foo_pair {
     int key;
     char *value;
};

int foo_pair_compare(void *x, void *y) {
    struct foo_pair *a = x, *b = y;
    return (a->key > b->key) - (a->key < b->key);
}

int main(void) {
    struct foo_pair foo[] = { { .key = 3, .value = "foo" },
                              { .key = 5, .value = "bar" },
                              { .key = 6, .value = "etc" } };

    /* qsort needs to be done at the start of the program,
       and again each time foo changes */
    qsort(foo, sizeof foo / sizeof *foo, sizeof *foo, foo_pair_compare);

    /* bsearch is used to retrieve an item from the sorted array */
    struct foo_pair *selection = bsearch(&(struct foo_pair) { .key = 5 },
                                         foo, sizeof foo / sizeof *foo,
                                         sizeof *foo, foo_pair_compare);
}

当从集合中例行添加或删除项目时,选择哈希表或某种有序映射会更有意义。如果你不能在编写和测试你自己的这些系列时感到困扰,我想有很多尝试过的&amp;您可以在互联网上测试图书馆。