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
autoor the type by value - Large types (string, vector, struct): use
const auto&— avoids copy - When modifying elements: use
auto&
Choosing the Right Loop
| Loop | Best when |
|---|---|
for | Number of iterations known; index needed; iterating 0..n |
while | Condition-driven; could run 0 times; EOF or retry patterns |
do-while | Body must run at least once; input validation; menu loops |
Range-for | Iterating 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
forfor known iteration counts and ranges;whilefor condition-driven loops;do-whilewhen body runs at least once- Range-based
foris the cleanest way to iterate containers — useconst auto&for large types breakexits the innermost loop only;continueskips to the next iteration- Off-by-one: use
i < n(noti <= n) with zero-based indexing; range-for avoids this entirely - Floating-point counters: use integer counters and compute the float — never test
float == floatas 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 likestd::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++ if / else / switch: Conditionals, Pitfalls, and switch](/en/blog/cpp-if-switch-guide/
- [C++ Functions: Parameters, Return Values, Overloading, and](/en/blog/cpp-function-basics/
- C++ STL vector | ‘배열보다 편한’ 벡터 완벽 정리 [실전 예제]
이 글에서 다루는 키워드 (관련 검색어)
C++, for, while, loops, control flow 등으로 검색하시면 이 글이 도움이 됩니다.