struct, union, enum, and typedef
The basic types give you single values, but real data comes in bundles: a point has an x and a y; a date has a day, month, and year. C lets you build your own compound types from the basic ones. The four tools for this are struct, union, enum, and typedef — they let you name a record, a shared slot, a set of options, and a shorthand, respectively.
A struct groups several named fields that all exist at once, laid out one after another: 'struct Point { int x; int y; };' is a record holding both an x and a y, accessed as p.x and p.y. A union also lists several fields but they SHARE the same memory, so only one is meaningful at a time — it is a way to view the same bytes as different types and is the size of its largest member. An enum defines a set of named integer constants, like 'enum Day { MON, TUE, WED };', giving readable names to a fixed list. A typedef simply creates an alias for an existing type: 'typedef struct Point Point;' lets you write Point instead of struct Point everywhere. (Structs may also contain bit-fields, packing several small values into the bits of one field, covered separately.)
Why this matters: structs are how C programs model the things they work with — files, network packets, tree nodes — turning loose variables into meaningful records. enums make code self-documenting and switchable. typedef tames verbose type names. The honest caution is about unions: because all members overlap, the language does not track which member is currently valid; reading a member you did not most recently write is generally not what you want (and reading a different member than was written is implementation-defined or worse). Discipline, usually a companion tag enum, is needed to use a union safely.
struct Point { int x; int y; }; typedef struct Point Point; /* now 'Point' is shorthand */ Point p = { 3, 4 }; /* p.x == 3, p.y == 4 */ enum Day { MON, TUE, WED }; /* MON==0, TUE==1, WED==2 */ union Value { int i; float f; }; /* i and f share the same bytes */
struct stores all fields at once; union overlaps them in shared memory; enum names integer constants; typedef gives a shorter alias.
A union's members share one block of memory, so only one is valid at a time and the language does not track which — track it yourself, usually with a companion enum tag. A struct's members each get their own storage and may have padding between them for alignment.