Structures, Unions & File I/O in C for GATE CS
Struct memory layout, padding rules, union sizing, bit fields, and file operations — with GATE-level sizeof questions and output tracing.
Last updated: April 2026 | GATE CS 2024–2026 syllabus
Key Takeaways for GATE
- struct: separate storage for each member.
sizeof(struct) ≥ sum of membersdue to padding. - Padding rule: each member aligned to offset that is a multiple of its size. Struct ends padded to multiple of largest member’s size.
- union: all members share same memory.
sizeof(union) = sizeof(largest member)+ alignment padding. - Bit fields:
unsigned int x : 3uses only 3 bits. Cannot take address of bit field. - typedef: creates alias —
typedef struct Node Node;— allows using justNodeinstead ofstruct Node. - File I/O:
fopen/fclose, text mode (fprintf/fscanf) vs binary mode (fread/fwrite).
1. Struct Basics
struct Point {
int x; // 4 bytes
int y; // 4 bytes
}; // sizeof(struct Point) = 8
struct Point p = {3, 4};
p.x = 10; // member access with dot
struct Point *pp = &p;
pp->y = 20; // member access via pointer with arrow Accessing members:
Value: p.member Pointer: pp->member ≡ (*pp).member
2. Structure Padding & Alignment
Trailing padding: Struct size rounded up to multiple of alignment of largest member.
Example 1:
struct A {
char c; // 1 byte at offset 0
// 3 bytes padding (to align int to offset 4)
int i; // 4 bytes at offset 4
char d; // 1 byte at offset 8
// 3 bytes trailing padding (to make size multiple of 4)
};
// sizeof(struct A) = 12 (not 6!)Example 2 — Reordered (smaller):
struct B {
int i; // 4 bytes at offset 0
char c; // 1 byte at offset 4
char d; // 1 byte at offset 5
// 2 bytes trailing padding
};
// sizeof(struct B) = 8Rule of thumb: Declare members in decreasing order of size to minimise padding.
| Member order | Members | sizeof |
|---|---|---|
| char, int, char | 1+3pad+4+1+3pad | 12 |
| int, char, char | 4+1+1+2pad | 8 |
| double, char, int | 8+1+3pad+4 | 16 |
| char, char, int, double | 1+1+2pad+4+8 | 16 |
3. Union
sizeof(union) = sizeof(largest member) + any trailing alignment padding.
union Data {
int i; // 4 bytes
float f; // 4 bytes
char c[8]; // 8 bytes ← largest
};
// sizeof(union Data) = 8Writing to one member and reading another is type-punning — valid in C (undefined in C++).
Use cases: Memory-efficient variant types, type punning (reading float bits as int), protocol parsing.
4. Struct vs Union
| Property | struct | union |
|---|---|---|
| Member storage | Separate for each member | Shared (same location) |
| sizeof | ≥ sum of members (with padding) | = largest member (with padding) |
| Valid members at once | All | Only 1 (most recently written) |
| Use case | Group related data | Memory-efficient variants |
5. Bit Fields
struct Flags {
unsigned int read : 1; // 1 bit
unsigned int write : 1; // 1 bit
unsigned int exec : 1; // 1 bit
unsigned int : 5; // 5 bits padding (unnamed)
};
// Packed into 1 byte (8 bits total) Rules:
• Can only use int, unsigned int, or _Bool as base type (in standard C).
• Cannot take address of bit field (&f.read is illegal).
• Unnamed bit field of size 0 forces next field to start at the next unit boundary.
• Bit field order within a unit is implementation-defined (endianness-dependent).
6. typedef
typedef existing_type new_name; — creates type alias, not a new type.
typedef unsigned long long ULL;
typedef struct Node {
int data;
struct Node *next; // must use 'struct Node' here, not 'Node' (not yet defined)
} Node; // now 'Node' is alias for 'struct Node'
Node n1; // equivalent to: struct Node n1; Common uses: simplifying function pointer declarations, struct aliases, platform-specific type abstraction (e.g., int32_t in <stdint.h>).
7. Nested Structs & Self-referential Structs
struct Address { char city[20]; int pin; };
struct Person {
char name[30];
struct Address addr; // embedded (not pointer)
};
// sizeof(Person) = 30 + sizeof(Address) + paddingSelf-referential (linked list node):
struct Node {
int data;
struct Node *next; // pointer to same type — OK (pointer is fixed size)
// struct Node next; // ILLEGAL — incomplete type, infinite size
};A struct cannot contain itself as a member (infinite size), but can contain a pointer to itself.
8. File I/O in C
| Function | Purpose | Mode |
|---|---|---|
fopen(name, mode) | Open file, returns FILE* | “r”,”w”,”a”,”rb”,”wb” |
fclose(fp) | Close file, flush buffers | — |
fprintf(fp, fmt, ...) | Formatted write to file | Text |
fscanf(fp, fmt, ...) | Formatted read from file | Text |
fgets(buf, n, fp) | Read line (safer than gets) | Text |
fputs(str, fp) | Write string to file | Text |
fread(buf, sz, n, fp) | Read n items of size sz | Binary |
fwrite(buf, sz, n, fp) | Write n items of size sz | Binary |
fseek(fp, off, whence) | Move file position | — |
ftell(fp) | Get current file position | — |
feof(fp) | Test end-of-file flag | — |
whence values for fseek: SEEK_SET (from start), SEEK_CUR (from current), SEEK_END (from end).
Always check fopen return: returns NULL on failure. Always fclose to flush buffers.
9. GATE Examples
struct S {
double d; // 8 bytes, offset 0
int i; // 4 bytes, offset 8
char c; // 1 byte, offset 12
// 3 bytes trailing padding (to align to 8-byte boundary of double)
};sizeof(S) = 8 + 4 + 1 + 3 = 16 bytes
union U {
int a; // 4 bytes
double b; // 8 bytes ← largest
char c; // 1 byte
};sizeof(U) = sizeof(double) = 8 bytes
union { int i; char c[4]; } u;
u.i = 0x01020304;
printf("%x", u.c[0]); On little-endian system: c[0] = least significant byte = 0x04. Output: 4
On big-endian: c[0] = 0x01. Endianness determines answer — GATE usually specifies.
10. Common Mistakes
- Assuming sizeof(struct) = sum of members: Padding adds extra bytes. Always compute using alignment rules, or use
__attribute__((packed))to disable padding (non-standard). - Using union member after writing another: In C++, this is undefined behaviour. In C, it is implementation-defined. For GATE, assume the hardware stores in little-endian unless stated otherwise.
- Self-referential struct with value, not pointer:
struct Node { int data; struct Node next; }is illegal — incomplete type. Must usestruct Node *next. - Forgetting fclose: Data may remain in the buffer and not be written to disk. Always fclose after writing, especially before reading the same file.
- Using gets() instead of fgets(): gets() has no length limit and is a security vulnerability (buffer overflow). Always use fgets(buf, sizeof(buf), stdin).
11. FAQ
- What is structure padding in C?
- Padding is extra bytes inserted between struct members so each member starts at an address that is a multiple of its size (natural alignment). For example, a 4-byte int must start at an offset divisible by 4. Padding ensures correct and efficient CPU access on all architectures. Total sizeof(struct) includes all padding bytes.
- What is the size of a union in C?
- sizeof(union) equals the size of its largest member, plus any trailing padding needed for alignment. All members start at offset 0 and share the same memory. For union {int i; double d; char c[8];}: sizeof = 8 (double is largest, char[8] is same size).
- What is the difference between struct and union?
- struct allocates separate memory for each member sequentially (with padding), so all members are valid simultaneously. union allocates a single block shared by all members — the size equals the largest member — and only one member can hold a valid value at a time. struct is for grouping related data; union is for memory-efficient variant types.
- What is the difference between fread and fscanf?
- fread(buf, size, n, fp) reads n raw binary items of given size into buf — no formatting or whitespace interpretation. fscanf(fp, fmt, …) reads formatted text from file using a format string like scanf. Use fread/fwrite for binary files (images, structs); use fprintf/fscanf for human-readable text files.