Chapter 6 – Control Structures (C++)
Control Structures – General Overview
- A C++ program is rarely a single linear sequence; instead it needs to
- Repeat certain instructions (iteration)
- Choose between alternative paths (selection / decision-making)
- Constructs that provide these capabilities are collectively called control structures.
- Every control structure ultimately manipulates the program counter (the instruction pointer) so that execution jumps forward, backward, or conditionally.
- Introduction of control structures brings a new syntactic unit: the compound statement / block.
Compound Statements (Blocks)
- Definition: A block is a group of C++ statements treated as one.
- Written inside braces {}.
- Each inner statement ends with a semicolon ; as usual.
- Example syntax:
cpp { statement1; statement2; statement3; }
- Usage rules:
- Wherever a single statement is allowed syntactically, a block can be substituted.
- If only one instruction should run, braces are optional; if many, braces are mandatory.
- Practical implication: Always consider braces for clarity, even for single-line bodies, to avoid logical errors when adding lines later (industry best practice).
Conditional Structure: if
- Purpose: Execute a statement / block only if a boolean condition evaluates to true.
- Syntax:
if (condition)
statement; // may be a single instruction or a block
- Flow (high-level algorithm):
- Evaluate condition.
- If true → run statement.
- Else → skip statement and continue after the
if.
- Simple example:
if (x == 100)
cout << "x is 100";
- Multi-statement body example (using a block):
if (x == 100) {
cout << "x is ";
cout << x;
}
- Complete applied program (division guard):
#include <iostream>
using namespace std;
int main() {
int dividend, divisor;
cout << "Please enter two integers to divide:";
cin >> dividend >> divisor;
if (divisor != 0)
cout << dividend << "/" << divisor << " = "
<< dividend / divisor << '\n';
return 0;
}
- Demonstrates guarding against divide-by-zero error; if divisor \neq 0 the division is executed.
- Nested
if: Anifinside anotherifto create hierarchical checks.
- Nested
if (value >= 0)
if (value <= 10)
cout << "In range";
cout << "Done\n";
- Logic: Only prints In range when 0 \leq value \leq 10.
Conditional Structure: if … else
- Allows one action on true branch and an alternative on false branch.
- Syntax:
if (condition)
statement1; // executes when condition true
else
statement2; // executes when condition false
- Example:
if (x == 100)
cout << "x is 100";
else
cout << "x is not 100";
- Multi-statement bodies require blocks.
- Extended program (revisited division):
if (divisor != 0) {
cout << dividend << "/" << divisor << " = "
<< dividend / divisor << '\n';
} else {
cout << "Division by zero is not allowed\n";
}
Conditional Structure: Nested / Cascaded if … else if … else
- Purpose: Check multiple mutually exclusive conditions in sequence.
- Generic syntax:
if (cond1)
stmt1;
else if (cond2)
stmt2;
...
else
stmtN;
- Multi-category sign example:
if (x > 0)
cout << "x is positive";
else if (x < 0)
cout << "x is negative";
else
cout << "x is 0";
- Full program translating integers 0 to 5 into words:
if (value < 0) cout << "Too small";
else if (value == 0) cout << "zero";
else if (value == 1) cout << "one";
else if (value == 2) cout << "two";
else if (value == 3) cout << "three";
else if (value == 4) cout << "four";
else if (value == 5) cout << "five";
else cout << "Too large";
Iteration Structures (Loops) – Overview
- A loop repeats a statement / block while or until a condition holds.
- Motivation: Avoid code duplication; central for algorithms such as searching, sorting, numerical methods.
- C++ provides three native loop constructs, each best suited for particular scenarios:
forloop – counter-controlled, known iteration count.whileloop – condition-controlled, unknown/variable count.do … whileloop – post-test version, guarantees at least one execution.
for Loop
- Syntax: \texttt{for (initialization; condition; update) statement;}
- Sequence:
- Execute initialization once.
- Check condition. If false → exit loop.
- Execute statement (body).
- Execute update.
- Repeat from step 2.
- Countdown example:
for (int n = 10; n > 0; n--) {
cout << n << ", ";
}
cout << "END!";
- Output: 10,\ 9,\ 8,\ 7,\ 6,\ 5,\ 4,\ 3,\ 2,\ 1,\ END!
- Omitted fields: Any of the three fields may be empty but semicolons remain.
- Example:
for (; n < 10; )(no init, no update).
while Loop
- Syntax: ```cpp
while (expression)
statement;
- Semantics: Entry-controlled; body executes **only if** expression is true.
- Custom countdown program:
cpp
int n;
cin >> n;
while (n > 0) {
cout << n << ", ";
--n; // crucial to avoid infinite loop
}
cout << "DONE!";
- Vital design note: Ensure something inside the loop eventually makes the condition false.
## `do … while` Loop
- Syntax:
cpp
do
statement;
while (condition);
- Semantics: Exit-controlled; body runs **at least once**.
- Echo program:
cpp
unsigned long n;
do {
cout << "Enter number (0 to end): ";
cin >> n;
cout << "You entered: " << n << "\n";
} while (n != 0);
- Use-case guideline: Best when the termination condition depends on body interaction (e.g., reading user input inside the loop).
# Jump Statements
- Purpose: Alter the normal sequential flow instantly.
- Four in C++: `break`, `continue`, `return`, `goto`.
## `break`
- Immediately exits **innermost** loop or `switch`.
- Early-abort countdown:
cpp
for (int n = 10; n > 0; n--) {
cout << n << ", ";
if (n == 3) {
cout << "countdown aborted!";
break;
}
}
- Practical application: Emergency termination, searching until found, menu exit.
## `continue`
- Skips remaining body statements **only for the current iteration**, proceeds with next.
- Skipping 5 in countdown:
cpp
for (int n = 10; n > 0; n--) {
if (n == 5) continue; // jump to next iteration
cout << n << ", ";
}
cout << "DONE!";
## `goto`
- Unconditional jump to a **label** within same function.
- Example:
cpp
int n = 10;
loop:
cout << n << ", ";
if (--n > 0) goto loop;
cout << "DONE!";
- Warnings / best practice:
- Breaks structured programming;
- Can create *spaghetti code*; avoid unless interfacing with low-level constructs or generated code.
## `return`
- Immediately exits the **current function**, optionally providing a return value.
- In `main`, `return 0;` conventionally signals normal termination.
## `exit()` Function
- Prototype: `void exit(int exitcode);` from `<cstdlib>`.
- Terminates **entire** program, bypassing stack unwinding.
- Use exit\,(0) for normal termination; non-zero for error signalling.
- Distinction: `exit` executes static object destructors and `atexit` handlers, whereas some low-level aborts do not.
# Selective Structure: `switch`
- Designed for multi-way branching based on **integral** constant values (chars, ints, enums).
- Syntax skeleton:
cpp
switch (expression) {
case constant1:
statements1;
break;
case constant2:
statements2;
break;
…
default:
default_statements;
}
- Operational steps:
1. Evaluate expression once.
2. Compare with each `case` label in order.
3. Jump into first matching label; execute downward until `break` or end of `switch`.
- Equivalence example (shows relation to `if-else if` chain):
cpp
switch (x) {
case 1: cout << "x is 1"; break;
case 2: cout << "x is 2"; break;
default: cout << "value of x unknown";
}``
is semantically identical to nestedif/else if` shown earlier.
- Fall-through behavior:
- Omitting
breaklets execution continue into subsequent cases. - Allows grouping of labels:
cpp switch (x) { case 1: case 2: case 3: cout << "x is 1, 2 or 3"; break; default: cout << "x is not 1, 2 nor 3"; }
- Omitting
- Limitations:
caselabels must be compile-time constants – no variables, no ranges.- For ranges or complex predicates, revert to
if/else if.
Practical, Philosophical & Ethical Notes
- Safety & correctness: Guarding against divide-by-zero, infinite loops, and other runtime errors is both a practical and ethical imperative (prevents crashes, data loss).
- Maintainability: Using structured constructs (
for,while,switch) rather thangotopromotes readable, verifiable code – aligning with professional standards and collaborative development norms. - Resource considerations: Infinite loops or forgotten
breakstatements can hog CPU cycles; responsible coding conserves shared computational resources. - User experience: Clear prompts and graceful exits (
exit(0), informative error messages) respect users’ time and trust. - Historical context: Early languages relied heavily on
goto; modern best practice ("structured programming" movement by Dijkstra) discourages it – foundational principle for subsequent object-oriented paradigms.
Quick Reference (Cheat Sheet)
- \texttt{if}\,(cond) → single-branch decision
- \texttt{if}\,(cond) … \texttt{else} → dual-branch decision
- \texttt{if}\,…\texttt{else if}\,…\texttt{else} → multi-branch decision
- \texttt{switch (expr)} → constant multi-branch selection, uses \texttt{case} labels & \texttt{break}
- \texttt{for (init; cond; upd)} → counter loop
- \texttt{while (cond)} → pre-test loop
- \texttt{do}\,…\texttt{while (cond);} → post-test loop (executes at least once)
- \texttt{break} → terminate loop / switch
- \texttt{continue} → skip to next iteration
- \texttt{return [value];} → exit function
- \texttt{goto label;} → unconditional jump (avoid)
- \texttt{exit(code);} → terminate program immediately (from
)
Connections to Earlier / Foundational Material
- Relies on Boolean logic (true / false) previously introduced in expressions chapter.
- Uses operators such as ==, !=, >, < covered in relational-operator lecture.
- Loop counters and conditions typically utilize variables, assignment, and arithmetic operations from basic C++ syntax lessons.
Real-World Relevance & Examples
- Input validation (e.g., checking divisor \neq 0) mirrors production systems preventing crashes.
- Menus in console apps often implemented with
switch. - Sensor polling loops in embedded systems often require
while(true)with internalbreakupon condition. - Game loops commonly exploit
whilefor main update cycle, combined withcontinuefor frame-skipping logic.
Common Pitfalls & Best Practices
- Forgetting braces in nested
ifstructures → danglingelseproblem. - Off-by-one errors in loop bounds (e.g., last iteration executed 10 times instead of 9).
- Infinite loops due to non-mutated condition variable.
- Neglecting
breakinswitchcausing unintended fall-through. - Prefer pre-increment/ decrement (
++i) where semantics allow to potentially optimize. - Consider using range-based
forin modern C++ for container iteration.
Formulas & Symbolic Reminders
- Loop counter update: n \leftarrow n - 1 in countdown examples.
- Guard condition pattern: \text{while}\,(condition) where condition → false eventually.
- Division guard: divisor \neq 0 before evaluating \dfrac{dividend}{divisor}.
Summary
- Control structures empower programs to make decisions and perform repetition, forming the backbone of algorithmic logic in C++.
- Mastery involves understanding syntax, flow of control, and the nuanced differences between constructs so the most expressive, safe, and efficient tool is chosen for each task.