lookup table in c - c

I'm creating 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: initialization of flexible
array member in a nested context
error: (near initialization for
‘tab[0].message’)
How can I initialize the tab array in the second example?
Note: I know all the values inside the tab array.
UPDATE: message could be of different size, e.g
typedef struct {
char* action;
char* message[];
} lookuptab;
lookuptab tab[] = {
{"aaa", {"bbbb", "ccc", "dd"}},
{"cc", {"dd", "eeeee"}}
};
Thank you very much.
Best regards,
Victor

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;

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

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

Related

Is there a standard way to statically initialize flexible array members in C?

I need a statically created data structure in memory comprised of a table of string vectors, effectively:
typedef struct {
char *argv[];
} Entry;
const Entry Table[] = {
{"a"},
{"a", "b", "c"}
};
But trying to compile this results in error: initialization of flexible array member in a nested context
Apparently this is possible in GCC, according GCC Manual: 6.18 Arrays of Length Zero.
This may be possible following C 2018 6.7.2.1 18, although in regard to that I read elsewhere
There cannot be an array of structures that contain a flexible array member.
Is there a standard way to achieve this behavior? If not, is there a preferred way?
You can't do it with a flexible array member.
Instead, you can use char **argv and initialize it using compound literals.
typedef struct {
char **argv;
} Entry;
const Entry table[] = {
{ (char *[]) { "a", NULL } },
{ (char *[]) { "a", "b", "c", NULL } }
};
I added NULL to each of the arrays so the application can tell their lengths (the real argv has this as well).
You do not store the count of elements of argv. How would you know that the first one has 1 element, and the second one has 3? You have to store that, for example, in another array member.
You can define a structure that has the proper exact same static memory layout as the array of structures with flexible array members that you want to have. Then you can then alias the structure with a pointer to Entry, and use that as an array of entries. Following example does that:
#include <stdlib.h>
#include <assert.h>
#include <stdalign.h>
#include <stddef.h>
#include <stdio.h>
typedef struct {
unsigned len;
char *argv[];
} Entry;
// sane iterating
static_assert(alignof(Entry) == alignof(char *), "");
typedef struct {
unsigned len;
char *argv[1];
} Entry_1;
static_assert(alignof(Entry_1) == alignof(Entry), "");
static_assert(sizeof(Entry_1) == sizeof(Entry) + 1 * sizeof(char *), "");
typedef struct {
unsigned len;
char *argv[3];
} Entry_3;
static_assert(alignof(Entry_3) == alignof(Entry), "");
static_assert(sizeof(Entry_3) == sizeof(Entry) + 3 * sizeof(char *), "");
typedef struct {
Entry_1 e1;
Entry_3 e3;
} Entry_init_1_3;
static_assert(offsetof(Entry_init_1_3, e3) == sizeof(Entry_1), "");
const Entry_init_1_3 entry_init_1_3 = {
{ 1, { "a", } },
{ 3, { "b", "c", "d", } },
};
const Entry *const table = (const void *)&entry_init_1_3;
// ^^^^^^^^^^^^^^^ I hope I know what I am doing.
const Entry *const table_end = (const Entry*)((const char*)table + sizeof(entry_init_1_3));
const Entry *table_next(const Entry *it) {
return (const Entry *)(
(const char *)it + sizeof(Entry) + it->len * sizeof(char *)
);
}
int main() {
unsigned entry_idx = 0;
for (const Entry *it = table;
it != table_end;
it = table_next(it), ++entry_idx
) {
for (unsigned x = 0; x < it->len; ++x) {
fprintf(stderr, "table[%d].argv[%d] = %s\n",
entry_idx,
x,
it->argv[x]
);
}
}
}
Code outputs:
table[0].argv[0] = a
table[1].argv[0] = b
table[1].argv[1] = c
table[1].argv[2] = d
Most notable inotify() Linux system call returns an array of flexible array members.
Is there a standard way to statically initialize flexible array members in C?
No.
If not, is there a preferred way?
Don't use flexible array members. Use pointers, as presented in the other answer.

Write to double const pointer

