Array problem : type containing an unknown-size array is not allowed

I need to create a structure like sort of tree. But I’m stuck at a point. Here is the code.

typedef struct 
{
	String Name;
	uint8_t Age;
	uint8_t Toys;
} Child;

typedef struct 
{
	String Name;
	uint8_t Age;
	Child Children[];
} Parent;

Parent Parents[] = 
{
	{ 
		"Parent 1", 40,
		{ 
			{"Child 1", 2} ,
			{"Child 2", 5} ,
			{"Child 3", 10} ,
		} 
	},
	{ 
		"Parent 2", 45,
		{ 
			{"Child 1", 4}
		} 
	}
};

void PrintAllInfo()
{
	uint8_t parentsCount = sizeof(Parents);//may not return 2
	for(uint8_t a = 0; a < parentsCount; a++)
	{
		Parent parent = Parents[a];
		uint8_t childrenCount = sizeof(parent.Children);
		Serial.println(parent.Name + "(" + parent.Age + ")");
		for(uint8_t b = 0; b < childrenCount; b++)
		{
			Child child = parent.Children[b];
			Serial.println("  -" + child.Name + "(" + child.Age + ", " + child.Toys + ")");
		}
	}
}

There is a main error at “Parents” global variable

type containing an unknown-size array is not allowed

Also at “sizeof(parent.Children)”

“incomplete type is not allowed”

Anyone know how can I fix this ?

Thank you.

This line seems to be your problem:

Child Children[];

You need to give it a size. e.g.

Child Children[4];

but a parent can have 1 or even 100 children, having the array size of 100 will be a waste of flash space if not using other 99.

Arrays in C++ must have their size defined at compile time. There is simply no way around this. If you want something that is resizeable at run-time then you must use a more complicated structure like an STL vector that can allocate memory dynamically. There's an ArduinoSTL port in the Library manager, but using dynamic allocation on a microcontroller can get dicey if you are constantly creating and destroying objects on the heap.

Alternately, if you just want the parent to have a reference to an array of children that is defined elsewhere, use a pointer. Arrays are trivially convertable to a pointer. Then you need a separate member variable to store the number of children so you don't overflow the array boundary.

Child *children;
size_t numChildren;

One possible answer would be to let the parent have a pointer to one child and implement the children as linked lists such that each child also has a pointer to its next sibling

How do you want to process this structure ? Using the parent node to access child nodes as in the example, or do you need to go also from a specific child to its parent ?

Jiggy-Ninja:
Arrays in C++ must have their size defined at compile time. There is simply no way around this.

Strictly speaking, this is not correct. Arrays can be created during program execution without having to determine the size at compile-time.

"Arrays can be created during program execution without having to determine the size at compile-time."

Can you post a working example of that? As this comes up pretty frequently.

CrossRoads:
you post a working example of that? As this comes up pretty frequently.

void setup() 
{
  Serial.begin(9600);
  randomSeed(analogRead(A4));
}

void loop() 
{
  makeAnArray(random(20));
  delay(1000);
}

void makeAnArray(size_t size)
{
  int myArray[size];  // size is not known at compile time.
  Serial.println(sizeof(myArray)/sizeof(myArray[0]));
}

:wink:

Strictly speaking, not allowed in C++11 or older, allowed in C++14 (and C99):

>> avr-g++ -Wall -Wextra -pedantic -std=gnu++11 ... arry.ino

arry.ino:18:19: warning: ISO C++ forbids variable length array 'myArray' [-Wvla]
  int myArray[size];  // size is not known at compile time.


>> avr-g++ -Wall -Wextra -pedantic -std=gnu++14 ... arry.ino

(no warnings)

avr-gcc compiler

6.19 Arrays of Variable Length

Variable-length automatic arrays are allowed in ISO C99, and as an extension GCC accepts them in C90 mode and in C++. These arrays are declared like any other automatic arrays, but with a length that is not a constant expression. The storage is allocated at the point of declaration and deallocated when the block scope containing the declaration exits.

Yep, notice the -pedantic in the flags. :wink:

BulldogLowell:
Strictly speaking, this is not correct. Arrays can be created during program execution without having to determine the size at compile-time.

Good catch, thank you for the correction.

This doesn't help the OP though, because the array size must still be known when the array is declared and allocated. xmen will need to either use my pointer idea or, if it must be resized at run-time, a dynamic solution like a vector or linked list.

Jiggy-Ninja:
Good catch, thank you for the correction.

This doesn't help the OP though, because the array size must still be known when the array is declared and allocated. xmen will need to either use my pointer idea or, if it must be resized at run-time, a dynamic solution like a vector or linked list.

Im using std:vector, much better.