optional · CSS study notes
II.15 Structures, Unions, and Bit Manipulation
⬆️ P-I.II. Programming Fundamentals · Question Bank · Chapter II (2016–2026)
🧠
Remember: Struct stores together; union shares; masks select bits.
Start here — what you should be able to do
- Design records and pass them to functions.
- Explain union storage and active members accurately.
- Calculate bitwise results and use valid masks.
Reading order: foundation checks → full notes and examples → exam traps → self-test without notes → past-paper answers. All sections below remain part of the topic; code examples are kept in full.
Foundation checks
Bit-mask toolkit
Use an unsigned value x and an unsigned mask 1u << k, with k within the type's bit width.
| Operation | Expression |
|---|---|
| Set bit | `x |
| Clear bit | x &= ~mask |
| Toggle bit | x ^= mask |
| Test bit | (x & mask) != 0 |
| Power of two | x != 0 && (x & (x - 1)) == 0 |
Memory: ordinary struct members have separate storage, with possible padding. A union has shared storage sufficient for its largest member plus alignment requirements. Active member: do not assume reading arbitrary inactive union members is portable C++. Enum: unassigned enumerators start at zero and then increment; an explicit value changes the subsequent sequence.
1. Structures (struct)
- Groups different data types under one name; each member gets its own separate memory, so the struct's total size is (at least) the sum of its members' sizes
struct Student {
char name[20];
int age;
float gpa;
};
struct Student s1 = {"Ali", 20, 3.8};
printf("%s", s1.name); // dot operator to access members
- Members are accessed with the dot operator (
.) on a struct variable, or the arrow operator (->) via a pointer to a struct:ptr->name - Nested structures: a struct can contain another struct as a member
- Structures can be passed to functions by value (a full copy) or by reference/pointer (to avoid copying and/or allow modification)
2. Unions
- Union: members share storage; size is sufficient for the largest member and alignment requirements, not the sum.
union Data {
int i;
float f;
char c;
};
union Data d;
d.i = 10; // writing to i overwrites the same memory f and c would use
- Useful when only one of several possible types is needed at a time (memory-saving), e.g. representing a value that could be an int OR a float depending on context
- Active member: ordinary C++ union use has one active member; arbitrary inactive-member reads are not portable type-punning.
3. Struct vs Union
| struct | union | |
|---|---|---|
| Memory per member | Separate for each | Shared (overlapping) |
| Total size | Ordinary members plus any padding | Sufficient for largest member and alignment |
| Simultaneous access | All members valid at once | Only the most recently written member is valid |
4. Enumerations (enum)
- A user-defined type consisting of a set of named integer constants, improving readability over "magic numbers"
enum Day {SUN, MON, TUE, WED, THU, FRI, SAT}; // SUN=0, MON=1, ... by default
enum Day today = WED; // today holds the integer value 3
5. Bit Manipulation Operators
| Operator | Name | Effect |
|---|---|---|
| & | AND | 1 only if both bits are 1 |
| OR | ||
| ^ | XOR | 1 if bits differ |
| ~ | NOT | Flips every bit (1's complement) |
| << | Left shift | Shifts bits left; each shift multiplies by 2 |
| >> | Right shift | Shifts bits right; each shift divides by 2 (for unsigned/positive values) |
- Example:
6 & 3→0110 & 0011=0010=2;6 | 3→0110 | 0011=0111=7;6 ^ 3→0101=5 5 << 1=10(multiply by 2);5 >> 1=2(divide by 2, truncated)
6. Bit Masking / Flags Technique
- A common low-level pattern for storing multiple boolean flags compactly in one integer:
#define READ 1 // 001
#define WRITE 2 // 010
#define EXEC 4 // 100
int perms = READ | WRITE; // set flags: 011
if (perms & WRITE) { ... } // check a flag: is WRITE set?
perms = perms & ~WRITE; // clear a flag: unset WRITE
- Used in permission systems, hardware registers, and status flags where memory efficiency matters
7. 💻 Code Examples: C & C++
Struct, union, enum, and a bit-flag permissions example, all in one program:
C:
#include <stdio.h>
struct Student { char name[20]; int age; float gpa; };
union Data { int i; float f; };
enum Day { SUN, MON, TUE, WED, THU, FRI, SAT };
#define READ 1 // 001
#define WRITE 2 // 010
int main(void) {
struct Student s1 = {"Ali", 20, 3.8};
printf("%s is %d, GPA %.1f\n", s1.name, s1.age, s1.gpa); // dot operator
union Data d;
d.i = 10;
- **Size example:** the union's size accommodates its largest member and alignment; int/float are often four bytes, but check the actual implementation.
enum Day today = WED;
printf("today = %d\n", today); // 3
int perms = READ | WRITE; // set flags: 011
if (perms & WRITE) printf("write allowed\n"); // check a flag
perms = perms & ~WRITE; // clear a flag
return 0;
}
C++:
#include <iostream>
using namespace std;
struct Student { string name; int age; float gpa; }; // C++ allows std::string as a member
union Data { int i; float f; };
enum Day { SUN, MON, TUE, WED, THU, FRI, SAT };
const int READ = 1; // 001
const int WRITE = 2; // 010
int main() {
Student s1{"Ali", 20, 3.8f}; // C++11 brace initialization
cout << s1.name << " is " << s1.age << ", GPA " << s1.gpa << endl;
Data d;
d.i = 10;
cout << "d.i=" << d.i << " (sizeof union = " << sizeof(d) << ")" << endl;
Day today = WED;
cout << "today = " << today << endl; // 3
int perms = READ | WRITE;
if (perms & WRITE) cout << "write allowed" << endl;
perms = perms & ~WRITE;
return 0;
}
- Size example: the union's size accommodates its largest member and alignment; int/float are often four bytes, but check the actual implementation.
8. MCQ Traps
- In a struct, each member has separate memory; in a union, all members share the same memory
- Union size: at least enough for the largest member, with alignment/padding as required.
- Accessing a struct member via a pointer requires the arrow operator (
->), not the dot operator enumvalues default to 0, 1, 2, ... in declaration order unless explicitly assigned otherwise- Left shift (
<<) multiplies by 2 per shift; right shift (>>) divides by 2 per shift — but only under the appropriate unsigned/range and valid-shift-count conditions
9. Self-Test Questions — with answers
Q1. Why is union storage based on the largest member?
Answer
- Members overlap the same storage.
- It must be sufficient for the largest member and satisfy alignment requirements; it is not the sum of member sizes.
- Ordinary C++ use has one active member at a time.
Q2. Which operator accesses a member through a pointer?
Answer
ptr->member, equivalent to(*ptr).member.- Use
object.memberwhen you have the struct object itself.
Q3. Compute 12 AND 10, OR 10 and XOR 10.
Answer
- 12 =
1100; 10 =1010. - AND:
1000= 8. - OR:
1110= 14. - XOR:
0110= 6.
Q4. What values do JAN, FEB and MAR have by default?
Answer
- For
enum Month { JAN, FEB, MAR };: 0, 1 and 2. - If JAN is explicitly 1, the following unassigned values become 2 and 3.
Q5. How do OR and AND set and test a flag?
Answer
- Set:
flags |= mask. - Test:
(flags & mask) != 0. - Clear:
flags &= ~mask. - Use an unsigned mask and a valid bit position.
- Why does a union's size equal its largest member's size rather than the sum of all members?
- What operator is used to access a struct member through a pointer, and why?
- Compute
12 & 10,12 | 10, and12 ^ 10in binary. - What integer values do the enum constants
{JAN, FEB, MAR}take by default? - Describe how bitwise OR and AND can be used to set and check a flag bit, respectively.
10. 📝 Exam Practice: Binary Logic Gate Simulator
Q: Write a C/C++ program which implements binary logical 'AND', 'OR', and 'XOR' gates. The program takes binary numbers and a desired logical gate, and outputs the result of the gate.
Solution:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string bin1, bin2, gate;
cout << "Enter first binary number: ";
cin >> bin1;
cout << "Enter second binary number: ";
cin >> bin2;
cout << "Enter desired gate (AND / OR / XOR): ";
cin >> gate;
// Pad the shorter string with leading zeros so both are equal length
int maxLen = (bin1.length() > bin2.length()) ? bin1.length() : bin2.length();
while (bin1.length() < maxLen) bin1 = "0" + bin1;
while (bin2.length() < maxLen) bin2 = "0" + bin2;
string result = "";
for (int i = 0; i < maxLen; i++)
{
int bit1 = bin1[i] - '0'; // convert char '0'/'1' to int 0/1
int bit2 = bin2[i] - '0';
int resBit;
if (gate == "AND" || gate == "and") resBit = bit1 & bit2;
else if (gate == "OR" || gate == "or") resBit = bit1 | bit2;
else if (gate == "XOR" || gate == "xor") resBit = bit1 ^ bit2;
else { cout << "Invalid gate entered."; return 0; }
result += (resBit == 1) ? '1' : '0';
}
cout << "\nResult of " << gate << " operation: " << result << endl;
return 0;
}
Sample run:
Enter first binary number: 1010
Enter second binary number: 1100
Enter desired gate (AND / OR / XOR): AND
Result of AND operation: 1000
Column-method trace (matches the textbook's "evaluate by column" approach):
| Position | bin1 | bin2 | AND | OR | XOR |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 1 | 0 |
| 2 | 0 | 1 | 0 | 1 | 1 |
| 3 | 1 | 0 | 0 | 1 | 1 |
| 4 | 0 | 0 | 0 | 0 | 0 |
Key reasoning points:
- Binary numbers are treated as strings, not integers — each character is processed individually with
&,|,^applied to single 0/1 ints, mirroring the textbook's column-by-column method - Shorter input is zero-padded on the left first, so both operands align at the same bit positions
- Matches the chapter's summary rules exactly: AND needs both bits 1, OR needs at least one bit 1, XOR needs an odd count of 1 bits (here just "the two bits differ")
11. 📜 Past-Paper Questions & MCQs (CSS 2016–2026)
2016 · Paper-I · Q4(a) · 6 marks
Recall cue: Define the record fields; input the complete record; test age boundaries; display the category.
Q. Define a structure for a Person (name, age, address). Input one record and display "Young" if age < 20, "Old" if age > 50, otherwise "Middle".
Answer — key points
struct Person { char name[30]; int age; char address[50]; };
int main() {
Person p;
cout << "Enter Name = "; cin.getline(p.name, 30);
cout << "Enter Age = "; cin >> p.age; cin.ignore();
cout << "Enter Address = "; cin.getline(p.address, 50);
if (p.age < 20) cout << "Person is YOUNG";
else if (p.age > 50) cout << "Person is OLD";
else cout << "Person is MIDDLE";
}
- The paper leaves ages 20 and 50 undefined, so treat them as Middle.
2017 · Paper-I · Q3(c) · 6 marks
Recall cue: Store code, name and price together; find the code; multiply price by quantity; accumulate the bill.
Q. Write a supermarket checkout program. The database of items (name, code, price) is a structure. The cashier enters codes and quantities, and the program prints the total.
Answer — key points
struct Item { int code; char name[20]; float price; };
Item db[3] = { {1,"Rice",500}, {2,"Sugar",150}, {3,"Oil",400} };
float total = 0; char more;
do {
int code, qty;
cout << "Enter product code: "; cin >> code;
cout << "Enter quantity: "; cin >> qty;
for (int i = 0; i < 3; i++)
if (db[i].code == code) total += db[i].price * qty;
cout << "Do you have more products to add (Y/N): "; cin >> more;
} while (more == 'Y' || more == 'y');
cout << "The total amount is " << total;
- To search by name, compare with
strcmp(db[i].name, input) == 0.
2019 · Paper-I · Q5(b) · 5 marks and 2023 · Paper-I · Q3(c) · 6 marks
Recall cue: Define bitwise operations; demonstrate masks; use unsigned values and valid shift counts.
Q. What is bit twiddling? Give a brief description.
Answer — key points
- Bit twiddling (bit manipulation) means working directly on the individual bits of data using bitwise operators
&,|,^,~,<<,>>. - Why: it is fast and memory-efficient, so it is used in device drivers, graphics, cryptography, compression and flags.
- Examples:
- odd or even:
n & 1 - multiply by 2:
n << 1 - set bit k:
n | (1 << k) - clear bit k:
n & ~(1 << k) - toggle bit k:
n ^ (1 << k) - power of two test:
n != 0 && (n & (n - 1)) == 0 - swap without a temporary:
a ^= b; b ^= a; a ^= b;
- odd or even:
2022 · Paper-I · Q4(b) · 8 marks
Recall cue: Write both numbers in binary; OR each bit; convert 11101 back to 29.
Q. Write the output of the program with a = 12, b = 25 that prints a | b.
Answer — key points
- 12 = 01100, 25 = 11001, so 12 | 25 = 11101 = 29.
- Output:
a = 12
b = 25
a | b = 29
2025 · Paper-I · Q4(c) · 8 marks
Recall cue: Represent real and imaginary parts; add corresponding fields; format negative imaginary parts correctly.
Q. Demonstrate two complex numbers using a structure. Use a function to add them and display the result as (a + bi).
Answer — key points
struct Complex { float re, im; };
Complex add(Complex x, Complex y) { return { x.re + y.re, x.im + y.im }; }
void show(Complex c) {
cout << "(" << c.re << (c.im < 0 ? " - " : " + ") << (c.im < 0 ? -c.im : c.im) << "i)";
}
int main() {
Complex a, b;
cout << "First (real imag): "; cin >> a.re >> a.im;
cout << "Second (real imag): "; cin >> b.re >> b.im;
show(add(a, b));
}
2026 · Paper-I · Q3(a) · 6 marks
Recall cue: Explain bit manipulation; show checking and setting/clearing bits; avoid blanket performance claims.
Q. What is bit manipulation in programming, and why is it used? Give two examples.
Answer — key points
- Bit manipulation uses bitwise operators (
&,|,^,~,<<,>>) to read or change individual bits. - Why used: speed, low memory use, and direct control of flags, masks, hardware registers, compression and encryption.
- Example 1: checking odd or even with
n & 1(1 means odd). - Example 2: setting and clearing a bit with
flags |= (1 << 3)andflags &= ~(1 << 3).
MCQs
2026 P-I · Q3. A programmer wants to group different data types. What should he or she use?
- (A) Structures ✅
- (B) Arrays
- (C) Unions
- (D) None of these
- Answer: (A) Structures.
- Why: a structure holds members of different types together, each with its own memory (for example an int, a float and a char array). An array holds elements of one type only. A union also mixes types, but all members share the same memory, so only one value is valid at a time.
Technical accuracy notes
- For unsigned n, a power-of-two test must exclude zero:
n != 0 && (n & (n - 1)) == 0. - Use unsigned masks such as
1u << k, with k less than the type's bit width. Bitwise operations are not automatically faster than arithmetic after optimisation. - A union is large enough for its largest member and obeys alignment requirements. Its members share storage, but arbitrary access through an inactive member is not portable C++ type-punning. C++ working draft.
- Prefer a temporary variable or an appropriate swap function over XOR swapping, particularly when two expressions may alias.
Recall check and coverage
- Explain the three learning outcomes at the top without looking.
- Reproduce one example or trace and test a boundary case.
- Answer each self-test, then compare with the key.
- Attempt each recorded past-paper task on this page.
- Recorded written references: 2016 · Paper-I · Q4(a) · 6 marks; 2017 · Paper-I · Q3(c) · 6 marks; 2019 · Paper-I · Q5(b) · 5 marks and 2023 · Paper-I · Q3(c) · 6 marks; 2022 · Paper-I · Q4(b) · 8 marks; 2025 · Paper-I · Q4(c) · 8 marks; 2026 · Paper-I · Q3(a) · 6 marks
Evidence limit: this page preserves the question records found in your Notion notes. Disputed labels and questions not checked against original PDFs remain flagged in the Question Bank; this is not a claim of exhaustive original-paper verification.