I want to implement my own string implementation for education. For that I defined a struct named string as follows:
struct string {
const char *const data;
const int length;
};
I use functions to create these string structs and then I assign them to variables.
In order to override the const int length I use the following trick:
*(int *) &result.length = // a int
Now I also want to write to the const char *const data.
As far as I know the first const makes sure that you cant edit the items at which the pointer points, and the second const is that you can't point the pointer to a different memory location. These are properties of an immutable string. So my question is: How can I assign something to the const char *const data like I did to the const int length?
Edit: result as shown above is an instance of the struct string
Form the struct string at its declaration and initialize it.
Also recommend to store the size and not the length and use size_t.
#include <stdio.h>
#include <stdlib.h>
struct string {
const char * const data;
const size_t size;
};
struct string string_copy(const char *src) {
size_t size = strlen(src) + 1;
char *copy = malloc(size);
if (copy) {
memcpy(copy, src, size);
} else {
size = 0;
}
struct string retval = {copy, size}; // ****
return retval;
// or return a compound literal (C99)
return (struct string){ copy, size};
}
void string_free(struct string s) {
free((void*)s.data);
}
int main(void) {
struct string a = string_copy("Hello");
printf("%zu <%s>\n", a.size, a.data);
string_free(a);
// do not use `a` subsequently
return 0;
}
I do not recommend to initialize with a string literal like struct string retval = {"World", 6}; as that limits the usefulness of struct string.
Using a opaque struct has many advantages #Jonathan Leffler that exceed this approach - mainly to keep other code from messing with the struct string.

How to pass structure to function to allocate memory

