In this esp32 tutorial, we will check how to use variable length arrays on the Arduino core running on the ESP32. The tests of this tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 development board.
Introduction
In this esp32 tutorial, we will check how to use variable length arrays on the Arduino core running on the ESP32.
Variable length arrays are arrays that can be declared with a length that is not a constant expression [1]. Thus, this gives more flexibility to declare arrays when we don’t know their length at compile time.
One very important thing to take in consideration is that these arrays are allocated in the stack memory [2]. This means that we don’t need to worry about explicit memory allocation and de-allocation, even though the length of these arrays is not determined at compile time.
Naturally, this is an advantage in comparison to dynamic allocation of memory on the heap using, for example, the malloc function, which is commonly used when we don’t know the length of the array at compile time.
Furthermore, that kind of dynamic allocation in the heap in embedded systems should be avoided if possible (you can read a very interesting article about this here). So, the variable length arrays can be used as alternative.
Note however that variable length arrays also have some particularities that need to be carefully taken in consideration. One problem that they present is that they give no mechanism for checking if the stack size available was exceeded [3], meaning that we don’t have any way of handling that failure in our code.
Thus, we need to be careful using this feature and make sure that the dynamic value we will use for the array length doesn’t exceed the available stack.
Note that this is a feature of the C language and thus it is not specific from the ESP32 or even the Arduino environment. So, you should be able to use this feature in other microcontrollers. Variable length arrays were introduced in the C99 standard.
The tests of this ESP32 tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.
The code
In our code, we will compare the use of a variable length array versus the dynamic allocation of an array on the heap, using a malloc call.
For both cases, we will check the effect on the available heap memory. You can check here a detailed tutorial on how to get the available heap on the ESP32.
We will write all our code in the setup function. We will start by opening a serial connection to output the results of our program.
Serial.begin(115200);
Then, we will declare an integer variable called arrayLength that will store the dynamically generated length for the array.
In order for us to confirm that we can really use a value not known at compile time and that this feature is not only some compiler functionality that gets the value of the expression for the array length, we will use a random value for it. You can check here a tutorial on how to generate random numbers on the ESP32.
So, we will generate a random number between 98 and 100 for the length of our array. Note that, as mentioned in the introductory section, we need to be careful with the maximum length of the array to avoid exceeding the stack available size.
You can change this randomly assigned value to a big number to see the stack exceeding message generated by the core.
int arrayLength = random(98,100);
Now we will print the current size of the heap, so we can track if some change will occur from our declarations.
We get the free heap of the ESP32 by calling the getFreeHeap method on the ESP variable, which is available by default in our code without the need for includes. This method will return the free heap in bytes.
Serial.print("Heap before variable size array: ");
Serial.println(ESP.getFreeHeap());
After this we will declare our variable length array, using the variable that stored the number randomly generated.
int stackArray[arrayLength];
After this, we will print the free heap again in order to later confirm that the array was not allocated there.
Serial.print("Heap after variable size array: ");
Serial.println(ESP.getFreeHeap());
Now we will repeat the same approach but for an array allocated in the heap, using the malloc function. This function receives as input the size of the memory block we want to allocate, in bytes [4].
In our case, we want an array with the length defined in the arrayLength variable. Thus, we will multiply that value by the number of bytes a int occupies. We can get the number of bytes of an int using the sizeof operator.
We also need to make a cast to a pointer to int, since the malloc function returns a generic pointer to void [4] and the cast needs to be explicit..
Serial.print("Heap before malloc: ");
Serial.println(ESP.getFreeHeap());
int * heapArray =(int *) malloc(arrayLength*sizeof(int));
Serial.print("Heap after malloc: ");
Serial.println(ESP.getFreeHeap());
All the code we need for our validation is already written. Nonetheless, we will need to use these declared arrays to do something or they will be removed due to compiler optimizations, which means that the calls to get the free heap would return the same value even though we are allocating memory with the malloc.
Thus, we will finalize our code by iterating both arrays to initialize their values and print them to the serial port. The final full code can be seen below and already includes this additional part.
void setup() {
Serial.begin(115200);
int arrayLength = random(98,100);
Serial.print("Heap before variable size array: ");
Serial.println(ESP.getFreeHeap());
int stackArray[arrayLength];
Serial.print("Heap after variable size array: ");
Serial.println(ESP.getFreeHeap());
Serial.print("Heap before malloc: ");
Serial.println(ESP.getFreeHeap());
int * heapArray =(int *) malloc(arrayLength*sizeof(int));
Serial.print("Heap after malloc: ");
Serial.println(ESP.getFreeHeap());
for(int i= 0; i<arrayLength; i++){
heapArray[i] = i;
stackArray[i]=i;
Serial.print(heapArray[i]);
Serial.print(stackArray[i]);
}
}
void loop() {}
Testing the code
To test the code, simply compile it and upload it to your ESP32 using the Arduino IDE. Then, open the serial monitor.
You should get an output similar to the one illustrated in figure 1.
Figure 1 – Output of the comparison program.
As we can see, the variable length array declaration had no impact on the available heap, meaning it was indeed allocated on the stack, as expected. On the other hand, after using the malloc, the heap available decreased.For curiosity, figure 2 shows the result of running the same code but without the final loop. As can be seen, the size of the heap always stays the same, which means that the malloc call had no effect. Most likely, the compiler ignored those instructions since the variables wouldn’t be used.
Figure 2 – Running the program without the final loop.