Control Flow in C++
Table of Contents
- Control Flow in C++
Introduction
Control flow determines the order in which statements are executed in a program. C++ provides three fundamental control flow mechanisms:
┌─────────────────────────────────────────────────────────────┐
│ CONTROL FLOW TYPES │
├─────────────────────────────────────────────────────────────┤
│ 1. Sequential - Statements execute one after another │
│ 2. Selection - Choose between different paths │
│ 3. Iteration - Repeat a block of code │
└─────────────────────────────────────────────────────────────┘
Control Flow Diagram
┌─────────────┐
│ Start │
└──────┬──────┘
│
┌───────▼───────┐
│ Statement 1 │ Sequential
└───────┬───────┘
│
┌───────▼───────┐
┌────│ Condition? │────┐
│ └───────────────┘ │ Selection
Yes No
│ │
┌───▼───┐ ┌───▼───┐
│ Path A │ │ Path B │
└───┬───┘ └───┬───┘
│ ┌───────────────┐ │
└────► Merge Point ◄────┘
└───────┬───────┘
│
┌───────▼───────┐
┌───►│ Loop Body │ Iteration
│ └───────┬───────┘
│ │
│ ┌───────▼───────┐
│ │ Continue? │────No──►
│ └───────┬───────┘
│ Yes
└────────────┘
Sequential Execution
By default, C++ executes statements in order from top to bottom.
#include <iostream>
using namespace std;
int main() {
cout << "Step 1" << endl; // Executes first
cout << "Step 2" << endl; // Executes second
cout << "Step 3" << endl; // Executes third
return 0;
}
Conditional Statements
if Statement
Executes a block of code if a condition is true.
┌──────────────┐
│ Condition │
└──────┬───────┘
│
┌────▼────┐
Yes No
│ │
┌───▼───┐ │
│ Code │ │
└───┬───┘ │
└────┬────┘
│
Continue...
Syntax:
if (condition) {
// code to execute if condition is true
}
Examples:
int age = 20;
if (age >= 18) {
cout << "You are an adult." << endl;
}
// Single statement (braces optional but recommended)
if (age >= 18)
cout << "You can vote." << endl;
// Checking multiple conditions with logical operators
int score = 85;
if (score >= 80 && score <= 100) {
cout << "Excellent performance!" << endl;
}
if-else Statement
Choose between two paths based on a condition.
┌──────────────┐
│ Condition │
└──────┬───────┘
│
┌────▼────┐
Yes No
│ │
┌───▼───┐ ┌───▼───┐
│ True │ │ False │
│ Block │ │ Block │
└───┬───┘ └───┬───┘
└────┬────┘
│
Continue...
Syntax:
if (condition) {
// code if condition is true
} else {
// code if condition is false
}
Examples:
int number = 7;
if (number % 2 == 0) {
cout << number << " is even." << endl;
} else {
cout << number << " is odd." << endl;
}
// Using ternary as alternative for simple cases
string result = (number % 2 == 0) ? "even" : "odd";
cout << number << " is " << result << endl;
if-else-if Ladder
Check multiple conditions in sequence.
int score = 75;
char grade;
if (score >= 90) {
grade = 'A';
} else if (score >= 80) {
grade = 'B';
} else if (score >= 70) {
grade = 'C';
} else if (score >= 60) {
grade = 'D';
} else {
grade = 'F';
}
cout << "Grade: " << grade << endl; // Output: Grade: C
Key Points:
- Conditions are evaluated top to bottom
- Only the first true condition's block executes
elseis optional and catches all remaining cases
Nested if Statements
if statements inside other if statements.
int age = 25;
bool hasLicense = true;
if (age >= 18) {
cout << "You are an adult." << endl;
if (hasLicense) {
cout << "You can drive." << endl;
} else {
cout << "You need a license to drive." << endl;
}
} else {
cout << "You are a minor." << endl;
}
Warning: Deeply nested if statements can be hard to read. Consider refactoring:
// Better: Early return pattern
void checkDriving(int age, bool hasLicense) {
if (age < 18) {
cout << "You are a minor." << endl;
return;
}
cout << "You are an adult." << endl;
if (hasLicense) {
cout << "You can drive." << endl;
} else {
cout << "You need a license to drive." << endl;
}
}
switch Statement
Select one of many code blocks to execute.
int day = 3;
switch (day) {
case 1:
cout << "Monday" << endl;
break;
case 2:
cout << "Tuesday" << endl;
break;
case 3:
cout << "Wednesday" << endl;
break;
case 4:
cout << "Thursday" << endl;
break;
case 5:
cout << "Friday" << endl;
break;
case 6:
case 7:
cout << "Weekend" << endl;
break;
default:
cout << "Invalid day" << endl;
}
Key Points:
- Expression must be integral type (int, char, enum)
breakprevents fall-through to next casedefaulthandles unmatched values- Multiple cases can share the same code block
Fall-through Example:
char grade = 'B';
switch (grade) {
case 'A':
case 'B':
case 'C':
cout << "Pass" << endl;
break;
case 'D':
case 'F':
cout << "Fail" << endl;
break;
default:
cout << "Invalid grade" << endl;
}
C++17 Init Statement in switch:
switch (int x = getValue(); x) {
case 1:
cout << "One" << endl;
break;
case 2:
cout << "Two" << endl;
break;
default:
cout << "Other: " << x << endl;
}
Loops
for Loop
Best for known number of iterations.
┌─────────────────┐
│ Initialize │
└────────┬────────┘
│
┌────────▼────────┐
│ Condition? │───No──► Exit
└────────┬────────┘
Yes
│
┌────────▼────────┐
│ Loop Body │
└────────┬────────┘
│
┌────────▼────────┐
│ Update │
└────────┬────────┘
│
└───────────────┐
│
┌────────────────────────┘
│
▼ (Back to Condition)
Syntax:
for (initialization; condition; update) {
// loop body
}
Examples:
// Basic counting loop
for (int i = 0; i < 5; i++) {
cout << i << " "; // Output: 0 1 2 3 4
}
cout << endl;
// Counting backward
for (int i = 5; i > 0; i--) {
cout << i << " "; // Output: 5 4 3 2 1
}
cout << endl;
// Step by 2
for (int i = 0; i <= 10; i += 2) {
cout << i << " "; // Output: 0 2 4 6 8 10
}
cout << endl;
// Multiple variables
for (int i = 0, j = 10; i < j; i++, j--) {
cout << "i=" << i << ", j=" << j << endl;
}
// Infinite loop (use with caution)
for (;;) {
// runs forever unless break
}
while Loop
Best when number of iterations is unknown.
while (condition) {
// loop body
}
Examples:
// Basic while loop
int count = 0;
while (count < 5) {
cout << count << " ";
count++;
}
cout << endl; // Output: 0 1 2 3 4
// Input validation
int number;
cout << "Enter a positive number: ";
cin >> number;
while (number <= 0) {
cout << "Invalid! Enter a positive number: ";
cin >> number;
}
// Reading until sentinel value
int input;
int sum = 0;
cout << "Enter numbers (0 to stop): " << endl;
while (cin >> input && input != 0) {
sum += input;
}
cout << "Sum: " << sum << endl;
do-while Loop
Executes at least once, then checks condition.
┌────────────────┐
│ Loop Body │◄────┐
└───────┬────────┘ │
│ │
┌───────▼────────┐ │
│ Condition? │ Yes
└───────┬────────┘ │
No │
│ └─────────┘
│
Exit
Syntax:
do {
// loop body
} while (condition);
Examples:
// Guaranteed at least one execution
int count = 0;
do {
cout << count << " ";
count++;
} while (count < 5);
cout << endl; // Output: 0 1 2 3 4
// Menu system
int choice;
do {
cout << "\n=== Menu ===" << endl;
cout << "1. Option A" << endl;
cout << "2. Option B" << endl;
cout << "3. Exit" << endl;
cout << "Enter choice: ";
cin >> choice;
switch (choice) {
case 1: cout << "You chose A" << endl; break;
case 2: cout << "You chose B" << endl; break;
case 3: cout << "Goodbye!" << endl; break;
default: cout << "Invalid choice" << endl;
}
} while (choice != 3);
// Difference from while
int x = 10;
do {
cout << "do-while executes" << endl;
} while (x < 5); // Prints once
while (x < 5) {
cout << "while does not execute" << endl; // Never prints
}
Range-based for Loop (C++11)
Simplest way to iterate over containers.
Syntax:
for (declaration : container) {
// use element
}
Examples:
#include <vector>
#include <array>
#include <string>
// Iterate over array
int arr[] = {1, 2, 3, 4, 5};
for (int x : arr) {
cout << x << " "; // Output: 1 2 3 4 5
}
cout << endl;
// Iterate over vector
vector<string> names = {"Alice", "Bob", "Charlie"};
for (const string& name : names) {
cout << name << " ";
}
cout << endl;
// Iterate over string
string text = "Hello";
for (char c : text) {
cout << c << "-"; // Output: H-e-l-l-o-
}
cout << endl;
// Modify elements (use reference)
vector<int> nums = {1, 2, 3, 4, 5};
for (int& n : nums) {
n *= 2; // Double each element
}
// With auto
for (auto& n : nums) {
cout << n << " "; // Output: 2 4 6 8 10
}
cout << endl;
// Initializer list
for (int x : {10, 20, 30, 40}) {
cout << x << " "; // Output: 10 20 30 40
}
Jump Statements
break Statement
Exits the innermost loop or switch immediately.
// Break out of loop
for (int i = 0; i < 10; i++) {
if (i == 5) break;
cout << i << " "; // Output: 0 1 2 3 4
}
cout << endl;
// Search example
int target = 7;
int arr[] = {2, 4, 6, 7, 8, 10};
bool found = false;
for (int i = 0; i < 6; i++) {
if (arr[i] == target) {
cout << "Found at index " << i << endl;
found = true;
break;
}
}
if (!found) {
cout << "Not found" << endl;
}
continue Statement
Skips the rest of current iteration and continues with next.
// Skip even numbers
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) continue;
cout << i << " "; // Output: 1 3 5 7 9
}
cout << endl;
// Skip negative numbers
int nums[] = {3, -1, 4, -1, 5, -9, 2};
int sum = 0;
for (int n : nums) {
if (n < 0) continue;
sum += n;
}
cout << "Sum of positives: " << sum << endl; // Output: 14
goto Statement
Jumps to a labeled statement (use sparingly).
// goto example (avoid in modern code)
int i = 0;
loop_start:
if (i >= 5) goto loop_end;
cout << i << " ";
i++;
goto loop_start;
loop_end:
cout << endl; // Output: 0 1 2 3 4
// Legitimate use: breaking out of nested loops
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (i * j > 25) {
goto exit_loops;
}
cout << "(" << i << "," << j << ") ";
}
}
exit_loops:
cout << "Exited nested loops" << endl;
Warning: goto makes code hard to follow. Prefer structured alternatives.
return Statement
Exits the current function.
int findFirst(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i; // Exit function, return index
}
}
return -1; // Not found
}
// Early return for validation
bool processData(int value) {
if (value < 0) {
cout << "Error: negative value" << endl;
return false;
}
// Process value...
cout << "Processing: " << value << endl;
return true;
}
Nested Loops
Loops inside other loops.
// Multiplication table
for (int i = 1; i <= 5; i++) {
for (int j = 1; j <= 5; j++) {
cout << setw(4) << i * j;
}
cout << endl;
}
/*
Output:
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25
*/
// Pattern printing
int n = 5;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
cout << "* ";
}
cout << endl;
}
/*
Output:
*
* *
* * *
* * * *
* * * * *
*/
// Breaking out of nested loops
bool found = false;
int matrix[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
for (int i = 0; i < 3 && !found; i++) {
for (int j = 0; j < 3 && !found; j++) {
if (matrix[i][j] == 5) {
cout << "Found 5 at [" << i << "][" << j << "]" << endl;
found = true;
}
}
}
// Alternative: Use a function
auto findInMatrix = [](int mat[][3], int rows, int target) -> pair<int, int> {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 3; j++) {
if (mat[i][j] == target) {
return {i, j};
}
}
}
return {-1, -1};
};
auto [row, col] = findInMatrix(matrix, 3, 5);
Loop Control Patterns
Counter-Controlled Loop
for (int i = 0; i < 10; i++) {
// Process item i
}
Sentinel-Controlled Loop
int value;
while (cin >> value && value != -1) {
// Process value until -1 is entered
}
Flag-Controlled Loop
bool done = false;
while (!done) {
// Process...
if (someCondition) {
done = true;
}
}
Infinite Loop with Break
while (true) {
// Process...
if (shouldExit) {
break;
}
}
Common Algorithms
Linear Search
int linearSearch(int arr[], int size, int target) {
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
return i;
}
}
return -1;
}
Finding Maximum
int findMax(int arr[], int size) {
int maxVal = arr[0];
for (int i = 1; i < size; i++) {
if (arr[i] > maxVal) {
maxVal = arr[i];
}
}
return maxVal;
}
Sum of Array
int sum(int arr[], int size) {
int total = 0;
for (int i = 0; i < size; i++) {
total += arr[i];
}
return total;
}
Count Occurrences
int countOccurrences(int arr[], int size, int target) {
int count = 0;
for (int i = 0; i < size; i++) {
if (arr[i] == target) {
count++;
}
}
return count;
}
Reverse Array
void reverseArray(int arr[], int size) {
for (int i = 0; i < size / 2; i++) {
swap(arr[i], arr[size - 1 - i]);
}
}
Check Prime
bool isPrime(int n) {
if (n <= 1) return false;
if (n <= 3) return true;
if (n % 2 == 0 || n % 3 == 0) return false;
for (int i = 5; i * i <= n; i += 6) {
if (n % i == 0 || n % (i + 2) == 0) {
return false;
}
}
return true;
}
Factorial
unsigned long long factorial(int n) {
unsigned long long result = 1;
for (int i = 2; i <= n; i++) {
result *= i;
}
return result;
}
Fibonacci
int fibonacci(int n) {
if (n <= 1) return n;
int a = 0, b = 1;
for (int i = 2; i <= n; i++) {
int temp = a + b;
a = b;
b = temp;
}
return b;
}
Best Practices
1. Always Use Braces
// Bad
if (condition)
doSomething();
// Good
if (condition) {
doSomething();
}
2. Keep Loops Simple
// Bad: Multiple responsibilities
for (int i = 0; i < n; i++) {
process(arr[i]);
validate(arr[i]);
log(arr[i]);
save(arr[i]);
}
// Good: Single responsibility
for (int i = 0; i < n; i++) {
handleItem(arr[i]);
}
void handleItem(int item) {
process(item);
validate(item);
log(item);
save(item);
}
3. Prefer Range-based for
// Old style
for (size_t i = 0; i < vec.size(); i++) {
cout << vec[i] << " ";
}
// Modern style
for (const auto& item : vec) {
cout << item << " ";
}
4. Avoid Infinite Loops
// Ensure loop termination
while (condition) {
// Make sure condition eventually becomes false
// or use break
}
5. Use Meaningful Loop Variables
// Bad
for (int i = 0; i < users.size(); i++) { }
// Better
for (size_t userIndex = 0; userIndex < users.size(); userIndex++) { }
// Best
for (const auto& user : users) { }
6. Limit Nesting Depth
// Bad: Deep nesting
if (a) {
if (b) {
if (c) {
if (d) {
// code
}
}
}
}
// Good: Early returns
if (!a) return;
if (!b) return;
if (!c) return;
if (!d) return;
// code
Common Mistakes
1. Off-by-One Errors
// Wrong: Accesses arr[size], which is out of bounds
for (int i = 0; i <= size; i++) {
arr[i] = 0;
}
// Correct
for (int i = 0; i < size; i++) {
arr[i] = 0;
}
2. Infinite Loop
// Wrong: i never changes
int i = 0;
while (i < 10) {
cout << i << endl;
// Missing: i++
}
// Wrong: Condition always true
for (int i = 10; i > 0; i++) { // Should be i--
cout << i << endl;
}
3. Missing Break in Switch
// Wrong: Falls through to next case
switch (x) {
case 1:
cout << "One" << endl;
// Missing break!
case 2:
cout << "Two" << endl;
break;
}
// Correct
switch (x) {
case 1:
cout << "One" << endl;
break;
case 2:
cout << "Two" << endl;
break;
}
4. Modifying Loop Variable
// Dangerous: Modifying i inside loop
for (int i = 0; i < 10; i++) {
if (condition) {
i += 2; // May cause unexpected behavior
}
}
5. Assignment Instead of Comparison
// Wrong: Assignment, always true
if (x = 5) { }
// Correct: Comparison
if (x == 5) { }
6. Empty Loop Body
// Wrong: Semicolon creates empty loop
for (int i = 0; i < 10; i++); // Loop does nothing
{
cout << i << endl; // Error: i is out of scope
}
// Correct
for (int i = 0; i < 10; i++) {
cout << i << endl;
}
Summary
| Control Structure | Use When |
|---|---|
if | Single condition to check |
if-else | Two mutually exclusive paths |
if-else-if | Multiple conditions to check sequentially |
switch | Single variable with multiple discrete values |
for | Known number of iterations |
while | Unknown iterations, check before |
do-while | Unknown iterations, execute at least once |
range-for | Iterating over containers |
break | Exit loop early |
continue | Skip to next iteration |
return | Exit function |
Loop Selection Guide
┌────────────────────────────────────────────────────────────┐
│ WHICH LOOP SHOULD I USE? │
├────────────────────────────────────────────────────────────┤
│ Know iteration count? │
│ YES → Use for loop │
│ NO → Do you need at least one iteration? │
│ YES → Use do-while │
│ NO → Use while │
│ │
│ Iterating over container? │
│ YES → Use range-based for loop │
└────────────────────────────────────────────────────────────┘
Compilation
g++ -std=c++17 -Wall -Wextra examples.cpp -o examples
./examples
Navigation
| Previous | Up | Next |
|---|---|---|
| Operators | Foundations | Working with Data |
Master control flow to write powerful and efficient C++ programs!