As the title says i want to pass structure to function and allocate memory, maybe it's a stupid question but i can't find the answer..
structName *allocate_memory( int *numPlayers,structName )
{
structName *retVal = malloc( sizeof(struct structName) * (*numPlayers) );
return retVal;
}
The problem is in parameters structName what should go there?
if you need the full code i can post it but i think there is no need..
You can't pass in a type as a parameter. But you can pass in its size:
void *allocate_memory( int *numPlayers, size_t struct_size)
{
void *retVal = malloc( struct_size * (*numPlayers) );
if (!retVal) {
perror("malloc failed!");
exit(1);
}
return retVal;
}
Then call it like this:
struct mystruct *s = allocate_memory(&numPlayers, sizeof(struct mystruct));
Or you just do this instead, assuming you want the memory initialized to all 0:
struct mystruct *s = calloc(numPlayers, sizeof(struct mystruct));
You can use a void pointer there, void can take anything...hope it helps....
You have two options, the first returning a new pointer (see allocate_memory) and the second is to fill in an existing pointer (see allocate_memory2. In both cases I converted numPlayers to int because it isn't necessary to provide by reference
struct structName *allocate_memory(int numPlayers)
{
struct structName *retVal = malloc(sizeof(struct structName) * numPlayers);
return retVal;
}
void allocate_memory2(struct structName **target, int numPlayers)
{
*target = malloc(sizeof(struct structName) * numPlayers);
}
int main(int argc, char** argv)
{
struct structName *str;
struct structName *str2;
//After this line str is a valid pointer of size 20*sizeof(struct structName)
str = allocate_memory(20);
//After this line str2 is a valid pointer of size 20*sizeof(struct structName)
allocate_memory2(&str2, 20);
}
You cannot pass a type as a parameter to a function.
You basically have two options realizing your allocate_memory function:
Instead of passing the name of the type simply pass the size of the type:
void *allocate_memory( int *numPlayers, size_t size). But this is only a trivial wrapper for malloc.
You could write a macro #define allocate_memory(num, type) (malloc(num * sizeof(type))) to do the job.
Maybe you're looking for a combination of both if you want to track some statistics of the memory allocated or do additional checks:
#define allocate_memory(num, type) (my_malloc((num), sizeof((type))))
void *my_malloc(int num, size_t size)
{
void *pMem = malloc(num * size);
if (pMem == NULL)
{
/* do error handling */
}
return (pMem);
}
You can use the above macro as follows:
pInt = allocate_memory(5, int); // allocates 5 integers
pStruct = allocate_memory(10, some_struct); // allocates 10 some_structs

Accessing information from nested struct passed to function

I have the following code:
struct wordPair {
char* englishWord;
char* foreignWord;
};
struct dictionary {
struct wordPair ** data;
int nbwords;
int size;
};
Say I have struct dictionary *dictionaryPtr filled with some data, and I pass it to the following function:
char* dictionary_translate( struct dictionary* d,
const char* const english_word,
const char* const foreign_word)
Within the function dictionary_translate, how can I access the data from the struct wordPair that is nested within the passed struct? I need the function to return a strdup of either englishWord or foreignWord.
I was trying d->data->englishWord, but this gives me the error "request for member 'englishWord' in something not a structure or union".
UPDATE!
What I need the function dictionary_translate to do is determine if there is a matching word pair that contains one of the words passed to it, and return the strdup of the translation (the other word in the pair). Here is the array of words I have defined:
const char* test_translations[NB_TESTS][NB_COLS] =
{
{"hello", "hola"},
{"cat", "gato"},
{"dog", "perro"},
{"thanks", "gracias"},
{"pants", "pantalones"},
{"shoes", "zapatos"},
};
This is how I'm calling the function in the first test I'm trying, which is when the translate function is passed an English word and is required to return a foreign word:
char* translationPtr = NULL;
for (i = 0; i < NB_TESTS; i++) {
translationPtr = dictionary_translate(dictionaryPtr, test_translations[i][0], NULL);
printf("English Word %s translated: %s\n", test_translations[i][0], translationPtr);
}
Here is the translate function as I have it so far...
char* dictionary_translate( struct dictionary* d,
const char* const english_word,
const char* const foreign_word){
int i;
if (d == NULL) return NULL;
for (i = 0; i < d->nbwords; i++) {
if (strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return NULL;
}
As soon as the program gets to the translation function, it crashes. I can't make sense of the debugger to find out what is going on, but it seems like translationPtr never has a value other than NULL (0x0). I'm new with the debugger, so I'm sure it could tell me more if I knew how to read it.
It isn't entirely clear what your function is to do, but about the simplest implementation that might legitimately work is:
#include <string.h>
struct wordPair
{
char *englishWord;
char *foreignWord;
};
struct dictionary
{
struct wordPair **data;
int nbwords;
int size;
};
extern char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word);
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return 0;
}
I think you should review the design of your struct dictionary. Using a double pointer seems unnecessary (or the reason for using it is not obvious). The only advantage is that you'd have a contiguous array of pointers to struct wordPair, while the actual struct wordPair elements need not be contiguously allocated themselves. The following code is a more orthodox definition, assuming that a contiguous array of struct wordPair is not a problem:
#include <string.h>
struct wordPair
{
char *englishWord;
char *foreignWord;
};
struct dictionary
{
struct wordPair *data;
int nbwords;
int size;
};
extern char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word);
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (strcmp(english_word, d->data[i].englishWord) == 0)
return strdup(d->data[i].foreignWord);
else if (strcmp(foreign_word, d->data[i].foreignWord) == 0)
return strdup(d->data[i].englishWord);
}
return 0;
}
Given the sample test code where one of the arguments to dictionary_translate() is a NULL pointer, the code in the function must be revised not to dereference the argument if it is null. This assumes the double-pointer version of struct dictionary.
char *dictionary_translate(struct dictionary *d,
const char *const english_word,
const char *const foreign_word)
{
for (int i = 0; i < d->nbwords; i++)
{
if (englishWord != NULL && strcmp(english_word, d->data[i]->englishWord) == 0)
return strdup(d->data[i]->foreignWord);
else if (foreignWord != NULL && strcmp(foreign_word, d->data[i]->foreignWord) == 0)
return strdup(d->data[i]->englishWord);
}
return 0;
}
d->(*data)->englishWord
Should compile.

array of type void

