An array in Arduino is a contiguous block of memory used to store multiple variables of the same data type under a single name. Instead of declaring eight separate integer variables for an LED bar graph, you declare one array and access elements via an index (0 through 7). This project walks through building an 8-channel LED voltmeter to demonstrate array declaration, iteration, and bounds-checking, followed by a deep dive into the most notorious compiler and runtime errors associated with C++ arrays on AVR microcontrollers.
Project Overview & Parts List
This build maps an analog voltage (0-5V) from a potentiometer to an 8-LED bar graph. As the voltage increases, more LEDs illuminate. We use a 1D integer array to hold the pin numbers, which allows us to loop through the hardware pins cleanly without hardcoding eight separate digitalWrite() calls.
Bill of Materials
- Microcontroller: Arduino Uno R3 (Genuine ~$27.00 or ATmega328P clone ~$12.00)
- LEDs: 8x 5mm Through-hole LEDs (4x Red, 4x Green)
- Current Limiting Resistors: 8x 220Ω 1/4W Carbon Film (or 330Ω if using high-brightness LEDs)
- Input: 10kΩ Linear Taper Potentiometer (B10K)
- Wiring: 22 AWG solid core jumper wires, half-size breadboard
Pin Mapping & Wiring
Wire the potentiometer's outer pins to 5V and GND, with the wiper (center pin) to A0. Wire each LED anode to a digital pin through a 220Ω resistor, and tie all cathodes to the breadboard's ground rail.
| Component | Arduino Pin | Notes |
|---|---|---|
| LED 1 (Red) | Digital 2 | Array Index 0 |
| LED 2 (Red) | Digital 3 | Array Index 1 |
| LED 3 (Red) | Digital 4 | Array Index 2 |
| LED 4 (Red) | Digital 5 | Array Index 3 |
| LED 5 (Green) | Digital 6 | Array Index 4 |
| LED 6 (Green) | Digital 7 | Array Index 5 |
| LED 7 (Green) | Digital 8 | Array Index 6 |
| LED 8 (Green) | Digital 9 | Array Index 7 |
| Potentiometer Wiper | Analog A0 | 0-5V Input |
Complete Arduino Array Code
The following code is fully compilable for the Arduino Uno R3. It includes explicit bounds-checking to prevent memory corruption and uses the sizeof() operator to dynamically calculate the array length, ensuring the code remains robust if you add or remove LEDs later.
/*
* 8-Channel LED Bar Graph Voltmeter
* Target: Arduino Uno R3 (ATmega328P)
* Demonstrates: 1D Arrays, sizeof() length calculation, bounds checking
*/
// Hardware Pin Definitions
const int POT_PIN = A0;
// Array declaration: stores the digital pins connected to the LEDs
const int LED_PINS[] = {2, 3, 4, 5, 6, 7, 8, 9};
// Calculate the number of elements in the array safely.
// sizeof(LED_PINS) returns total bytes (16 bytes for 8 ints).
// sizeof(LED_PINS[0]) returns bytes per element (2 bytes for 1 int).
// 16 / 2 = 8 elements.
const int LED_COUNT = sizeof(LED_PINS) / sizeof(LED_PINS[0]);
void setup() {
Serial.begin(115200);
// Initialize all LED pins as outputs using a range-based for loop
for (int i = 0; i < LED_COUNT; i++) {
pinMode(LED_PINS[i], OUTPUT);
digitalWrite(LED_PINS[i], LOW); // Ensure all start OFF
}
pinMode(POT_PIN, INPUT);
Serial.print("Initialized ");
Serial.print(LED_COUNT);
Serial.println(" LED channels.");
}
void loop() {
// Read analog voltage (0-1023)
int rawAdc = analogRead(POT_PIN);
// Map the ADC value to an array index (0 to LED_COUNT - 1)
// We map to LED_COUNT - 1 because the max valid index is 7.
int targetIndex = map(rawAdc, 0, 1023, 0, LED_COUNT - 1);
// ERROR HANDLING: Bounds checking to prevent out-of-bounds array access
if (targetIndex >= 0 && targetIndex < LED_COUNT) {
updateBarGraph(targetIndex);
} else {
// Fallback safety state if mapping yields unexpected results
Serial.println("Error: Index out of bounds. Turning off all LEDs.");
updateBarGraph(-1);
}
delay(50); // Small delay for ADC stability and to prevent flickering
}
// Function to update the LED states
void updateBarGraph(int activeIndex) {
for (int i = 0; i < LED_COUNT; i++) {
if (i <= activeIndex) {
digitalWrite(LED_PINS[i], HIGH);
} else {
digitalWrite(LED_PINS[i], LOW);
}
}
}
Debugging Common Array Errors
Arrays in C++ (and by extension, Arduino) do not have native bounds checking. If you try to access LED_PINS[10] on an 8-element array, the compiler will not stop you. Instead, the microcontroller will read whatever data happens to be sitting in the SRAM adjacent to the array, leading to erratic behavior. Here is how to diagnose the most common array-related failures.
The Compiler Error: error: array subscript is not an integer
You will see this exact error string if you attempt to use a floating-point number as an array index. For example, if you divide an analog read by a float and forget to cast it back to an integer:
float index = analogRead(A0) / 128.0;
digitalWrite(LED_PINS[index], HIGH); // Triggers the error
Ranked Causes & Fixes:
- Missing cast: You performed math that resulted in a
floatordouble. Fix: Wrap the calculation in(int)or use integer math (e.g.,map()). - Wrong variable type: You declared your index variable as a
floatearlier in the sketch. Fix: Change the variable declaration tointorbyte. - Typo in index variable: You accidentally typed a character or string literal inside the brackets. Fix: Verify the variable inside the
[]is a numeric type.
The Runtime Error: Random Resets or Serial Gibberish
If your code compiles perfectly but the Arduino randomly restarts, the watchdog timer triggers, or your Serial monitor prints gibberish, you have an out-of-bounds array write. Writing to myArray[15] when the array only has 10 elements overwrites adjacent memory. If it overwrites the stack or heap, the microcontroller's execution pointer gets corrupted, causing a crash.
- Verify your loop limits: Ensure your
forloops use< LED_COUNTand not<= LED_COUNT. The latter causes an off-by-one error, accessing memory one slot past the end of the array. - Check the
map()function bounds: Ensure the upper bound of yourmap()function isARRAY_SIZE - 1, notARRAY_SIZE. - Inspect SRAM usage: If your array is massive (e.g.,
int dataLog[2000]), it consumes 4000 bytes, exceeding the Uno's 2048-byte SRAM limit. This causes immediate stack collision. Check the IDE's "Global variables use" metric at the bottom of the console.
Extending and Simplifying Your Build
Once you have the basic 1D array working, you will eventually need to pass arrays to functions or store large datasets. This is where standard Arduino tutorials fall short.
The Pointer Decay Trap
If you try to pass LED_PINS to a custom function and use sizeof() inside that function to find the length, it will fail. When an array is passed to a function in C++, it "decays" into a pointer to its first element. sizeof() will return the size of the pointer (2 bytes on an Uno), not the array.
The Fix: Always pass the array length as a secondary parameter to your functions:
void processArray(int* myArray, int length) {
for(int i=0; i<length; i++) {
// Safe iteration
}
}
Storing Large Arrays in PROGMEM
If you are building a project that requires a massive lookup table (like a sine wave for a DAC or a large bitmap for an OLED), do not store it in SRAM. Use the avr-libc PROGMEM library to store the array in the ATmega328P's 32KB Flash memory. You will need to use pgm_read_byte() or pgm_read_word() to fetch the data at runtime, but it frees up your precious RAM for stack operations.
Using std::array (Modern C++)
If you want to avoid pointer decay entirely and enable compiler bounds-checking, you can use the modern C++ std::array included in recent Arduino AVR cores. It requires #include <array> at the top of your sketch. Unlike raw C-arrays, std::array knows its own size and can be passed to functions without decaying into a pointer.
Frequently Asked Questions
How do I pass an array to a function in Arduino?
You pass an array to a function by passing a pointer to its first element. In the function signature, use either int myArray[] or int* myArray—the compiler treats them identically. Because the function does not know the size of the array, you must always pass the length as a separate integer argument (e.g., void myFunc(int* arr, int len)). For more details on variable scopes, refer to the official Arduino Language Reference.
What is the maximum array size limit in Arduino?
There is no hard-coded limit enforced by the compiler for array size, but you are strictly bound by the microcontroller's physical SRAM. The Arduino Uno R3 (ATmega328P) has 2048 bytes of SRAM. However, the system uses a portion of this for the stack, heap, and serial buffers. As a rule of thumb, your global arrays should not exceed 1500 bytes total (e.g., an int array of 750 elements, or a byte array of 1500 elements). If you exceed this, the program will compile but crash at runtime due to stack overflow.
How do I initialize an array in Arduino with all zeros?
If you declare a global array without initializing it (e.g., int myData[50]; outside of setup()), the C++ standard guarantees it will be automatically zero-initialized by the compiler before setup() runs. If you declare it locally inside a function, it will contain garbage data. To explicitly initialize a local array with zeros, use the syntax int myData[50] = {0};. The compiler sets the first element to 0 and automatically zero-fills the rest of the array.






