lookup table in c

前端 未结 4 2058
误落风尘
误落风尘 2021-01-03 00:58

I\'m creating a lookup table in C When I define this:

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

lookuptab tab[] = {
  {\"aa\",\"bb\"},
           


        
相关标签:
4条回答
  • 2021-01-03 01:20

    You can't use structures containing a flexible array member in an array (of the structure). See C99 standard §6.7.2.1/2:

    A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), except that the last member of a structure with more than one named member may have incomplete array type; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array.

    So, use a char ** instead (and worry about how you know how many entries there are):

    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" } }
    };
    

    This uses a C99 construct (§6.5.2.5 Compound literals) - beware if you are not using a C99 compiler.

    0 讨论(0)
  • 2021-01-03 01:25

    I think you have to specify the array size to use the struct in another array:

    typedef struct {
     char* action;
     char* message[2];
    } lookuptab;
    
    0 讨论(0)
  • 2021-01-03 01:31
    typedef struct {
     char* action;
     char* message[];
    } lookuptab;
    

    lookuptab is an incomplete type. You cannot create objects of that type. Either provide a definite size for the message array

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

    or use pointers all around and manage memory "by hand"

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

    you can use the flexible array member (all elements will have the same size), but it's a lot of work :-)

    #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;
    }
    
    0 讨论(0)
  • 2021-01-03 01:37

    You need to specify a size for the message array member in the struct definition:

    #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"}},
      ...
    };
    

    In this case, N must be at least 2.

    If you want each instance of the lookuptab struct to have a different number of elements in the message array, then you will have to allocate each message array separately, meaning you won't be able to use a static initializer:

    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);
      ...
    }
    

    Instead of passing the number of messages explicitly, you can use a sentinel:

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

    but you'll either have to cycle through all the arguments twice (first to get the number to allocate the messages array, then to copy each message) or you'll have to realloc() your array for each message, such as:

    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++;
      }
    }
    
    0 讨论(0)
提交回复
热议问题