2

I'm newbie in programming and learning about struct, when trying to put two flexible array in a single struct they give me a error, why i can't put two array in a single struct? I created a pokemon example to test a array in struct but only *pokemon_name[] works, why?

#include <stdio.h> void main() { struct pokemon { int first_generation; char *pokemon_type[]; char *pokemon_name[]; } number_pokedex[438]; number_pokedex[23].pokemon_name[5] = "Arbok"; number_pokedex[23].pokemon_type[6] = "Poison"; number_pokedex[23].first_generation = 1; printf("Name of the pokemon: %s\n", number_pokedex[23].pokemon_name[5]); printf("Type of the pokemon: %s\n", number_pokedex[23].pokemon_type[6]); printf("From first generation?: %d\n", number_pokedex[23].first_generation); } 
2
  • 2
    You can't because 1) The C standard says so. 2) Think of how this will be implemented under the hood. There is no straightforward way to make this work. Also note, you can't have an array of structures containing a flexible member. I would suggest to stay away of this feature. At least until the point where you consider yourself intermediate to advanced level in C and not newbie. Commented Feb 21, 2019 at 21:47
  • why not just char * name; ? it can have several names ?, in that case char ** name; to have an array of names, and use malloc/realloc for it. Same for type Commented Feb 21, 2019 at 21:57

2 Answers 2

1

Why the error message ?

The C standard says in section 6.7.2.1 / 18:

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply.

In your case, you have such a flexible array that is not the last element of the struct, and hence the error.

Why doesn't C allow more than one flexible array member ?

The behavior of a struct with a flexible array, is defined so that it works as if the flexible array starts just after the code of the struct.

 +--------------------------------+----+----+----+----+ | struct without flexible array |f[0]|f[1]|f[2]|... | +--------------------------------+----+----+----+----+ 

So you can write code such as:

 struct test { int a; int flex[]; } *pt, array[10]; static struct test t={ 1, {2,3,4}}; printf ("%x %x %x\n", &t, &t.flex[0], &t.flex[3]); pt = malloc(sizeof(struct test)+20*sizeof(int)); printf ("%x %x\n", pt, &pt->flex[0]); 

The problem is that you have to know how many elements are reserved for the flexible array (either statically reserved or dynamically allocated). If C would allow several flexible arrays, this kind of behavior would no longer be possible, since the compiler would not know where the second flexible array would start.

Alterantive

Now you can very well rewrite your code by using more robust fixed size arrays, or using dynamic arrays by the means of a pointer to pointers.

struct pokemon { int first_generation; char **pokemon_type; char **pokemon_name; } number_pokedex[438]; 

In this case, you'd have to inialize the char** pointers by allocating an array of sufficient size:

// assuming that no more than 10 elements in item 23. number_pokedex[23].pokemon_name = calloc (10, sizeof(char*)); number_pokedex[23].pokemon_type = calloc (10, sizeof(char*)); 

You'd also need to free the arrays when no longer needed. Finally you'd have to take extra care when copying struct elements, since you'd clone the pointers.

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

Comments

1

While Christophe gives a perfectly sound traditional answer, you might want to be aware of an alternative. Instead of an array of pointers, if you're willing to limit the length of the names, you could use an array of arrays instead.

typedef char name_type[20]; struct pokemon { int first_generation; name_type *pokemon_type, *pokemon_name; } number_pokedex[438]; void b() { number_pokedex[23].pokemon_name = calloc (10, sizeof(name_type)); number_pokedex[23].pokemon_type = calloc (10, sizeof(name_type)); } 

This says your names are 20 bytes, and your arrays are 200 bytes: 10 elements of 20 bytes each. Unlike the array-of-pointers technique, here calloc allocates not pointers, but arrays, so you have only one allocation and one deallocation.

IMO an array of arrays is easier to use: when it comes time to populate the name, the storage is already allocated, and when it comes time to free the array, you don't have to chase the pointer for each element.

A common objection is that this technique requires the name size to be established at compile-time, making it less "flexible". That's less of an issue than it might seem, though, because wherever the name appears there is an implied limit, whether it's a field in a GUI or a column in a database or the width of a terminal or the size of the window on an envelope. Might as well decide how big your names are, and get on with it.

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.