Introduction
A structure groups values of different types into one object, such as a student record with a name and marks, or a list node with a key and a pointer to the next node. A union lets several members share the same storage, so that the object holds one of them at a time. An enumeration gives names to a set of integer constants.
Structures are the building blocks of every linked data structure in this subject: linked lists, trees, and graph adjacency lists. The usual points of care are member access through pointers, copying semantics, and the size of a structure once padding is taken into account.
Conventions: C11, gcc on x86-64 Linux. On this platform each basic type is aligned to its own size (char 1, short 2, int 4, long, double and pointers 8), as reported by _Alignof. All sizes and offsets below depend on this alignment assumption; a question that states another one must be solved with its rule.
Prerequisites
- Pointers:
&,*, pointer arithmetic. - C Program Structure and Data Types: sizes of basic types.
Core concepts
Declaring and using structures
struct point { int x, y; }; /* structure tag: point */
struct point p = {3, 4}; /* positional initialiser */
struct point q = { .y = 9 }; /* designated (C99): q.x is 0 */
typedef struct node { int key; struct node *next; } Node; /* alias Node */- Members are accessed with
.on a structure and with->on a pointer to a structure:ptr->keymeans(*ptr).key. The parentheses matter, because.binds tighter than unary*:*ptr.keymeans*(ptr.key). - Members not mentioned in an initialiser are set to zero.
- Assignment copies every member: after
struct point r = p; r.x = 100;,p.xis still 3. Structures can be passed to and returned from functions by value (a full copy) (Functions and Parameter Passing). - Structures cannot be compared with
==; compare member by member. (memcmpis unreliable because of padding bytes.) - A structure cannot contain a member of its own type (that would be infinitely large), but it can contain a pointer to its own type. Such a self-referential structure is how linked nodes are built.
typedefcreates an alias, not a new type:Nodeandstruct nodeare the same type.
Alignment and padding
Many processors access an object fastest, or only, when its address is a multiple of its alignment. The compiler therefore inserts unused padding bytes inside and at the end of a structure. Under the stated alignment assumption the rules are:
- Members are laid out in declaration order (the compiler may not reorder them).
- Each member starts at the next offset that is a multiple of its alignment. The first member is at offset 0.
- The structure's alignment is the largest alignment of its members, and its size is rounded up to a multiple of that alignment, so that every element of an array of structures is aligned.

