I\'m creating a lookup table in C When I define this:
typedef struct {
char* action;
char* message;
} lookuptab;
lookuptab tab[] = {
{\"aa\",\"bb\"},
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.
I think you have to specify the array size to use the struct in another array:
typedef struct {
char* action;
char* message[2];
} lookuptab;
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;
}
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++;
}
}