본문으로 건너뛰기 C++ Loops Masterclass: for, while, do-while, Range-for,

C++ Loops Masterclass: for, while, do-while, Range-for,

C++ Loops Masterclass: for, while, do-while, Range-for,

이 글의 핵심

Choose the right loop: counted for, condition-driven while, do-while for at-least-once, range-based for, break/continue rules, off-by-one, and floating-point loop pitfalls. Complete guide with practical examples.

The for Loop

The for loop packages initialization, condition, and increment together — ideal when you know the iteration count or range up front:

#include <iostream>

int main() {
    // Count from 1 to 5
    for (int i = 1; i <= 5; i++) {
        std::cout << i << ' ';
    }
    std::cout << '\n';  // 1 2 3 4 5

    // Count down
    for (int i = 5; i >= 1; i--) {
        std::cout << i << ' ';
    }
    std::cout << '\n';  // 5 4 3 2 1

    // Step by 2
    for (int i = 0; i < 10; i += 2) {
        std::cout << i << ' ';
    }
    std::cout << '\n';  // 0 2 4 6 8
}

The three parts of the for header are all optional. Any of them can be empty:

int i = 0;
for (; i < 5; ) {
    std::cout << i << ' ';
    i++;
}
// Same as while (i < 5) { ...; i++; }

The while Loop

while is best when the number of iterations isn’t known in advance:

#include <iostream>

int main() {
    // Read until the user enters 0
    int n;
    int sum = 0;
    std::cout << "Enter numbers (0 to stop): ";
    while (std::cin >> n && n != 0) {
        sum += n;
    }
    std::cout << "Sum: " << sum << '\n';
}
// Retry until success
int attempts = 0;
bool connected = false;
while (!connected && attempts < 3) {
    connected = tryConnect();
    attempts++;
}
if (!connected) {
    std::cerr << "Failed after 3 attempts\n";
}

The do-while Loop

do-while runs the body first, then checks the condition. Use it when the body must run at least once:

#include <iostream>

int main() {
    // Input validation — show prompt, read, then check
    int value;
    do {
        std::cout << "Enter a positive number: ";
        std::cin >> value;
    } while (value <= 0);

    std::cout << "You entered: " << value << '\n';
}
// Menu-driven program
int choice;
do {
    std::cout << "1. Play  2. Options  3. Quit\nChoice: ";
    std::cin >> choice;

    switch (choice) {
        case 1: play(); break;
        case 2: showOptions(); break;
    }
} while (choice != 3);

Range-Based for (C++11)

For iterating containers, range-based for is the clearest option:

#include <vector>
#include <string>
#include <iostream>

int main() {
    std::vector<int> nums = {3, 1, 4, 1, 5, 9};

    // By value — copies each element (fine for ints)
    for (int n : nums) {
        std::cout << n << ' ';
    }

    // By const reference — no copy, read-only (use for large types)
    std::vector<std::string> words = {"hello", "world"};
    for (const std::string& w : words) {
        std::cout << w << ' ';
    }

    // By reference — can modify elements
    for (int& n : nums) {
        n *= 2;  // double each element
    }

    // auto — let the compiler deduce the type
    for (const auto& w : words) {
        std::cout << w.size() << ' ';
    }
}

Rule of thumb for element type in range-for:

  • Small types (int, double): use auto or the type by value
  • Large types (string, vector, struct): use const auto& — avoids copy
  • When modifying elements: use auto&

Choosing the Right Loop

LoopBest when
forNumber of iterations known; index needed; iterating 0..n
whileCondition-driven; could run 0 times; EOF or retry patterns
do-whileBody must run at least once; input validation; menu loops
Range-forIterating a container; no index needed

break and continue

break exits the innermost enclosing loop (or switch):

std::vector<int> nums = {2, 5, 3, 8, 1, 7};

// Find first number > 6
for (int n : nums) {
    if (n > 6) {
        std::cout << "Found: " << n << '\n';  // Found: 8
        break;  // stop searching
    }
}

continue skips the rest of the current iteration:

// Print only odd numbers
for (int i = 1; i <= 10; i++) {
    if (i % 2 == 0) continue;  // skip even numbers
    std::cout << i << ' ';
}
// 1 3 5 7 9

break and continue only affect the innermost enclosing loop. They cannot break out of multiple levels at once.


Nested Loops

// Multiplication table
for (int i = 1; i <= 5; i++) {
    for (int j = 1; j <= 5; j++) {
        std::cout << i * j << '\t';
    }
    std::cout << '\n';
}

Exiting Nested Loops

C++ has no labeled break. Options:

Option 1: Use a function and return

