идиоматический C для сопоставления строк типа int и const

Как я могу выразить на C карту, подобную этой?

{
{1, "One"},
{1000, "One thousand"},
{1000000, "One million"}
}

Ключ - это int и может быть большим int, значение - это постоянная строка, известная во время компиляции.

Карта будет содержать от 20 до 30 элементов.

Я бы написал такую ​​функцию:

const char* numbers( const int i ) 
{
   switch( i ) {
      case       1: return "One";
      case    1000: return "One thousand";
      case 1000000: return "One million";
      default: return "";
   }
}

есть ли лучший (более идиоматический) способ сделать это?


person Alessandro Jacopson    schedule 21.10.2011    source источник
comment
Вот для чего нужны хеш-таблицы. В C, в отличие от других языков более высокого уровня, язык не предоставляет таких возможностей, и вам придется придумывать свои собственные.   -  person Blagovest Buyukliev    schedule 21.10.2011
comment
@BlagovestBuyukliev: Хеширование целых чисел несколько необычно. Для цифровых ключей чаще применяется двоичный поиск. (Конечно, вы можете, но не так много хеш-функций, которые тестируются на интегральных данных.)   -  person Dietrich Epp    schedule 21.10.2011
comment
@ Дитрих: да, действительно, я говорил в более общем смысле.   -  person Blagovest Buyukliev    schedule 21.10.2011
comment
К вашему сведению: существуют различные библиотеки C, которые люди реализовали для анализа, доступа и вывода JSON, перечисленные здесь: json.org   -  person HostileFork says dont trust SE    schedule 21.10.2011


Ответы (4)


Использование переключателя - это полностью идиоматический C, есть отдельное рассмотрение стиля (которое будет применяться практически к любому языку), хотите ли вы отделить данные ключ / значение из логики программы.

Вы можете использовать массив const struct { int key; const char *value; };, но тогда вы начнете беспокоиться о том, следует ли использовать линейный поиск, двоичный поиск, идеальный хэш и т. Д. С переключателем компилятор забирает это из ваших рук.

Если у вас есть какой-то ассоциативный контейнер (дерево или хэш-карта), который вы используете для других вещей в этом проекте, вы можете использовать его, но на самом деле не стоит писать его для коллекции из 30 элементов.

person Steve Jessop    schedule 21.10.2011

Как и вы:

typedef struct {
    long long key;
    char *val;
} Item;

const Item mydict[] = {
    {1, "One"},
    {1000, "One thousand"},
    {1000000, "One million"}
};

Я оставляю в качестве упражнения тело функции numbers().

Альтернативное решение, предложенное Стивом Джессопом также совершенно верно.

person mouviciel    schedule 21.10.2011
comment
Как это ответ? Вы практически полностью проигнорировали вопрос OP и оставили его как упражнение !! - person Shahbaz; 21.10.2011

Если все статически известно, я бы сказал что-то вроде этого:

char strings[][] = {"One", "One thousand", "One million", /* whatever */};
int map[] = {1, 1000, 1000000};

const char *numbers(const int i)
{
    position = search(map, i);// if the array is too small, just linear search
                              // if it is big, you can binary search
                              // if there is a relation use a formula
                              // although a formula is not extendable.
                              // In this case, it is log(i) in base 1000.
    return strings[position];
}

Этот метод можно расширить для нестатических данных. Вам просто нужно убедиться, что вы правильно заполнили массив strings и сохранили map отсортированным.

Примечание. Очевидно, вам следует добавить достаточную проверку ошибок и т. Д. Например, в случае, когда search не может найти i.

person Shahbaz    schedule 21.10.2011
comment
Неужто вы хотите вернуть строки [позиция]? Я бы отредактировал, но это было слишком короткое изменение. - person tinman; 21.10.2011

Это могло быть одним из решений.

В основном создайте отсортированный массив пар ключ-значение, а затем просто используйте функцию bsearch (выполняет двоичный поиск), чтобы быстро найти правильное значение. Возможно, имеет смысл реализовать собственный двоичный поиск, чтобы сделать поиск более удобным.

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

typedef struct mapping
{
    int key;
    char* value;
} Mapping;

int mappingCompare(const void* a, const void* b)
{
    const Mapping* first = (const Mapping*)a;
    const Mapping* second = (const Mapping*)b;
    return second->key - first->key;
}

int main()
{
    Mapping map[3];
    Mapping search;
    Mapping* result;
    map[0].key = 1;
    map[0].value = "One";
    map[1].key = 1000;
    map[1].value = "One thousand";
    map[2].key = 1000000;
    map[2].value = "One million";

    //qsort is only needed if the map is not already in order
    qsort(map, 3, sizeof(Mapping), mappingCompare);

    search.key = 1000;
    result = (Mapping*)bsearch(&search, map, 3, sizeof(Mapping), mappingCompare);
    printf("value for key 1000 is %s\n", result->value);
}
person Juho    schedule 21.10.2011