написать конструкцию C - PullRequest
       8

написать конструкцию C

0 голосов
/ 03 августа 2011

Есть ли способ (в C) написать конструкцию, подобную оператору switch, но для строк? Есть ли способ написать конструкцию C на всех в C?

Под конструкцией C я подразумеваю утверждение с фигурными скобками ... как у оператора if есть фигурные скобки, а это конструкция C ... верно?

Ответы [ 8 ]

3 голосов
/ 03 августа 2011

Нет, ты должен сделать это сам. Вариантов много:

if (strcmp(str, "toto") == 0)
{
    // ...
}

else if (strcmp(str, "tata") == 0)
{
    // ...
}

else
{
    // ...
}

Если ожидается рост числа строк, то таблица отправки с указателями на функции

struct dispatch_entry
{
    const char *key;
    void (*action)(void);
};

// Make sure it is sorted !
dispatch_entry dispatch_table[] = 
{
    { "tata", &action_tata },
    { "toto", &action_toto },
};

в сочетании с бинарным поиском:

int dispatch_compare(const void *x, const void *y)
{
    const dispatch_entry *xx = x, *yy = y;
    return strcmp(xx->key, yy->key);
}

// Return -1 on failure
int dispatch(const char *str)
{
    static const size = sizeof(struct dispatch_entry);
    static const n = sizeof(dispatch_table) / size ;

    dispatch_entry tmp = { str, NULL };
    dispatch_entry *what = bsearch(tmp, dispatch_table, n, size, &dispatch_compare);

    if (what == NULL) return -1;

    (*what->action)();
    return 0;
}

будет делать. Подходы, основанные на хэш-таблицах, тоже хороши.

3 голосов
/ 03 августа 2011

Самый простой подход - это цепочка if-else, использующая strcmp для сравнения:

if (strcmp(str, "String 1") == 0)
  // do something
else if (strcmp(str, "String 2") == 0)
  // do something else
else if (strcmp(str, "String 3") == 0)
  // do something else 
...
else
  printf("%s not found\n", str);

Более сложный подход заключается в использовании таблицы подстановки, которую вводит строка:

struct lookup {const char *key; int value};

struct lookup LookupTable[] = {
  {"String 1", 1}, 
  {"String 2", 2}, 
  {"String 3", 3}, 
  ...
  {NULL, -1}
};

int lookup(const char *key)
{
  size_t i = 0;
  while (LookupTable[i].key != NULL)
    if (strcmp(str, LookupTable[i].key) == 0)
      return LookupTable[i].value;
    else
      i++;
  return -1;
}
...
switch(lookup(str))
{
  case 1: ...
  case 2: ...
  case 3: ...
  ...
  default: printf("%s not found\n", str); break;
}

Если вы хотите стать действительно модным, вы можете изменить таблицу поиска так, чтобы значение было указателем на функцию:

void String1Cmd(void) { ... }
void String2Cmd(void) { ... }
void String3Cmd(void) { ... }
...
void BadCmd(void) { printf("Key not found!\n"); }

struct lookup {char *key, void (*cmd)(void); };

struct lookup LookupTable[] = {
  {"String 1", String1Cmd}, 
  {"String 2", String2Cmd}, 
  {"String 3", String3Cmd}, 
  ...
  {NULL, BadCmd}
};

void (*lookup(const char *str))(void)
{
  size_t i = 0;
  while(LookupTable[i].key != NULL)
    if (strcmp(str, LookupTable[i].key) == 0)
      return LookupTable[i].cmd;
    else
      i++;
  return BadCmd;
}
...
void (*f)(void) = lookup(str); // retrieve the function for the given string
f(); // execute the function

В последнем примере, если str == "Строка 1", будет выполняться String1Cmd. Если str - строка, не найденная в таблице поиска, то будет выполняться BadCmd. Этот метод очень гибкий и в зависимости от вашего дизайна позволяет добавлять поведение во время выполнения (своего рода архитектура подключаемого модуля).

Однако обратите внимание, что мы только что перенесли основную проблему - ветвление на строковое значение - на функцию lookup, и что функция lookup вернулась к выполнению strcmp для каждого значения в таблице , Мы могли бы ускорить эту часть процесса, используя хеш-таблицу или дерево , чтобы минимизировать количество сравнений. В зависимости от того, сколько строк вы используете, это может стоить или не стоить дополнительных усилий.

2 голосов
/ 03 августа 2011

если у вас есть функция lfind в вашей библиотеке (POSIX или gcc), вы можете использовать ее так:

  enum   { NOTFOUND, HELLO,  WORLD,  FOO,  BAR };
  char list[][100]={"hello","world","foo","bar"};

  size_t r, siz = sizeof*list, num = sizeof list/siz;

  char *tosearch = "foo";

  switch ( (r=lfind(tosearch,list,&num,siz,strcmp))?
          (r+siz-(size_t)list)/siz:0 )  {

    case HELLO: puts("hello");break;
    case WORLD: puts("world");break;
    case FOO:   puts("foo");  break;
    case BAR:   puts("bar");  break;
    case NOTFOUND:puts("not found");

  }

каждая строка в массиве должна иметь одинаковый размер ине быть указателем

1 голос
/ 03 августа 2011

Нет, поскольку коммутатор может использоваться только с целочисленными типами или с типом, конвертируемым в целочисленный тип

1 голос
/ 03 августа 2011

a хеш-таблица , если у вас большое количество строк и скорость является проблемой

0 голосов
/ 03 августа 2011

Конечно, в зависимости от того, сколько работы вы готовы сделать.

Вы можете использовать препроцессор и некоторые макросы для отображения строк в интегральные идентификаторы , что дает вам синтаксис вроде:

switch (SOSID_LOOKUP (sample_string)) {
   case SOSID (hello): printf ("Hello ");   break;
   case SOSID (world): printf ("World! ");  break;
   case 0: default:    printf ("unknown "); break;
}

Если вы можете использовать C ++ вместо C, вы можете использовать litb's строковый переключатель на основе шаблона , что дает вам синтаксис, такой как:

 sswitch(s) {
    scase("foo"): {
      std::cout << "s is foo" << std::endl;
      break; // could fall-through if we wanted
    }

    // supports brace-less style too
    scase("bar"):
      std::cout << "s is bar" << std::endl;
      break;

    // default must be at the end
    sdefault():
      std::cout << "neither of those!" << std::endl;
      break;
  }
0 голосов
/ 03 августа 2011

Нет, switch работает с целочисленным значением (я думаю, что числа с плавающей запятой / двойные числа даже не допускаются). Вы можете эмулировать это, если if / else if / else делает strcmp.

if (strcmp(mystr, "this") == 0) {
    //mystr == "this"
}
else if (strcmp(mystr, "that") == 0) {
    //mystr == "that"
}
else {
   //mystr is not "this" or "that"
}
0 голосов
/ 03 августа 2011

Да, и путь - длинный if-else-if оператор. (для справки: Почему оператор switch нельзя применять к строкам? )

А что вы подразумеваете под "конструкцией C вообще в C" o.O? Я отредактирую свой пост, когда вы ответите:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...