plain C have nice feature - void type pointers, which can be used as pointer to any data type.
But, assume I have following struct:
struct token {
int type;
void *value;
};
where value field may point to char array, or to int, or something else.
So when allocating new instance of this struct, I need:
1) allocate memory for this struct;
2) allocate memory for value and assign it to value field.
My question is - is there ways to declare "array of type void", which can be casted to any another type like void pointer?
All I want is to use "flexible member array" (described in 6.7.2.1 of C99 standard) with ability to casting to any type.
Something like this:
struct token {
int type;
void value[];
};
struct token *p = malloc(sizeof(struct token) + value_size);
memcpy(p->value, val, value_size);
...
char *ptr = token->value;
I suppose declaring token->value as char or int array and casting to needed type later will do this work, but can be very confusing for someone who will read this code later.
Well, sort of, but it's probably not something you want:
struct token {
// your fields
size_t item_size;
size_t length
};
struct token *make_token(/* your arguments */, size_t item_size, size_t length)
{
struct token *t = malloc(sizeof *t + item_size * length);
if(t == NULL) return NULL;
t->item_size = item_size;
t->length = length;
// rest of initialization
}
The following macro can be used to index your data (assuming x is a struct token *):
#define idx(x, i, t) *(t *)(i < x->length ? sizeof(t) == x->item_size ?
(void *)(((char *)x[1]) + x->item_size * i)
: NULL : NULL)
And, if you like, the following macro can wrap your make_token function to make it a little more intuitive (or more hackish, if you think about it that way):
#define make_token(/* args */, t, l) (make_token)(/* args */, sizeof(t), l)
Usage:
struct token *p = make_token(/* args */, int, 5); // allocates space for 5 ints
...
idx(p, 2, int) = 10;
Expanding on AShelly's answer you can do this;
/** A buffer structure containing count entries of the given size. */
typedef struct {
size_t size;
int count;
void *buf;
} buffer_t;
/** Allocate a new buffer_t with "count" entries of "size" size. */
buffer_t *buffer_new(size_t size, int count)
{
buffer_t *p = malloc(offsetof(buffer_t, buf) + count*size);
if (p) {
p->size = size;
p->count = count;
}
return p;
}
Note the use of "offsetof()" instead of "sizeof()" when allocating the memory to avoid wasting the "void *buf;" field size. The type of "buf" doesn't matter much, but using "void *" means it will align the "buf" field in the struct optimally for a pointer, adding padding before it if required. This usually gives better memory alignment for the entries, particularly if they are at least as big as a pointer.
Accessing the entries in the buffer looks like this;
/** Get a pointer to the i'th entry. */
void *buffer_get(buffer_t *t, int i)
{
return &t->buf + i * t->size;
}
Note the extra address-of operator to get the address of the "buf" field as the starting point for the allocated entry memory.
I would probably do this:
struct token {
int type;
void *value;
};
struct token p;
p.value = malloc(value_size);
p.value[0] = something;
p.value[1] = something;
...
edit, actually you have to typecast those p.value[index] = somethings. And/or use a union to not have to typecast.
You can't have an array of 'void' items, but you should be able to do something like what you want, as long as you know value_size when you do the malloc. But it won't be pretty.
struct token {
int type;
void *value;
};
value_size = sizeof(type)*item_count;
struct token *p = malloc(sizeof(struct token) + value_size);
//can't do memcpy: memcpy(p->value, val, value_size);
//do this instead
type* p = (type*)&(p->value);
type* end = p+item_count;
while (p<end) { *p++ = someItem; }
Note that you need an extra address-of operator when you want to get the extra storage.
type *ptr = (type*)&(token->value);
This will 'waste' sizeof(void*) bytes, and the original type of value doesn't really matter, so you may as well use a smaller item. I'd probably typedef char placeholder; and make value that type.
following structure can help you.
struct clib_object_t {
void* raw_data;
size_t size;
};
struct clib_object_t*
new_clib_object(void *inObject, size_t obj_size) {
struct clib_object_t* tmp = (struct clib_object_t*)malloc(sizeof(struct clib_object_t));
if ( ! tmp )
return (struct clib_object_t*)0;
tmp->size = obj_size;
tmp->raw_data = (void*)malloc(obj_size);
if ( !tmp->raw_data ) {
free ( tmp );
return (struct clib_object_t*)0;
}
memcpy ( tmp->raw_data, inObject, obj_size);
return tmp;
}
clib_error
get_raw_clib_object ( struct clib_object_t *inObject, void**elem) {
*elem = (void*)malloc(inObject->size);
if ( ! *elem )
return CLIB_ELEMENT_RETURN_ERROR;
memcpy ( *elem, inObject->raw_data, inObject->size );
return CLIB_ERROR_SUCCESS;
}
More Details : clibutils
Array of type void is not supporting in c/c++.
Example like:
int main() {
void alexa[]; // error: declaration of ‘alexa’ as array of void
return 0;
}
Array of void pointer is supported in c/c++.
Example below:
int main(int argc, char argv*[])
{
void *alexa[100]; // Compiled successfully
return 0;
}

Resources