Arduino - Arrays
Arduino - Modern Array Handling
Section titled “Arduino - Modern Array Handling”An array is a fundamental data structure that stores a fixed-size, sequential collection of elements of the same data type. Think of it as a set of labeled boxes in a row, where each box holds a value of the same type (e.g., all integers).
Understanding Array Concepts
Section titled “Understanding Array Concepts”To access a specific element in an array, you use its name and an index. The index (or subscript) specifies the element’s position.
- Zero-Based Indexing: In C++ (the language of Arduino), array indexing starts at 0. The first element is at index 0, the second at index 1, and so on.
- Final Element: The last element’s index is always
arraySize - 1.
Let’s visualize an array named sensorReadings of type int with 5 elements:
Array name: sensorReadings
Index: [0] [1] [2] [3] [4] +-----+-----+-----+-----+-----+Value: | 452 | 455 | 450 | 458 | 454 | +-----+-----+-----+-----+-----+
// To access the value 450, you would use:sensorReadings[2]Declaring and Initializing Arrays
Section titled “Declaring and Initializing Arrays”You must declare an array before you can use it, specifying its type, name, and size. A modern best practice is to use a const or constexpr variable for the size to avoid magic numbers and make code easier to maintain.
// Best practice: Define the size as a constant.const int SENSOR_COUNT = 5;
// Declare an integer array with 5 elements.int sensorReadings[SENSOR_COUNT];Arrays can be initialized in several ways.
Example 1: Initialization using an Initializer List
Section titled “Example 1: Initialization using an Initializer List”The most common and concise method is to provide the values directly in the declaration.
// The compiler automatically infers the size from the list.int ledPins[] = {2, 3, 4, 5, 6};
void setup() { Serial.begin(9600);
Serial.println("Configuring LED pins...");
// A modern, safe way to loop through an array: range-based for loop for (int pin : ledPins) { pinMode(pin, OUTPUT); Serial.print("Pin "); Serial.print(pin); Serial.println(" configured as OUTPUT."); }}
void loop() { // Empty for this example}Example 2: Initialization using a Loop
Section titled “Example 2: Initialization using a Loop”Sometimes you need to initialize an array with calculated values. A for loop is perfect for this.
const int NUM_VALUES = 10;int squaredValues[NUM_VALUES];
void setup() { Serial.begin(9600);
// Initialize the array with the square of the index (i*i) for (int i = 0; i < NUM_VALUES; ++i) { squaredValues[i] = i * i; }
Serial.println("Array Initialized. Contents:"); // Print the array contents to verify for (int i = 0; i < NUM_VALUES; ++i) { Serial.print("Index "); Serial.print(i); Serial.print(": "); Serial.println(squaredValues[i]); }}
void loop() { // Empty for this example}Working with Arrays: A Practical Example
Section titled “Working with Arrays: A Practical Example”Example 3: Calculating the Average of Sensor Readings
Section titled “Example 3: Calculating the Average of Sensor Readings”This program calculates the average of a series of mock sensor readings stored in an array. It demonstrates iteration and a common calculation.
// Array of sensor readingsint sensorReadings[] = {87, 68, 94, 100, 83, 78, 85, 91, 76, 87};
// A robust way to calculate array size that adapts if you change the arrayconst int NUM_READINGS = sizeof(sensorReadings) / sizeof(sensorReadings[0]);
void setup() { Serial.begin(9600);
long total = 0; // Use 'long' for the total to avoid overflow with large arrays
// Sum the contents of the array for (int i = 0; i < NUM_READINGS; ++i) { total += sensorReadings[i]; }
// Calculate the average as a floating-point number float average = (float)total / NUM_READINGS;
Serial.print("Total of array elements: "); Serial.println(total); Serial.print("Number of readings: "); Serial.println(NUM_READINGS); Serial.print("Average reading: "); Serial.println(average);}
void loop() { // Main loop is empty because the calculation is only done once.}Expected Output
Section titled “Expected Output”Total of array elements: 849Number of readings: 10Average reading: 84.90Common Errors and Best Practices
Section titled “Common Errors and Best Practices”- Out-of-Bounds Error: The most common mistake is trying to access an element that doesn’t exist (e.g.,
myArray[5]in a 5-element array). C++ does not prevent this! It will read from or write to adjacent memory, leading to unpredictable crashes and bugs that are very hard to trace. Always be vigilant with your loop conditions (< size, not<= size). - Off-by-One Error: A classic mistake related to zero-based indexing. Forgetting that the last element is at
size - 1often leads to out-of-bounds access. - Use
sizeoffor Array Length: Thesizeof(array) / sizeof(array[0])pattern is the standard, robust way to determine the number of elements in an array. It automatically adapts if you add or remove elements from the initializer list. - Use Range-Based
forLoops: When you just need to read every element in an array, thefor (int element : myArray)syntax is cleaner and safer, as it eliminates the possibility of out-of-bounds errors.
Advanced Topics
Section titled “Advanced Topics”| Concept | Description |
|---|---|
| Multi-Dimensional Arrays | Arrays can have more than one dimension. For example, int table[3][4]; creates a 2D array (a grid or table) with 3 rows and 4 columns. These are useful for representing grids, matrices, or game boards. |
| Passing Arrays to Functions | You can pass an array to a function to operate on it. You typically pass the array itself (which acts as a pointer to the first element) and its size as a separate argument to prevent out-of-bounds access within the function. |
| Modern C++ Containers | For more advanced projects or on more powerful boards (like ESP32), consider using C++ Standard Library containers like std::array or std::vector. std::array is a fixed-size container with a similar memory footprint to a C-style array but with a more modern interface. std::vector is a dynamic array that can grow and shrink as needed. |