You can use designated initialisers, as described in M. Oehm's post, but that silently introduces the same gaps you were referring to earlier (with implicit 0
values). That option is most suitable when you know 0
will never be an actual selection, when the table doesn't change dynamically (particularly in size) and when the size of the table is small.
If the table is particularly large, but items are never added or removed from it you can use qsort
and bsearch
on a key/value-pair style structure. For example:
struct foo_pair {
int key;
char *value;
};
int foo_pair_compare(void *x, void *y) {
struct foo_pair *a = x, *b = y;
return (a->key > b->key) - (a->key < b->key);
}
int main(void) {
struct foo_pair foo[] = { { .key = 3, .value = "foo" },
{ .key = 5, .value = "bar" },
{ .key = 6, .value = "etc" } };
/* qsort needs to be done at the start of the program,
and again each time foo changes */
qsort(foo, sizeof foo / sizeof *foo, sizeof *foo, foo_pair_compare);
/* bsearch is used to retrieve an item from the sorted array */
struct foo_pair *selection = bsearch(&(struct foo_pair) { .key = 5 },
foo, sizeof foo / sizeof *foo,
sizeof *foo, foo_pair_compare);
}
When items are routinely added or removed from the collection, it will make more sense to select a hashtable or some kind of ordered map. If you can't be bothered writing and testing your own of these collections, I imagine there are plenty of tried & tested libraries on the internet that you could check out.