Structures, Unions and Enums — Revision Notes
Structures, unions, and enums test whether you understand memory layout — especially struct padding and the fact that a union shares one block of memory. These are favourite "what is sizeof?" trick questions in placement written tests.
struct
A struct groups different types into one record; each member has its own storage, laid out in declaration order. The compiler inserts padding so members meet alignment requirements, so sizeof(struct) is often larger than the sum of member sizes.
union
A union gives all members the same starting address — they overlap and share one block. Its size equals the largest member. Writing one member and reading another reinterprets the bytes (useful for type-punning, dangerous if misused). Only one member is meaningfully "active" at a time.
enum
An enum is a set of named integer constants, starting at 0 by default and incrementing by 1 unless assigned. It improves readability over magic numbers.
| Feature | struct | union |
|---|---|---|
| Memory | sum + padding | size of largest member |
| Members active | all at once | one at a time |
| Use | records | space-saving / type-punning |
Exam Tricks & Tips
- 🎯
sizeof(struct)≠ sum of members due to padding/alignment — the total is rounded up to the largest member's alignment. - 🎯 Reorder struct members largest-to-smallest to minimise padding and shrink the struct.
- 🎯 A
union's size is the size of its biggest member; all members share address 0 of the block. - 🎯 Writing one union member and reading another gives implementation-defined reinterpreted bytes — not conversion.
- 🎯
enumvalues start at 0 and auto-increment; assigning one (enum {A=5, B, C}→ B is 6) shifts the rest. - 🎯 Use
->to access members through a struct pointer,.for a struct object. - ❌ Common mistake: assuming
sizeofof a struct equals the sum of its fields, forgetting padding.
Expected pattern
"Compute sizeof of this struct" (padding), "what does the union print after writing member A and reading member B?", enum auto-increment values, and . vs -> selection.
Quick recap
struct = separate storage per member + padding; union = shared memory sized to the largest member (one active at a time); enum = auto-incrementing named integers from 0. Reorder struct fields to cut padding; use -> on pointers.
Structures, Unions and Enums — Flashcards
Cover the answer, recall, then check. 11 cards on C structs, unions and enums.
Q1. How do struct and union differ in memory usage?
A1. A struct gives each member its own storage (sum + padding); a union overlaps all members in one block sized to the largest.
Q2. Why is sizeof(struct) often larger than the sum of its members?
A2. The compiler inserts padding bytes for alignment, and rounds the total up to the largest member's alignment.
Q3. What is the size of a union?
A3. The size of its largest member (all members share the same starting address).
Q4. How can you reduce padding in a struct?
A4. Reorder members from largest to smallest data type to minimise inserted padding.
Q5. What happens if you write one union member and read a different one?
A5. You reinterpret the same bytes — the result is implementation-defined (type-punning), not a value conversion.
Q6. What is the default starting value of an enum?
A6. 0, incrementing by 1 for each subsequent constant unless explicitly assigned.
Q7. In enum {A=5, B, C}; what are B and C?
A7. B = 6 and C = 7 — auto-increment continues from the assigned value.
Q8. When do you use -> vs . for struct members?
A8. -> to access a member through a struct pointer; . to access it through a struct object/instance.
Q9. How many union members are meaningfully valid at once?
A9. One — writing a new member overwrites the shared storage of the others.
Q10. Why use an enum instead of magic numbers?
A10. It gives readable, named integer constants, improving clarity and reducing error-prone literals.
Q11. Can a struct contain a pointer to its own type?
A11. Yes — a self-referential struct (e.g. a linked-list node with a next pointer to the same struct type).
Structures, Unions and Enums
When one value is not enough, C gives you three ways to package data: struct (all members together), union (members overlapping), and enum (named integer constants). Choosing among them is a memory-model decision.
Core idea: a struct gives each member its own storage laid out in order (so its size is the sum, plus padding); a union overlays all members in the same storage (so its size is the largest member, and only one is valid at a time); an enum is just readable names for int values.
How it works
Beginner — struct as a record
struct Point { int x; int y; };
struct Point p = {3, 4};
p.x = 5; // dot for a value; p->x for a pointer
Members are stored in declaration order. sizeof(struct Point) is at least the sum of member sizes.
Intermediate — padding and alignment
The compiler inserts padding so each member sits at an address that is a multiple of its alignment (an int typically aligns to 4, a double to 8). This makes sizeof larger than the naive sum:
struct S { char c; int i; }; // sizeof is 8, not 5:
// [c][pad][pad][pad][i i i i] — 3 bytes padding after c so i is 4-aligned
Why: unaligned access is slow or illegal on some CPUs. Ordering members largest-to-smallest often shrinks a struct by reducing padding.
Advanced — union for overlapping data
union Value { int i; float f; char bytes[4]; };
union Value v;
v.i = 1; // writing i and then reading f is meaningless
All members share the same 4 bytes, so sizeof(union Value) is 4 (the largest member). Unions save memory when a value is "one of several types" — often paired with an enum tag that records which member is currently live (a "tagged union"). enum constants default to 0, 1, 2… but can be assigned: enum Level { LOW=1, MID, HIGH }; gives 1, 2, 3.
Worked example — tagged union
enum Kind { INT_K, FLT_K };
struct Var {
enum Kind kind; // which member is valid
union { int i; float f; } data;
};
struct Var a = { INT_K, .data.i = 42 };
if (a.kind == INT_K) printf("%d\n", a.data.i); // 42
The enum tag tells safe code which union member to read. Reading a.data.f here would reinterpret the int's bits as a float — a bug the tag exists to prevent.
Interview & exam relevance
Very common: "compute sizeof of a struct with padding", "difference between struct and union" (separate vs shared storage → size = sum vs size = max), and "what is a tagged union / when to use a union". Structure padding questions test whether you truly understand memory layout.
Tricks & gotchas
- Use
.on a struct value,->on a struct pointer (p->xis(*p).x). - Reorder members from largest to smallest type to minimise padding.
- In a union only the last written member is valid; reading another is type-punning (implementation-defined).
- Mnemonic: "struct = suitcase (all fit), union = one seat (share)."
Assuming sizeof(struct) equals the sum of its members' sizes. Alignment padding almost always makes it larger, and the exact value depends on member order. Writing serialization code that trusts the naive sum will read or write the wrong number of bytes.
- ✓-
struct: members have separate storage in order; size ≈ sum + padding. - ✓-
union: members overlap; size = largest member; only one valid at a time. - ✓- Padding aligns members; reorder large→small to shrink a struct.
- ✓-
enumnames integer constants (default 0,1,2…; assignable). - ✓- Tagged union =
enumtag +unionpayload for type-safe variants.
- ✓Pick the container by storage model:
structwhen you need every field at once (pay padding),unionwhen only one field is live at a time (save memory, track it with anenumtag), andenumto give integers meaningful names.
Structures, Unions and Enums — Worked Example
Worked Example
Problem: On a 64-bit system with 4-byte int and 8-byte alignment, compute sizeof(struct S) and sizeof(union U), and explain padding.
struct S { char a; int b; char c; }; // struct
union U { char a; int b; double d; }; // union
enum Color { RED, GREEN = 5, BLUE }; // enum values?
Solution:
Struct members are laid out in order, each aligned to its own alignment; the struct's size is padded up to a multiple of its largest member's alignment.
- char a at offset 0 (1 byte).
- int b needs 4-byte alignment, so 3 padding bytes follow a; b occupies offsets 4..7.
- char c at offset 8 (1 byte).
- The struct must be a multiple of 4 (alignment of its largest member, int), so 3 trailing padding bytes are added → total 12.
So sizeof(struct S) = 12. Reordering to { int b; char a; char c; } would need only 8 bytes — a real optimisation.
A union overlays all members in the same storage, so its size is the size of its largest member (rounded up for alignment). Largest here is double (8 bytes), so sizeof(union U) = 8. Only one member is valid at a time.
For the enum, values auto-increment from 0 unless assigned: RED = 0. GREEN is explicitly 5, and BLUE continues from GREEN, so BLUE = 6.
Answer: sizeof(struct S) = 12 (due to alignment padding), sizeof(union U) = 8 (largest member), RED=0, GREEN=5, BLUE=6.
- ✓- Struct size includes padding for member alignment and trailing padding to the struct's alignment; member order affects size.
- ✓- A union's size equals its largest member; members share storage, only one valid at a time.
- ✓- Enum constants auto-increment from the previous value (default start 0).