Exercise 9 of 10 · Putting it together
Rainfall Week
What you will make
A seven-day rainfall chart with a row for every day, the week added up underneath it, and the wettest of the seven days picked out.
The one new idea: A variable made before a loop carries a running total from pass to pass
Adding up as you go, and holding on to the best value you have seen, are two patterns sitting underneath an enormous number of ordinary programs: a basket total, a high score, a longest streak, a progress bar. Each one is a variable made before a loop and changed inside it.
Go straight to the code ↓A variable that outlives one pass of the loop
There is no new syntax in this exercise. A std::vector, a range-based for, an if, std::setw, + —
you have met every piece of it. That is the point. Knowing five things separately is not the same as getting
them to work together in one program, and the gap between those two is where most people stall.
The idea that joins them up is small, but it matters: a variable declared before a loop is still standing on every pass, and still standing after the loop ends, so whatever one pass leaves in it is what the next pass finds. Declare that same variable inside the loop instead, and the declaration runs again every time round, discarding whatever the pass before it left there — and in C++, a variable declared inside a loop's braces stops existing the moment that pass finishes, so trying to read it afterwards is not even legal. Anything the loop must carry from one day to the next has to live above it.
Two things are worth carrying that way here.
A running total. Declare a variable at zero above the loop, and inside the loop write
total = total + mm;. C++ works out the right-hand side first — whatever total was a moment ago, plus this
pass's value — and stores the answer back under the same name. After seven passes it holds the sum of all
seven days.
The best so far. Declare a second variable at zero above the loop, then inside the loop ask whether this
pass beats it: if (mm > wettest_mm) {. When it does, store the new number. That variable then holds the
largest value seen up to that moment — and after the final pass, the largest so far is simply the largest
there is.
Remembering which day was wettest is one more line, not a new idea: inside the same if, store the day
alongside the amount. They change together because they are one fact in two halves.
A worked example
Four coins from a jar, with the running total printed on every pass so you can watch it climb:
#include <iostream>
#include <vector>
int main() {
std::vector<int> coins = {2, 5, 1, 5};
int total = 0;
int biggest = 0;
for (int coin : coins) {
total = total + coin;
if (coin > biggest) {
biggest = coin;
}
std::cout << "coin " << coin << " total " << total << std::endl;
}
std::cout << "biggest coin: " << biggest << std::endl;
}coin 2 total 2
coin 5 total 7
coin 1 total 8
coin 5 total 13
biggest coin: 5total never drops back to zero, because the line that sets it to zero sits above the loop and runs once,
before any counting starts. biggest ends on 5 — and notice it does not change on the last pass, even
though that coin is a 5 too: 5 > 5 is false, so a tie leaves the first record standing.
Your turn
The editor holds a week of rainfall in rain, a std::vector<int> of seven measurements in millimetres, and
the loop already prints a row for each one: a day number, a bar of one # per millimetre, and the
measurement itself. Day two was dry, so its bar is empty — that is correct, not broken, since zero
millimetres draws zero # characters.
Press Run first. The chart is correct; the two lines beneath it are not. The total reads 0 mm, and the
wettest day comes out as day 0, which is not one of the seven.
Both of your additions go inside the loop, after the std::cout that is already there:
- Add this day's rain to
total. - If this day beats
wettest_mm, store both the new amount and the day number.
total, wettest_mm and wettest_day already exist above the loop, all holding zero — you are not
declaring them, only changing them as the loop goes round. The counter day = day + 1; already shows the
shape your first new line needs.
If something goes wrong
If the compiler stops on use of undeclared identifier 'mm', a line meant for inside the loop has ended up
after its closing brace — mm belongs to the loop's own scope and stops existing the moment that brace is
reached.
If the millimetres come out right but the wettest day stays at 0, the if is updating wettest_mm and
forgetting wettest_day. Both lines belong inside the if, indented one step further than the if itself.
Nothing here can break. Once the week adds up, change one of the numbers in rain and run it again: the bar,
the total and the wettest day should all move on their own.
Write your code
Runs in your browser. Press Run (or Ctrl/Cmd+Enter) and the output is checked for you.
Press Esc then Tab to move keyboard focus out of the code editor.
Output will appear here after you run your code.The runtime is starting in the background. You can type now — it will be ready before you are.
The answer appears here once you have run your code at least once.
Things that often go wrong here
- Writing total = total + mm; after the loop's closing brace instead of inside it
- A line placed after the for loop's } runs once, after every day has already gone past. By that point mm no longer exists at all — it was declared inside the loop's parentheses and its scope ended with the loop — so the line will not even compile: error: use of undeclared identifier 'mm'. That refusal is actually useful here: in most other languages the same mistake compiles and silently uses a stale value instead of catching your attention.
- Setting total back to 0 inside the loop
- Put total = 0; as the first line inside the loop and every day wipes out the days before it, so the final total is just the last day's rain. A starting value belongs above the loop, where the line that sets it runs exactly once.
- Remembering the amount but not the day
- An if that updates only wettest_mm leaves wettest_day holding the zero it started with, so the last line claims the wettest day was day 0, which is not one of the seven days. Both lines belong inside the same if, because they are two halves of one fact — the day a record was set, and what the record was.
- Writing if (mm = wettest_mm)
- This compiles. One equals sign overwrites wettest_mm with whatever mm currently holds, and the if then reads that new value — true on every day except the one where rain happened to be exactly zero. The chart above would still be correct, which makes a wrong wettest-day line at the bottom easy to mistake for a different kind of bug.
Want a blank editor instead? Open the C++ playground.