// Cleanest approach
std::pair<int,int> findTarget(const std::vector<std::vector<int>>& grid, int target) {
    for (int r = 0; r < (int)grid.size(); r++) {
        for (int c = 0; c < (int)grid[r].size(); c++) {
            if (grid[r][c] == target) {
                return {r, c};  // return exits both loops
            }
        }
    }
    return {-1, -1};  // not found
}

Option 2: Flag variable

bool found = false;
for (int r = 0; r < rows && !found; r++) {
    for (int c = 0; c < cols && !found; c++) {
        if (grid[r][c] == target) {
            found = true;
            result = {r, c};
        }
    }
}

Option 3: goto (use sparingly)

// Only with team agreement — goto is clearer than complex flag logic here
for (int r = 0; r < rows; r++) {
    for (int c = 0; c < cols; c++) {
        if (grid[r][c] == target) goto done;
    }
}
done:

Common Mistakes

Off-by-One Errors

The most common loop bug. Use half-open ranges [0, n) consistently:

std::vector<int> v = {10, 20, 30, 40, 50};

// WRONG: i <= v.size() — goes one past the end (undefined behavior)
for (int i = 0; i <= (int)v.size(); i++) {
    std::cout << v[i] << '\n';  // v[5] is out of bounds
}

// CORRECT: i < v.size()
for (int i = 0; i < (int)v.size(); i++) {
    std::cout << v[i] << '\n';
}

// Better: use range-for when index not needed
for (int x : v) {
    std::cout << x << '\n';
}

Stray Semicolon

for (int i = 0; i < 10; i++);  // semicolon — empty loop body
{
    std::cout << "runs once after the loop\n";  // NOT inside the loop!
}

// Correct:
for (int i = 0; i < 10; i++) {
    std::cout << i << '\n';
}

Floating-Point Loop Counter

// WRONG — floating-point accumulation error may miss the exit condition
for (double x = 0.0; x != 1.0; x += 0.1) {
    // x may never equal exactly 1.0 due to rounding
    // loop may run forever or stop at wrong value
}

// CORRECT — integer counter, compute float from it
for (int i = 0; i < 10; i++) {
    double x = i * 0.1;  // 0.0, 0.1, 0.2, ..., 0.9
    // process x
}

Modifying a Container While Iterating

std::vector<int> v = {1, 2, 3, 4, 5};

// WRONG — erasing invalidates the iterator
for (auto it = v.begin(); it != v.end(); ++it) {
    if (*it % 2 == 0) {
        v.erase(it);  // iterator is now invalid!
    }
}

// CORRECT — erase returns next valid iterator
for (auto it = v.begin(); it != v.end(); ) {
    if (*it % 2 == 0) {
        it = v.erase(it);  // it now points to next element
    } else {
        ++it;
    }
}
// v: {1, 3, 5}

Practical Examples

Prime Number Sieve

#include <vector>
#include <iostream>

std::vector<int> sieve(int n) {
    std::vector<bool> is_prime(n + 1, true);
    is_prime[0] = is_prime[1] = false;

    for (int i = 2; i * i <= n; i++) {
        if (is_prime[i]) {
            for (int j = i * i; j <= n; j += i) {
                is_prime[j] = false;
            }
        }
    }

    std::vector<int> primes;
    for (int i = 2; i <= n; i++) {
        if (is_prime[i]) primes.push_back(i);
    }
    return primes;
}

int main() {
    auto primes = sieve(50);
    for (int p : primes) std::cout << p << ' ';
    // 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
}

Fibonacci Sequence

#include <iostream>

int main() {
    int n = 10;
    long long a = 0, b = 1;

    for (int i = 0; i < n; i++) {
        std::cout << a << ' ';
        long long next = a + b;
        a = b;
        b = next;
    }
    // 0 1 1 2 3 5 8 13 21 34
}

Key Takeaways

  • for for known iteration counts and ranges; while for condition-driven loops; do-while when body runs at least once
  • Range-based for is the cleanest way to iterate containers — use const auto& for large types
  • break exits the innermost loop only; continue skips to the next iteration
  • Off-by-one: use i < n (not i <= n) with zero-based indexing; range-for avoids this entirely
  • Floating-point counters: use integer counters and compute the float — never test float == float as a loop condition
  • Nested loop exit: refactor into a function with return, or use a flag variable
  • Modifying containers while iterating: use it = v.erase(it) pattern or use algorithms like std::remove_if

Frequently Asked Questions (FAQ)

Q. When would I use this in practice?

A. Choose the right loop: counted for, condition-driven while, do-while for at-least-once, range-based for, break/continue …

Q. What should I read before this?

A. Follow the previous article or related articles links at the bottom of each post to learn in sequence. See the C++ series index for the full picture.

Q. Where can I study this more deeply?

A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers C++, for, while, loops, control flow.