Loops
Reviewed & published by Brayan K
By the end of this lesson you'll be able to repeat code with for, while, and do-while loops, walk through a whole collection with a range-based for, and steer any loop with break and continue — the engine behind processing data, building patterns, and automating work.
Part of the free C++ course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
What You'll Learn
- Write a for loop with init, condition, and update
- Choose between for, while, and do-while correctly
- Walk a whole vector with a range-based for (auto x : vec)
- Avoid copies with for (const auto& x : vec)
- Steer loops with break and continue
- Build patterns and grids with nested loops
💡 Real-World Analogy
A loop is a washing machine cycle. You set it up once (init), it keeps spinning while a condition holds (the timer hasn't finished), and each rotation does the same job (the body) before stepping forward (update). A for loop is a timed cycle — you know it'll run, say, 30 minutes. A while loop is "keep rinsing while the water's still soapy" — you stop when a condition changes, not after a fixed count. A do-while always does at least one spin before it checks whether to stop. Same drum, different rules for when to stop.
📊 Which Loop, When?
| Loop | Best for | Checks condition |
|---|---|---|
| for | A known number of repeats (counting) | Before each pass |
| while | Repeat until a condition changes | Before each pass |
| do-while | Must run at least once (menus, prompts) | After each pass |
| range-for | Visit every item in a collection | Per element, automatically |
1. The for Loop
The for loop packs three things into its header: initialization (set up a counter), a condition (keep going while this is true), and an update (change the counter each pass). Read it as: "start here, keep going while this holds, take this step each time." It's the loop you reach for when you know how many times to repeat. Read this worked example, run it, then you'll write your own.
#include <iostream>
using namespace std;
int main() {
// A for loop has THREE parts: for (init; condition; update)
// init -> runs once at the start (int i = 1)
// condition -> checked BEFORE each pass (i <= 5)
// update -> runs AFTER each pass (i++)
for (int i = 1; i <= 5; i++) {
cout << "Count: " << i << endl; // prints 1, 2, 3, 4, 5
}
// Step by 2 — change only the update part
cout << "Evens: ";
for (int i = 2; i <= 10; i += 2) {
cout << i << " "; // 2 4 6 8 10
}
cout << endl;
// Accumulator pattern: a running total you add to each pass
int sum = 0; // start the box at 0 BEFORE the loop
for (int i = 1; i <= 100; i++) {
sum += i; // sum = sum + i
}
cout << "Sum of 1..100 = " << sum << endl; // 5050
return 0;
}
// ✅ Expected output:
// Count: 1
// Count: 2
// Count: 3
// Count: 4
// Count: 5
// Evens: 2 4 6 8 10
// Sum of 1..100 = 5050Your turn. The program below is almost complete — fill in the two blanks marked ___ using the hints, then run it.
#include <iostream>
using namespace std;
int main() {
// 🎯 YOUR TURN — replace each ___ then press "Run".
// Goal: print the 6 times table (6 x 1 through 6 x 10).
int n = 6;
// 1) Start i at 1
for (int i = ___; i <= 10; i++) { // 👉 the starting number
// 2) Print "6 x i = result"
cout << n << " x " << i << " = " << (n * ___) << endl; // 👉 multiply n by i
}
// ✅ Expected output:
// 6 x 1 = 6
// 6 x 2 = 12
// ... down to ...
// 6 x 10 = 60
return 0;
}2. while and do-while
Use while when you don't know the count up front — you loop until something changes. It checks the condition before the body, so it can run zero times. do-while flips that: it runs the body once first, then checks the condition, so it always runs at least once. The one rule both share: something inside the body must move you toward the condition becoming false, or you'll loop forever.
#include <iostream>
using namespace std;
int main() {
// WHILE — checks the condition FIRST, so it may run zero times.
// Use it when you do NOT know the count up front.
cout << "=== Doubling until 1000 ===" << endl;
int power = 1;
while (power < 1000) { // keep going while power is under 1000
cout << power << " "; // 1 2 4 8 16 32 64 128 256 512
power *= 2; // THE UPDATE — without this it loops forever!
}
cout << endl;
// DO-WHILE — runs the body once, THEN checks. Always runs at least once.
// Perfect for menus and "ask again" prompts.
cout << "\n=== Do-while runs once ===" << endl;
int tries = 0;
do {
cout << "Attempt " << tries << endl; // prints "Attempt 0" even though...
tries++;
} while (tries < 1); // ...the condition is already false-ish
return 0;
}
// ✅ Expected output:
// === Doubling until 1000 ===
// 1 2 4 8 16 32 64 128 256 512
//
// === Do-while runs once ===
// Attempt 03. The Range-Based for
When you just want to visit every item in a collection, the range-based for is cleaner and safer than a counter — there's no index to get wrong. The shape is for (auto x : vec), read as "for each x in vec." Plain auto x makes a copy of each element (fine for small types like int). For bigger items like strings, use const auto& x — the & means "look at the real element, don't copy it," and const promises you won't change it.
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> scores = {90, 75, 60, 100};
// Range-based for: "for each item in the collection".
// No index, no <= bound to get wrong — it just visits every element.
cout << "Scores: ";
for (int s : scores) { // s is a COPY of each element
cout << s << " "; // 90 75 60 100
}
cout << endl;
// 'auto' lets the compiler work out the element type for you.
int total = 0;
for (auto s : scores) { // auto -> int here
total += s;
}
cout << "Total: " << total << endl; // 325
// Use 'const auto&' (reference) to avoid copying — important for big items
// like strings. The & means "look at the real element, don't copy it".
vector<string> names = {"Ada", "Linus", "Grace"};
for (const auto& name : names) { // no copy made; can't modify it
cout << "Hi " << name << endl;
}
return 0;
}
// ✅ Expected output:
// Scores: 90 75 60 100
// Total: 325
// Hi Ada
// Hi Linus
// Hi GraceNow you try. Walk the prices vector with a range-based for and add up the total. Fill in the two blanks:
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 🎯 YOUR TURN — replace each ___ then press "Run".
vector<int> prices = {3, 5, 2, 8};
int total = 0;
// 1) Loop over EACH price in the vector using a range-based for.
// Use const auto& so nothing is copied.
for (const auto& p : ___) { // 👉 the vector to walk through
// 2) Add the current price to the running total
total ___ p; // 👉 the += operator
}
cout << "Total: " << total << endl;
// ✅ Expected output:
// Total: 18
return 0;
}4. break, continue & Nested Loops
break exits a loop immediately — great for stopping as soon as you've found what you wanted. continue skips just the rest of the current pass and jumps to the next one — great for ignoring items you don't care about. And a loop can live inside another loop: the inner loop runs all the way through for every single pass of the outer one, which is how you build grids and patterns.
#include <iostream>
using namespace std;
int main() {
// break — leave the loop IMMEDIATELY (stop searching once found).
cout << "First multiple of 7 above 50: ";
for (int i = 51; i <= 100; i++) {
if (i % 7 == 0) {
cout << i << endl; // 56
break; // done — exit the loop now
}
}
// continue — skip the REST of THIS pass, jump to the next one.
cout << "Odd numbers 1..10: ";
for (int i = 1; i <= 10; i++) {
if (i % 2 == 0) {
continue; // even? skip the cout below
}
cout << i << " "; // 1 3 5 7 9
}
cout << endl;
// Nested loops — a loop inside a loop. The inner one runs fully
// for every single pass of the outer one.
cout << "Star triangle:" << endl;
for (int row = 1; row <= 4; row++) { // outer: one line per row
for (int col = 1; col <= row; col++) { // inner: 'row' stars
cout << "* ";
}
cout << endl; // new line after each row
}
return 0;
}
// ✅ Expected output:
// First multiple of 7 above 50: 56
// Odd numbers 1..10: 1 3 5 7 9
// Star triangle:
// *
// * *
// * * *
// * * * *Pro Tips
- 💡 Prefer the range-based for when you don't need the index — there's no < vs <= boundary to get wrong.
- 💡 Use const auto& for anything bigger than an int (strings, vectors, objects) to skip a needless copy each pass.
- 💡 Accumulator pattern: start a variable before the loop, update it inside. The bedrock of sums, products, and counts.
- 💡 Break early to save work: once a search finds its answer, break out instead of finishing the loop.
Common Errors (and the fix)
- Off-by-one (< vs <=): for (int i = 0; i <= 5; i++) runs 6 times (0–5), not 5. If you want 5 passes use i < 5. Decide whether the last value is included, then match the operator.
- Infinite loop (missing update): a while (x < 10) with no x++ (or x *= 2) inside never ends — the condition can never become false. Make sure the body changes the value being tested.
- Wrong boundary direction: counting down with for (int i = 5; i >= 1; i--) needs -- and >=. Pairing i-- with i <= 5 spins forever.
- Copying in a range-for when you meant to reference: for (auto x : bigStrings) copies every element. For large types use for (const auto& x : bigStrings) — and if you actually want to modify the elements, drop the const and keep the &.
- Declaring the counter outside its scope: a variable declared with int i inside for (int i...) only lives in the loop. Referencing i after the loop gives "'i' was not declared in this scope".
📋 Quick Reference
| Goal | Use | Shape |
|---|---|---|
| Count a known number of times | for | for (int i=0; i<n; i++) { } |
| Repeat until a condition flips | while | while (cond) { } |
| Run at least once (menus) | do-while | do { } while (cond); |
| Visit every item (small type) | range-for | for (auto x : vec) { } |
| Visit every item (no copy) | range-for | for (const auto& x : vec) { } |
| Leave the loop now | break | break; |
| Skip to the next pass | continue | continue; |
Mini-Challenge: Count the Passing Scores
No blanks this time — just a brief and an outline to keep you on track. Build it, run it, and check your output against the example in the comments. This is exactly the kind of small loop real programs are full of.
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 🎯 MINI-CHALLENGE: Count the passing scores
// 1. You have: vector<int> scores = {55, 80, 42, 91, 67};
// 2. A score "passes" if it is 60 or more.
// 3. Loop over the scores (a range-based for is ideal) and COUNT
// how many pass — use a counter you start at 0 before the loop.
// 4. Inside the loop, use 'continue' to skip scores below 60.
// 5. Print: "Passed: X out of 5"
//
// ✅ Expected output:
// Passed: 3 out of 5
// your code here
return 0;
}🎉 Lesson Complete
- ✅ for packs init, condition, and update into one header — use it for a known count
- ✅ while checks first (may run zero times); do-while runs once then checks
- ✅ for (auto x : vec) visits every item; const auto& avoids copies
- ✅ break exits the loop; continue skips to the next pass
- ✅ Nested loops run the inner loop fully for every outer pass — patterns and grids
- ✅ Watch < vs <= for off-by-one, and always update the variable you test
Practice quiz
What are the three parts of a for loop header, in order?
- condition; init; update
- update; init; condition
- init; condition; update
- init; update; condition
Answer: init; condition; update. A for loop is for (init; condition; update).
Which loop checks its condition AFTER running the body, so it always runs at least once?
- do-while
- for
- while
- range-for
Answer: do-while. do-while runs the body first, then checks the condition.
How many times does 'for (int i = 0; i <= 5; i++)' run?
- 5
- 4
- Infinite
- 6
Answer: 6. i takes values 0,1,2,3,4,5 — that is 6 iterations because of <=.
What does 'break' do inside a loop?
- Skips to the next iteration
- Exits the loop immediately
- Restarts the loop
- Pauses for one second
Answer: Exits the loop immediately. break exits the entire loop immediately and continues after it.
What does 'continue' do inside a loop?
- Skips the rest of the current iteration and goes to the next
- Exits the loop
- Ends the program
- Repeats the current iteration
Answer: Skips the rest of the current iteration and goes to the next. continue skips the rest of this pass and jumps to the next iteration.
What is the shape of a range-based for loop over a vector v?
- for (x in v)
- foreach (v as x)
- for (auto x : v)
- for x : v ()
Answer: for (auto x : v). A range-based for is for (auto x : v), read as 'for each x in v'.
Why use 'const auto&' instead of 'auto' in a range-based for over strings?
- It is required syntax
- It avoids copying each element
- It modifies the elements
- It runs the loop backwards
Answer: It avoids copying each element. const auto& references the real element so no copy is made, and const promises not to change it.
What is the most common cause of an infinite loop?
- Using a for loop
- Using break
- Having too many iterations
- Forgetting the update step so the condition never becomes false
Answer: Forgetting the update step so the condition never becomes false. If nothing inside the body moves toward the condition being false, the loop runs forever.
After 'int sum = 0; for (int i = 1; i <= 100; i++) sum += i;', what is sum?
- 100
- 5050
- 5000
- 10100
Answer: 5050. The accumulator adds 1 through 100, which totals 5050.
In nested loops, how often does the inner loop run relative to the outer?
- Once total
- Only on the first outer pass
- Fully, for every single pass of the outer loop
- Half as often
Answer: Fully, for every single pass of the outer loop. The inner loop runs all the way through for every iteration of the outer loop.
Continue this course
- Previous: Control Flow
- Next: Strings (std::string) — Create, modify and search strings with std::string
- Quick reference: C++ cheat sheet
Frequently asked questions
When should I use for vs while vs do-while?
Use a for loop when you know the number of repetitions up front (counting, walking an array). Use while when you loop until some condition changes and don't know the count in advance. Use do-while when the body must run at least once — like showing a menu before checking if the user wants to quit.
What is the difference between break and continue?
break exits the entire loop immediately and continues with the code after it. continue skips only the rest of the current iteration and jumps straight to the next pass. Use break to stop early once you've found what you wanted; use continue to ignore items you don't care about.
What does 'for (auto x : vec)' actually do, and when do I need the & ?
It's a range-based for loop: it visits every element of vec in order without you managing an index. 'auto' lets the compiler deduce the element type. Writing 'auto x' copies each element into x, which is fine for small types like int. Use 'const auto& x' (a reference) for larger types like strings or objects so nothing is copied, and add the const to promise you won't change them.
Why does my loop run forever?
An infinite loop almost always means the condition never becomes false. The usual cause is forgetting the update step — a while loop with no i++ or no power *= 2 inside, so the variable never changes. Make sure every loop changes the value it's testing so the condition eventually fails.
Why is my loop running one time too many or too few?
That's an off-by-one error, and it usually comes down to < vs <=. for (int i = 0; i < 5; i++) runs 5 times (i is 0,1,2,3,4). for (int i = 0; i <= 5; i++) runs 6 times (0 through 5). Decide whether your last value should be included, then pick < or <= to match.