본문으로 건너뛰기
Previous
Next
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

자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. Choose the right loop: counted for, condition-driven while, do-while for at-least-once, range-based for, break/continue … 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

C++, for, while, loops, control flow 등으로 검색하시면 이 글이 도움이 됩니다.