4

I have the following code, which is not working as expected. It compiles, but throws a lot of warnings and segfaults when executed:

#include <stdio.h> enum output { A, B, C, D, }; struct translation { char *from; enum output to; }; struct dictionary { struct translation *foo; struct translation *bar; }; enum language { ONE, ANOTHER, }; struct dictionary languages[] = { [ONE] = { .foo = { {"LF", A}, {"LLF", C}, {"RRF", D}, }, .bar = { {"L", B}, }, }, [ANOTHER] = { .foo = { {"FF", B}, {"RRF", D}, }, .bar = { {"LF", B}, {"R", C}, {"RR", D}, }, }, }; int main(void) { printf("%s\n", languages[ONE].foo[0].from); return 0; } 

I am probably initializing languages the wrong way.

  • I would like to have that languages array in which I can access different dictionaries by language: languages[ONE]
  • I would like to access then different translation tables with the dictionary field: languages[ONE].foo
  • All translation tables accessed with a language+field pair may have different array lengths, as shown in the code example

Is that even possible? What am I doing wrong?

When compiling with gcc I get this (cropped) output:

asdf.c:27:17: warning: braces around scalar initializer .foo = { ^ asdf.c:27:17: note: (near initialization for ‘languages[0].foo’) asdf.c:28:25: warning: braces around scalar initializer {"LF", A}, ^ asdf.c:28:25: note: (near initialization for ‘languages[0].foo’) asdf.c:28:26: warning: initialization of ‘struct translation *’ from incompatible pointer type ‘char *’ [-Wincompatible-pointer-types] [...] 

The same warnings/notes repeat for multiple parts of the code.

1
  • @FiddlingBits Actually, that could be a workaround! :-) I tried with [] (no size) but that was illegal. You can post that as an answer if you want. Although I will wait before accepting to see if there is a way of making this work without having to specify a dictionary table size "big enough" to hold all translations. Commented Nov 19, 2018 at 21:35

2 Answers 2

3

Here are two things you can do:

  1. Allocate memory for struct translation *foo; and struct translation *bar; (you can also use malloc to dynamically allocate memory). For example:
 struct dictionary { struct translation foo[10]; struct translation bar[10]; }; 
  1. Use a compound literal in your definition:
 struct dictionary languages[] = { [ONE] = { .foo = (struct translation []){ {"LF", A}, {"LLF", C}, {"RRF", D}, }, .bar = (struct translation []){ {"L", B}, }, }, [ANOTHER] = { .foo = (struct translation []){ {"FF", B}, {"RRF", D}, }, .bar = (struct translation []){ {"LF", B}, {"R", C}, {"RR", D}, }, }, }; 

Note

As mentioned by @M.M, adding the qualifier const before struct dictionary is a good idea if its values won't change during runtime.

Sign up to request clarification or add additional context in comments.

9 Comments

Love the latter <3. I am learning a lot of C with this project. :-D
something like struct translation foo[10]; (leaving some of them uninitialized) is a very poor idea while compound literals are feature of C99 language
@VTT Sure. I mentioned it as an option, not a recommendation.
@VTT why is it a poor idea in your opinion?
@VTT not necessarily; in some systems memory is cheap and other concerns such as code clarity, portability, ease of development, ease of runtime access etc. may have a higher priority
|
1

Just initialize each array separately:

#include <stdio.h> enum output { a , b , c , d }; struct translation { char const * from; enum output to; }; struct dictionary { struct translation * foo; struct translation * bar; }; enum language { one , another , languages_count }; struct translation one_language_foo_translations[] = { {"LF" , a} , {"LLF", c} , {"RRF", d} }; struct translation one_language_bar_translations[] = { {"L", b} }; struct translation another_language_foo_translations[] = { {"FF" , b} , {"RRF", d} }; struct translation another_language_bar_translations[] = { {"LF", b} , {"R" , c} , {"RR", d} }; struct dictionary languages[languages_count] = { {one_language_foo_translations, one_language_bar_translations} , {another_language_foo_translations, another_language_bar_translations} }; int main(void) { printf("%s\n", languages[one].foo[0].from); return 0; } 

online compiler

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.