struct { char c; int i; char d; } (12 bytes: 3 padding bytes after c, 3 at the end) beside the reordered struct { int i; char c; char d; } (8 bytes), assuming each type is aligned to its size.Unions
union U { int i; char c[6]; };
union Bytes { unsigned i; unsigned char b[4]; };
union Pun { int i; float f; };- All members start at offset 0 and overlap. The size is at least the size of the largest member, rounded up to the union's alignment:
sizeof(union U)is 8 (6 rounded up to a multiple of 4). - Storing into one member and then reading another reinterprets the stored bytes as the other type (C11 footnote 95). The result depends on the representation, for example byte order. On little-endian x86-64, after
u.i = 0x01020304withunion Bytes u, the byteu.b[0]is 4 andu.b[3]is 1. Withunion Pun pandp.f = 1.0f, readingp.igives the bit pattern0x3f800000. Reading a different scalar member can encounter a trap representation and then has undefined behaviour; representation-dependent type punning does not guarantee a valid scalar value. Character-byte inspection is a distinct operation that can inspect object representation. The printed x86-64 results require the stated member sizes, byte order and valid representations; they are implementation examples, not universal C outputs. - Typical uses: saving memory when only one field is meaningful at a time (usually with a separate "tag" field saying which), and inspecting representations.
Enumerations
enum colour { RED, GREEN = 5, BLUE, CYAN = 2, MAGENTA };- Enumerators are integer constants of type
int. The first defaults to 0; each later one without an explicit value is one more than the previous one. SoREDis 0,GREEN5,BLUE6,CYAN2 andMAGENTA3. Values may repeat. - An
enumvariable has an implementation-defined integer type able to hold all the values (4 bytes with gcc here). C does not restrict anenumvariable to the listed values. - Enumerators are often used as
caselabels and array sizes, because they are constant expressions.
Bit-fields (brief)
A member can be declared with a width in bits: struct flags { unsigned a : 1; unsigned b : 3; unsigned c : 4; };. Storing a value too large for an unsigned bit-field keeps only the low bits: assigning 9 to the 3-bit field b stores . The layout of bit-fields within storage units is implementation-defined; with gcc this structure occupies 4 bytes. Bit-fields have no address, so &fl.b is invalid.
How it works: computing `sizeof` of a structure
Apply the three rules member by member, tracking the current offset.
| Structure | Offsets of members | Padding | sizeof |
|---|---|---|---|
struct A { char c; int i; char d; } | c 0, i 4, d 8 | 3 after c, 3 at end | 12 |
struct B { int i; char c; char d; } | i 0, c 4, d 5 | 2 at end | 8 |
struct C { char c; double d; int i; } | c 0, d 8, i 16 | 7 after c, 4 at end | 24 |
struct D { double d; int i; char c; } | d 0, i 8, c 12 | 3 at end | 16 |
struct E { char a, b, c; } | 0, 1, 2 | none | 3 |
Ordering members from largest to smallest alignment minimises padding: struct C and struct D hold the same members, yet one is 24 bytes and the other 16. The minimum possible size is the sum of the member sizes rounded up to the largest alignment.
Worked examples
All outputs below are for C11 with gcc on x86-64 Linux (LP64).
Example 1 (copy semantics).
struct student { char name[8]; int marks; };
void bump(struct student s) { s.marks += 10; } /* changes a copy */
void bump_p(struct student *s) { s->marks += 10; } /* changes the original */
struct student s = {"Asha", 70};
bump(s); /* s.marks is still 70 */
bump_p(&s); /* s.marks is now 80 */Example 2 (array of structures and ->). struct student arr[2] = {{"Ravi", 50}, {"Meena", 60}}; struct student *sp = arr; sp++; Then sp->name is "Meena", (sp - 1)->marks is 50, and sizeof arr is 24 (each element is 12 bytes: 8 for the name and 4 for marks, already aligned).
Example 3 (self-referential nodes). Node n2 = {20, NULL}, n1 = {10, &n2}; Node *h = &n1; gives h->key 10, h->next->key 20, and h->next->next == NULL is 1.
Example 4 (enumeration values). For enum colour above, printf("%d %d %d %d %d", RED, GREEN, BLUE, CYAN, MAGENTA) prints 0 5 6 2 3.
Important properties and observations
p->mis(*p).m;*p.mis a different expression.- Structure assignment and parameter passing copy all members, including arrays inside the structure.
- Structures cannot be compared with
==. - Padding depends on alignment rules; the size of a structure is at least the sum of its members and is a multiple of its alignment.
- A union's size is its largest member rounded up to its alignment; only one member holds a meaningful value at a time.
- Enumerators are
intconstants that count up from the previous value. - A structure may contain a pointer to its own type but not an instance of it.
GATE examination perspective
sizeofof a structure or union: state the alignment assumption, then apply the offset rules; reorder members if the question asks for the minimum size.- Pointer access chains:
p->next->next->key; draw the nodes. - Copy versus pointer semantics when a structure is passed to a function.
- Enum values with some explicit initialisers.
- Union reads after writing another member: the answer depends on endianness, which the question must state.
Summary
Sources
- ISO/IEC 9899:2011 (C11), committee draft N1570, (consulted 2026-11-09), Section 6.2.8 (alignment of objects), 6.5.2.3 (structure and union members, footnote 95 on reading a different union member), 6.7.2.1 (structure and union specifiers, padding and bit-fields), 6.7.2.2 (enumeration specifiers), 6.7.9 (initialization).
- B. W. Kernighan and D. M. Ritchie, The C Programming Language, 2nd ed., Prentice Hall, 1988: Chapter 6 (structures, including 6.8 unions and 6.9 bit-fields) and Section 2.3 (enumeration constants).