C

Structs & Unions

An array groups many values of the same type. A struct is the opposite: it groups several values of different types into one new, custom type — a sensor reading's timestamp, value, and status flag, bundled as a single unit instead of three separate loose variables. A union looks similar but means something almost opposite, covered second.

Quick reference
What it is
struct: a custom type bundling several named fields, each with its own type and its own storage. union: several named fields sharing the exact same storage.
Mental model
A struct is a form with several separate labeled boxes to fill in. A union is one box with several different labels you can read it under — only one label's data is valid at a time.
Key numbers
A struct's size is roughly the sum of its fields' sizes (plus possible padding); a union's size is exactly its largest field's size, no more.
Reach for it when
struct whenever several values conceptually belong together (a point's x/y, a sensor reading's fields); union specifically when you need to interpret the same bytes more than one way, never both at once.

Declaring and using a struct

struct SensorReading {
    int timestamp;
    float value;
    char status;
};

struct SensorReading r1 = {1000, 23.5f, 'O'};   // O for "OK"

printf("%d\n", r1.timestamp);   // 1000 — the DOT operator accesses a field
printf("%.1f\n", r1.value);     // 23.5
r1.status = 'E';                 // fields are ordinary, assignable variables

Each field is accessed with the dot operator (.) — r1.value reads exactly the way it sounds: "r1's value field."

A struct's memory layout

Unlike a union, every field in a struct gets its own separate storage, laid out one after another:

struct SensorReading lays timestamp, value, and status out one after another in memory, each with its own separate storage struct SensorReading r1 — each field owns its own bytes timestamp int, 4 bytes value float, 4 bytes status char, 1 byte (+ padding) Total size ≈ sum of fields — often rounded up for alignment (see Embedded C's Alignment & Padding)
All three fields exist simultaneously and independently — changing status has zero effect on timestamp or value.

Structs with arrays, and arrays of structs

struct SensorReading history[10];   // an array of 10 whole structs

history[0].timestamp = 1000;
history[0].value = 23.5f;
history[3].status = 'E';

for (int i = 0; i < 10; i++) {
    printf("%d: %.1f\n", history[i].timestamp, history[i].value);
}

This combination — an array of structs — is one of the most common real data structures in C: a fixed history of readings, a table of records, a list of connected devices.

Unions

A union looks exactly like a struct syntactically, but every field shares the exact same memory — writing one field overwrites whatever was in every other field, because there's only ever one shared block of storage underneath:

union Value {
    int as_int;
    float as_float;
    char as_bytes[4];
};

union Value v;
v.as_int = 65;
printf("%d\n", v.as_int);   // 65
printf("%d\n", v.as_bytes[0]);   // some byte of 65's representation — as_int and as_bytes are THE SAME memory
union Value has one shared 4-byte block of memory, interpreted as as_int, as_float, or as_bytes depending on which field is accessed 4 shared bytes union Value — ONE block, three labels as_int, as_float, and as_bytes all read/write these SAME 4 bytes
Unlike the struct above, there is only one box here — a union's size is its single largest field, not the sum of all of them.

Real-world applications

Gotchas

Field notes