alignment and padding
You might expect a struct's fields to sit back-to-back with no gaps, but they often do not. The CPU prefers — and on some machines requires — that each kind of value start at an address that is a neat multiple of its size. Alignment is that rule, and padding is the unused filler bytes the compiler inserts to keep every field properly aligned.
Concretely, a 4-byte int is naturally aligned when its address is a multiple of 4 (like 0x1000 or 0x1004), and an 8-byte value at a multiple of 8. When you lay out a struct, the compiler may have to nudge a field forward to meet its alignment, leaving padding bytes in the gap; it may also add tail padding so that, in an array of the struct, every element stays aligned. This is why sizeof a struct can be larger than the sum of its fields, and why the order of fields matters: putting the widest members first, or grouping by size, can shrink a struct by eliminating internal padding. The alignment requirement of a type is reported by alignof, and the rule of thumb is that a type's alignment equals the size of its largest scalar member.
Why care? Aligned access is faster, and on some architectures a misaligned access faults outright; that is also why malloc returns memory suitably aligned for any type. The honest caveat is that the exact padding is implementation-defined — it depends on the target's ABI — so you should never assume a particular layout, never rely on the gaps holding any value, and never compare two struct values byte-by-byte (with memcmp) expecting the padding to match, because padding bytes can hold arbitrary leftovers.
struct S { char c; int n; }; often has sizeof(struct S) == 8, not 5: a char (1 byte) at offset 0, then 3 padding bytes, then int n at offset 4 so it is 4-byte aligned. Reorder as { int n; char c; } and you still get 8 (tail padding for arrays).
Padding makes a struct larger than the sum of its fields; field order matters.
Exact padding and alignment are implementation- and ABI-defined, not guaranteed by the C standard, so never hardcode offsets, never assume padding bytes hold zero, and avoid memcmp on whole structs — the padding bytes may differ even when all the real fields are equal.