【问题标题】:lookup table in cc中的查找表
【发布时间】:2011-04-21 23:46:15
【问题描述】:

我正在用 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"}}
};

我收到以下错误:

错误:灵活初始化 嵌套上下文中的数组成员

错误:(接近初始化为 ‘tab[0].message’)

如何初始化第二个示例中的选项卡数组? 注意:我知道 tab 数组中的所有值。

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

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

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

非常感谢。

最好的问候, 维克多

【问题讨论】:

    标签: c arrays struct char


    【解决方案1】:

    您不能在(结构的)数组中使用包含灵活数组成员的结构。参见 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 编译器,请注意。

    【讨论】:

    • 我只是打开我的旧 C 书来理解这个结构;)(Java 正在扼杀我的工程技能......)
    【解决方案2】:

    我认为您必须指定数组大小才能在另一个数组中使用该结构:

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

    【讨论】:

    • 要么这样,要么吞下苦果并使用多行代码进行初始化;)
    • 您好,谢谢,您的选择有效,但消息的大小也可能不同,我刚刚更新了我的问题以反映这一点。对不起。
    • 顺便说一句,对消息使用 fix-max-size 也不太喜欢我。
    • @Victor:在这种情况下,您必须将message 的大小设置为可能的最大大小。或者只是使用指针手动管理内存,如另一个答案中所建议的那样。
    【解决方案3】:

    您需要在结构定义中为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++;
      }
    }
    

    【讨论】:

      【解决方案4】:
      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] 应该从哪里开始。
      • 在我的代码中它说所有数组元素都具有相同的大小,我编辑了注释以使其更加可见。感谢您指出这一点。
      猜你喜欢
      • 2022-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多