C语言中的查找表

6

我正在用C语言创建一个查找表。当我定义以下内容时:

typedef struct {
 char* action;
 char* message;
} lookuptab;

lookuptab tab[] = {
  {"aa","bb"},
  {"cc","dd"}
};

代码编译无误,但当我执行以下操作时:

typedef struct {
 char* action;
 char* message[];
} lookuptab;

lookuptab tab[] = {
  {"aaa", {"bbbb", "ccc"}},
  {"cc", {"dd", "eeeee"}}
};

我遇到了如下错误:

error: initialization of flexible array member in a nested context

error: (near initialization for ‘tab[0].message’)

在第二个例子中,我该如何初始化tab数组呢? 注意:我已经知道tab数组中所有的值。

更新:message的大小可能不同,例如:

typedef struct {
 char* action;
 char* message[];
} lookuptab;

lookuptab tab[] = {
  {"aaa", {"bbbb", "ccc", "dd"}},
  {"cc", {"dd", "eeeee"}}
};

非常感谢。
最好的问候, 维克托
4个回答

12
在数组中,不能使用包含柔性数组成员的结构体。参见C99标准§6.7.2.1/2:
“结构体或联合体不得包含具有不完全类型或函数类型的成员(因此,结构体不得包含其本身的实例,但可以包含指向其本身实例的指针),除非具有多个命名成员的结构体的最后一个成员具有不完全数组类型。这样的结构体(以及任何包含可能递归地包含该结构体成员的联合体)不得是结构体的成员或数组的元素。”
所以,应该使用char **代替结构体(并且需要考虑如何知道有多少条目)。
typedef struct
{
    const char         *action;
    const char * const *message;
} lookuptab;

static const lookuptab tab[] =
{
    { "aaa", (const char * const []){ "bbbb", "ccc"   } },
    { "cc",  (const char * const []){ "dd",   "eeeee" } }
};

这个使用了C99的构造(§6.5.2.5 复合字面量)- 如果你没有使用C99编译器,请小心。


5
我将翻译这句话:“我只是要拿出我的旧C语言书来理解这个结构;(Java让我失去了工程技能……)”。 - Victor Gaspar

2

我认为你需要指定数组大小才能在另一个数组中使用结构体:

typedef struct {
 char* action;
 char* message[2];
} lookuptab;

1
要么这样,要么就吞下苦果,使用多行代码进行初始化 ;) - riwalk
嗨bde,谢谢,你的选项可行,但是消息也可能有不同的大小,我刚刚更新了我的问题以反映这一点。抱歉。 - Victor Gaspar
顺带一提,我也不太喜欢使用固定最大消息大小的方式。 - Victor Gaspar
@Victor:在这种情况下,您将不得不将message的大小设置为可能的最大值。或者按照其他答案中建议的那样手动管理内存,使用指针。 - WildCrustacean

0
typedef struct {
 char* action;
 char* message[];
} lookuptab;

lookuptab 是一个不完整的类型。你不能创建该类型的对象。要么为消息数组提供明确的大小

typedef struct {
 char* action;
 char* message[42];
} lookuptab_definite_size;

或者到处使用指针并手动管理内存

typedef struct {
 char* action;
 char** message;
} lookuptab_pointers_all_around;

你可以使用灵活数组成员(所有元素将具有相同的大小),但这需要很多工作 :-)

#include <stdlib.h>
typedef struct {
  char* action;
  char* message[];
} lookuptab;

int main(void) {
  lookuptab *tab;

  tab = malloc(sizeof *tab + 42 * sizeof *tab->message);
  /* tab = malloc(elems * (sizeof *tab + 42 * sizeof *tab->message)); */
  /* tab[0] ... tab[elems-1] all have the same size */
  if (tab) {
    tab->action = NULL;
    tab->message[0] = NULL;
    tab->message[1] = NULL;
    /* ... */
    tab->message[41] = NULL;
    free(tab);
  }
  return 0;
}

你不能像你的注释所建议的那样分配一个柔性数组成员结构体的数组 - 编译器无法知道tab[1]应该从哪里开始。 - caf
在我的代码中,它说所有的数组元素都具有相同的大小,我编辑了注释以使其更加明显。谢谢你指出这一点。 - pmg

0

在结构体定义中,您需要为message数组成员指定一个大小:

#define N ... // maximum number of elements in message array

typedef struct
{
  char *action;
  char *message[N]; 
} lookuptab;

lookuptab tab[] = {
  {"aa", {"bb", "cc"}},
  {"dd", {"ee", "ff"}},
  ...
};

在这种情况下,N必须至少为2。
如果您希望lookuptab结构的每个实例在message数组中具有不同数量的元素,则必须单独分配每个message数组,这意味着您将无法使用静态初始化程序:
typedef struct
{
  char *action;
  char **messages;
} lookuptab;

lookuptab *newEntry(const char *action, size_t numMessages, ...)
{
  lookuptab *entry = malloc(sizeof *entry);
  if (entry)
  {
    entry->action = malloc(strlen(action) + 1);
    if (entry->action)
      strcpy(entry->action, action);
    if (numMessages > 0)
    {
      entry->messages = malloc(sizeof *entry->messages * numMessages);
      if (entry->messages)
      {
        size_t i;
        va_list ap;

        va_start(ap, numMessages);

        for (i = 0; i < numMessages; i++)
        {
          char *nextMessage = va_arg(ap, char *);
          entry->messages[i] = malloc(strlen(nextMessage) + 1);
          if (entry->messages[i])
            strcpy(entry->messages[i], nextMessage);
        }
      }
    }
  }
  return entry;
}

int main(void)
{
  lookuptab *tab[ENTRIES]; // for some number of ENTRIES
  tab[0] = newEntry("AA", 2, "BB", "CC");
  tab[1] = newEntry("DD", 3, "EE", "FF", "GG");
  tab[2] = newEntry("HH", 0);
  ...
}

你可以使用一个标志来代替显式地传递消息数量:

  tab[0] = newEntry("AA", "BB", "CC", NULL);

但是你要么必须两次循环遍历所有参数(第一次获取分配“messages”数组的数量,然后复制每个消息),要么就必须为每个消息realloc()你的数组,例如:

size_t numMessages = 0;
...
char *nextMessage
while ((nextMessage = va_arg(ap, char *)) != NULL)
{
  char **tmp = realloc(entry->messages, sizeof *entry->messages, numMessages+1);
  if (tmp)
  {
    entry->messages = tmp;
    entry->messages[numMessages] = malloc(strlen(nextMessage) + 1);
    strcpy(entry->messages[numMessages], nextMessage);
    numMessages++;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接