Source: https://mokxi.com/learn/arduino-struct
Updated: 2026-10-25

Learn

# Arduino struct, on three lamps that blink at their own rates

Written by the Mokxi team, updated October 25, 2026

Start building free

Or see every lesson.

- 455 parts on the bench
- 43 boards running now
- 1.00x real time, on every board

Hold the button

Each lamp keeps its pin, its rate, when it last changed and whether it is on, in one Lamp.

A struct gives one name to several values that belong together. struct Lamp { int pin; unsigned long everyMs; bool on; }; makes a new type called Lamp, and every Lamp you make carries its own pin, rate and state. Read or set one member with a dot, as in red.pin or red.on = true, and keep a whole list of them in one array of structs.

The circuit above is three lamps on an Uno, each blinking at its own rate. Press Run. The serial monitor prints "lamp on pin 13 every 250 ms", then the same for pins 12 and 11 at 400 and 650 ms, and "sizeof(Lamp) = 11". The sketch keeps each lamp’s pin, rate, last change and state in one struct, and loop() walks the array.

Below is how to define and fill a struct, return two values from a function, pass one by reference, how big one is, saving one to EEPROM and the errors people meet first, each run on an Uno with what it printed.

Want the step-by-step version? The lesson "Things that belong together" walks through this with checkpoints.
Open the lesson

## Define it, then make some

Here is the struct in the sketch running above, and the array that makes three of them. The values in each pair of braces fill the members in the order they are written: the pin, the rate, the last time it changed and whether it is on. So lamps[1].everyMs is 400 and lamps[2].pin is 11.

Adding a fourth lamp is one more line in the list. loop() counts the array with sizeof(lamps) / sizeof(lamps[0]), so it picks the new lamp up without another change. Six loose arrays of pins, rates and states would need an edit in six places.

A struct definition ends with a semicolon after its closing brace. Leave it out and the build stops: clang says expected ';' after struct, and GCC says expected ';' after struct definition.

firmware/uno/examples/cppstruct (the lamps running above)

## Return two values from one function

A function returns one value, but that value can be a struct, which is the usual answer to "how do I return two values from a function". The sketch below finds the lowest and highest of five readings in one pass and hands both back in a Range. It printed "low 471, high 530".

Lowest and highest, in one Range

## Pass it by reference to change it

A struct handed to a function is copied, like an int. toggleCopy() below flips its own copy and the caller’s lamp stays off, so the first line printed 0. Put & after the type and the function gets the caller’s lamp itself: toggle() printed 1.

A reference also saves copying a large struct, which matters with 2 KB of RAM. When the function only reads the struct, say so with const: void show(const Lamp &lamp). With a pointer to a struct, use an arrow instead of the dot: Lamp *p = &lamps[1]; p->on = false;.

A copy, then the lamp itself

## How big is a struct?

sizeof(Lamp) printed 11 on the Uno: 2 bytes for the int, 4 each for the two unsigned longs and 1 for the bool. The Uno’s chip packs members one after another with no gaps. The same struct printed 16 on an ESP32-C3, where an int is 4 bytes and members are lined up on 4-byte boundaries. Count the bytes before sending a struct from one board to another.

## Save a struct to EEPROM

EEPROM.put() writes a whole struct, byte by byte, and EEPROM.get() reads it back into a variable of the same type. The sketch below saved two settings and read them back as "brightness 180, mode 2". The struct is 3 bytes, so the next thing saved can start at address 3. On a real board those bytes survive a power cut, which makes a struct the tidy way to keep settings.

Two settings in one put()

## The errors people meet first

Too many values: a Lamp given five values when it has four members stopped the build with excess elements in struct initializer. GCC says too many initializers for 'Lamp'.

Used before it exists: a struct has to be defined above the first line that uses it. With struct Reading written under setup(), the line in setup() that made one stopped with unknown type name 'Reading', and GCC says 'Reading' was not declared in this scope. Move the definition to the top of the sketch, under the #include lines.

Comparing two: if (a == b) with two Lamps stopped with invalid operands to binary expression ('Lamp' and 'Lamp'); GCC says no match for 'operator=='. C++ does not compare structs for you. Compare the members you care about, a.pin == b.pin && a.on == b.on, or put that line in a function.

## Questions

What is a struct in Arduino?

A type you make yourself that groups several values under one name, such as a pin, a rate and a state for one lamp. It is plain C++, so it works on every board Arduino supports, and each variable of that type has its own copy of every member.

How do I make an array of structs?

Define the struct, then declare an array of it with one pair of braces per element: Lamp lamps[] = {{13, 250, 0, false}, {12, 400, 0, false}}; Read a member with lamps[i].pin inside a for loop.

How do I return two values from an Arduino function?

Return a struct that holds both, as rangeOf() does with a low and a high here. Or pass the variables in by reference, with an & after each type, and let the function set them.

What is the difference between a struct and a class?

Only who can see the members by default. A struct’s members are public unless you say otherwise and a class’s are private. Both can hold functions as well as values; Arduino code tends to use struct for plain groups of values.

Why does my sketch say the struct was not declared?

The struct is defined below the line that first uses it. Move the definition to the top of the sketch, above setup() and above any function that takes or returns one.

Related

## Keep going

Arduino Array: Lists of Pins, Patterns and Notes Arduino Functions: Write It Once, Call It Anywhere Arduino Pointers Explained: & and * on an Uno Arduino EEPROM: Read, Write, put() and get() Arduino Data Types: int, long, float and byte Arduino State Machine: A Four-State Reaction Game The free Arduino simulator The online Arduino compiler

Sources

## Where the facts on this page come from

- cppreference: class and struct declarations
- Arduino: the EEPROM library

## Build this for real

Open the editor, change a value and watch the number move with it. Nothing to install, and no account needed.

Start building free Open the editor
