идиоматический C для отображения строки типа int в const - PullRequest
2 голосов
/ 21 октября 2011

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

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

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

Карта будет содержать около 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 "";
   }
}

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

Ответы [ 4 ]

3 голосов
/ 21 октября 2011

Как и вы:

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

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

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

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

3 голосов
/ 21 октября 2011

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

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

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

2 голосов
/ 21 октября 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.

1 голос
/ 21 октября 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);
}
...