For following table structure, I could create a static table and print the values:
------ ---------
| key1 | value1 |
| key2 | value2 |
| key3 | value3 |
------ ---------
#include <stdio.h>
typedef struct key_value_map
{
char *key;
char *value;
} KeyValueMap;
static KeyValueMap key_value_map_table[] =
{
{"key1", "value1"},
{"key2", "value2"},
{"key3", "value3"},
};
int main(void) {
int i = 0;
int n = sizeof(key_value_map_table)/sizeof(key_value_map_table[0]);
for(i=0; i<n; i)
{
printf("Key=%s, Val=%s\n",key_value_map_table[i].key,
key_value_map_table[i].value);
}
return 0;
}
However, if I add more than one values then I'm not able to create a static table:
------ -----------------------
| key1 | value1 value2 value3 |
| key2 | value1 value4 value5 |
| key3 | value2 value4 |
| key4 | value5 |
------ -----------------------
typedef struct key_values_map
{
char *key;
char **values;
}KeyValuesMap;
static KeyValuesMap key_values_map_table[] =
{
{"key1", "value1", "value2", "value3"},
{"key2", "value1", "value4", "value5"},
{"key3", "value2", "value4"},
{"key3", "value5"},
};
This is giving me following error:
"Too many initializers"
How should I initialize and iterate over it?
CodePudding user response:
Use compound literals that are arrays of char*
.
static KeyValuesMap key_values_map_table[] =
{
{"key1", (char*[]){"value1", "value2", "value3"}},
{"key2", (char*[]){"value1", "value4", "value5"}},
{"key3", (char*[]){"value2", "value4"}},
{"key3", (char*[]){"value5"}},
};
Iteration is bit more complex. I see three strategies:
A. Use explicit length:
typedef struct key_values_map {
char *key;
size_t count;
char **values;
}KeyValuesMap;
static KeyValuesMap key_values_map_table[] = {
{"key1", 3, (char*[]){"value1", "value2", "value3"}},
...
};
B. Mark the last entry with NULL
.
{"key1", (char*[]){"value1", "value2", "value3", NULL}},
Iterate with:
for (char **p = key_values_map_table[0].values; *p; p) {
char *str = *p;
...
}
C. Use a macro to infer size for A variant.
#define MK_ENTRY(key, ...) \
{ key, \
sizeof((char*[]){ __VA_ARGS__ }) / sizeof(char*), \
(char*[]){ __VA_ARGS__ } }
static KeyValuesMap key_values_map_table[] = {
MK_ENTRY("key1", "value1", "value2", "value3"),
...
};
This macro applies sizeof X / sizeof X[0]
trick to evaluate the number of elements of X
array. It essentially divides the size of array (in bytes) by the size of its single element (in bytes as well).
In this case it is sizeof((char*[]){ ... }) / sizeof(char*)
.
A variadic macro is used to handle all macro arguments after the key.
Basically, __VA_ARGS__
is replaced by the list of the value strings.
CodePudding user response:
You may create an array for each key to list the values associated with that key, then include the array identifiers in the table initializer where appropriate.
An example of how this could be done:
const char * key1_vals[] = {"value1", "value2", "value3"};
const char * key2_vals[] = {"value1", "value4", "value5"};
const char * key3_vals_1[] = {"value2", "value4"};
const char * key3_vals_2[] = {"value5"};
static KeyValuesMap key_values_map_table[] =
{
{"key1", key1_vals},
{"key2", key2_vals},
{"key3", key3_vals_1},
{"key3", key3_vals_1},
};
Some things to keep in mind:
- You will need to keep track of the number of values associated with each key in object KeyValueMap, so that the program knows how many values to look for.
- You may want to replace
char *key;
andchar *value;
withconst char *key;
andconst char *value;
so that the program knows that these pointers are pointing to constant data.