Lookup table in c

I create a lookup table in C when I define this:

typedef struct { char* action; char* message; } lookuptab; lookuptab tab[] = { {"aa","bb"}, {"cc","dd"} }; 

it compiles without errors, but when I do something like this:

 typedef struct { char* action; char* message[]; } lookuptab; lookuptab tab[] = { {"aaa", {"bbbb", "ccc"}}, {"cc", {"dd", "eeeee"}} }; 

I get the following error:

error: initializing flexible array element in nested context

error: (near initialization for "Tab [0] .message)"

How to initialize a tab array in the second example? Note. I know all the values ​​inside an array of tabs.

UPDATE: the message may have a different size, for example

 typedef struct { char* action; char* message[]; } lookuptab; lookuptab tab[] = { {"aaa", {"bbbb", "ccc", "dd"}}, {"cc", {"dd", "eeeee"}} }; 

Many thanks.

Sincerely, Victor

+6
c arrays struct char
source share
4 answers

You cannot use structures containing the flexible element of an array in an array (structures). See Standard C99 §6.7.2.1 / 2:

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

So, use 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 the C99 construct (§ 6.5.5.5 Component literals) - be careful if you are not using the C99 compiler.

+12
source share

I think you need to specify the size of the array to use the structure in another array:

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

lookuptab is an incomplete type. You cannot create objects of this type. Or specify a specific size for the message array

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

or use pointers on all sides and manage memory “manually”

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

you can use a flexible array element (all elements will have the same size), but it works a lot :-)

 #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
source share

You need to specify the size for the message array element in the structure 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 structure lookuptab have a different number of elements in the message array, you will have to allocate each message array separately, that is, you cannot 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 explicitly passing the number of messages, you can use the watch:

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

but you will have to either iterate over all the arguments twice (first, to get a number to select the messages array, then copy each message), or you will need a realloc() array for each message, for example:

 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
source share

All Articles