Pitfalls of NOT declaring the size of an array?

When I declare the size of each array in my sketch and compile it, the Arduino IDE gives me the percentage of dynamic memory used by the sketch. If I don't explicitly declare the size of each array, that size goes down when I compile the sketch. It seems this might be a way to avoid the warnings about running out of memory ... but I have a bad feeling about this.

What are the potential pitfalls of NOT declaring the size of each array in my sketch?

Welcome to the forum.

I presume you mean:

uint8_t arr[] {1, 2, 3};

vs.

uint8_t arr[3] {1, 2, 3};

If you can be sure the array never needs to hold more than three elements, I would prefer the former.

if you are going to store data in an array type structure at some point you have to reserve memory for it
you can do this by

  1. defining the size in the source code (this assumes you know what you require before execution)
  2. creating it at run time using malloc()
  3. creating it at run time by using a container such as std::vector

Sounds like a wrong assumption.
IMHO you got different results based on different optimization of the compiler.

Show two compileable examples and some pro's can check (not me...).

More specifically ... what is the advantage of this:

int arr[64];

versus this:

in arr[] = {};

first will works, second won't :slight_smile:

The definition in the form of

int arr[] = {};

is completely non-sense, because defined the array of zero size

The second one works in for me in the sketch I've been working on. Not sure why, but it does.

It may occasionally work, depending on other variables.
Using such a notation is exactly the same as defining an array with a size of 10, but using up to 20 elements

I would prefer the former.

Why?

if you are going to store data in an array type structure at some point you have to reserve memory for it

It seems like there is a 4th option here - to let the MCU manage the memory allocation. Probably a bad idea.

Sounds like a wrong assumption.

It's not an assumption. I'm just changing the code to either define or not define the size of the arrays and I see a reduction in dynamic memory allocation reported by the compiler.

Actually, in my experience declaring the size and trying utilize space outside of the defines area yields a different result than not defining the array at all.

I did not said that you not defined array at all - you define it as array with zero size.
So it will exactly as

I've had that experience.

And I've had the other experience, especially with ESP32's. Where the array is accessed 'correctly' until a new task is added.

Because there can never be a discrepancy between the initial size of the array and the number of elements initially assigned to it.

I am not sure the following is a good rule of thumb, but I follow it anyway: If the compiler can figure something out, then let it do so.

When you get further with the sketch you are working on and all kindsa tots inexplicable hell starts breaking loose, revisit the idea that anything like what you describe as working was at all. Working.

You just lucky now. Luck shoukd not enter into writing code that works, really works.

a7

To expand on this, when the -pedantic compiler flag is used, the following error is raised:

x.cc:5:9: error: zero-size array β€˜arr’
    5 | int arr[] = {};

Of course, you see a decrease in size - in the second case you do not allocate memory for your arrays at all!

Yes, it definitely the way to avoid warnings... but only warnings, not the problem itself.

Thanks ... this is what I believed to be going on. Just trying to get to the root of a nagging curiosity.

I've found potential buffer overflows in code that ran continuously for 10 years. I'd say we got lucky :laughing:

LOL

There are multiple ways that an array can be constructed and initialized.
For a line like const int myArray[]={1, 2, 3}; the compiler could see that you needed 3*sizeof(int) bytes, then place those values in PROGMEM and link that address for every reference. "One and done".
Another way (without using const) is to allocate the bytes, take the values that were compiled into the code and copy them to the reserved memory.
Similarly, the compiler could allocate memory at runtime startup (data section or on stack) and copy the values. In both of these last two examples, two copies of your data exist, one in the program section, a copy in the data section (or on the stack) and additional code that runs before setup() is linked in to perform the initialization.

If you only ever mean to read those array values, create them using const. Not all boards can utilize the values straight from the code section, but even without using the PROGMEM macro, the AVR and many other boards get compiled into program memory automatically if you use the const specifier.

  • Wes