Chapter 8
Loops: Doing It Again Until It's Done
while, for, break, and the runaway loop you will definitely write.
So far every line you write runs once. If you want something ten times, you type it ten times, which you noticed at the end of chapter 5, copying the same four lines with different words in them.
A loop does the repeating for you.
while
int count = 1;
while (count <= 3) {
std::cout << "count is " << count << '\n';
++count;
}
count is 1
count is 2
count is 3
The shape is the same as an if: a condition in brackets, a block in braces. The
difference is what happens at the closing brace: instead of carrying on, C++ goes
back and checks the condition again. Run, check, run, check, until the condition
is false.
That ++count is new, and it’s the whole reason this loop ends.
Adding one
++count means “add one to count”. It’s such a common thing to do that it has its
own operator.
++count; // count = count + 1
count++; // also count = count + 1
Both work. There’s a difference between them, but it only shows up when you use
the result inside a bigger expression, which this book won’t do, because it
makes code harder to read for no gain. Prefer ++count and don’t think about it
again.
The loop that never ends
Take out the ++count and read what’s left:
int count = 1;
while (count <= 3) {
std::cout << "count is " << count << '\n';
}
count is 1. One is less than three, so the block runs. Nothing changes count.
So one is still less than three. Forever.
Your terminal fills with text and doesn’t stop. Press Ctrl-C. That’s the universal “stop this program”. Hold control and press C, in the terminal window where it’s running. You’ll use it more in your first month than in all the years after.
for
Counting loops all have the same three parts: start somewhere, keep going while
something is true, and change something each time round. for puts all three on
one line:
for (int i = 0; i < 3; ++i) {
std::cout << "i is " << i << '\n';
}
i is 0
i is 1
i is 2
Read the brackets as three instructions separated by semicolons:
| Part | Meaning |
|---|---|
int i = 0 | before the loop starts, make i and set it to 0 |
i < 3 | keep looping while this is true |
++i | after each pass, do this |
It’s exactly the while loop from earlier with the pieces gathered up where you
can see them. Nothing new happens, but the thing that makes a loop end is now
impossible to leave out by accident, which is why counting loops are almost always
written this way.
Note where it starts and stops. i runs 0, 1, 2: three passes, starting at
zero, never reaching 3. That’s deliberate: it matches how string positions work
from chapter 4, so a loop over name.size() characters lines up without any
awkward adjusting.
Leaving early
break gets you out of a loop immediately, wherever you are in it:
for (int i = 0; i < 10; ++i) {
if (i == 3) {
break;
}
std::cout << "i is " << i << '\n';
}
i is 0
i is 1
i is 2
The loop was told to run ten times and stopped after three. break is how you
leave when you’ve found what you were looking for, or when something’s wrong.
There’s also continue, which skips the rest of this pass and starts the next
one. It has its uses; in beginner code it usually makes a loop harder to follow
than an if would. Worth knowing the word, not worth reaching for yet.
Loops that read input
This is where two chapters collide, and the result is nastier than either alone.
Chapter 5 showed that typing letters into an int leaves it at 0 and jams cin
so every later read does nothing. Put that inside a loop:
const int secret = 42;
int guess = 0;
while (guess != secret) {
std::cout << "Guess: ";
std::cin >> guess;
std::cout << " you said " << guess << '\n';
}
Type abc once and you get this, forever:
Guess: you said 0
Guess: you said 0
Guess: you said 0
Guess: you said 0
It never pauses for you again. The read fails instantly every time, guess never
changes, so the condition never changes. That’s the runaway loop from earlier, with
a cause you can’t see by staring at the loop.
Exercise 1 · Write one, then break it
Print the numbers 1 to 10 with a for loop. Then print them backwards, starting
at 10, condition i >= 1, and --i to count down.
Now make one on purpose: write the countdown with ++i instead of --i and run
it. Watch it climb away from 1 and never stop, and practise Ctrl-C while the
stakes are zero.
Check yourself
Project
The number guessing game
Roughly 45 minutes
The program picks a number. You guess. It tells you higher or lower. It counts how many tries you took.
Your guess: 10
Higher.
Your guess: 80
Lower.
Your guess: 42
Got it in 3 attempts.What it needs:
- a
const int secret, hardcoded for now, say 42 - a
guessand anattemptscounter, both starting at 0 - a
whileloop that keeps going until the guess matches - an
if/else ifinside it for higher and lower
Two things to get right. The counter goes up on every guess including the
last one, so increment it right after reading. And there’s no else telling them
they were correct inside the loop. The loop ending is what means they got it,
so that message belongs after the closing brace.
Stretch one, a real random number. Hardcoding a secret makes for a short game. This picks one between 1 and 100:
#include <random>
std::random_device seed;
std::mt19937 generator(seed());
std::uniform_int_distribution<int> between(1, 100);
const int secret = between(generator);Borrowed machinery, like setprecision in chapter 6. Copy it and carry on.
Three lines, and every run is a different game.
Stretch two, limit the guesses. Give them seven tries. If they run out,
tell them the answer. This is what break is for, and you’ll need to work out
afterwards whether they won or lost, which is harder than it sounds.