Skip to content

Exercise 10 of 10 · A complete program

The Cafe Ticket

What you will make

A printed cafe receipt with the shop name at the top, three item rows in straight columns, a subtotal, a service charge the program works out itself, a total, and a thank-you line at the bottom.

The one new idea: Assembling a complete program from parts you already know

Nothing in this program is new, and that is the point. Real software is almost never one clever idea; it is a handful of ordinary ones stacked in the order the work happens. Once you can look at a finished program and name the parts, you can read other people's code and keep building your own.

Go straight to the code ↓

Nothing new, all at once

Every exercise so far handed you one new idea and somewhere small to try it. This one hands you no new idea at all. Every line in the editor is something you have already met.

That is what a finished program is. Not one clever trick, but a handful of ordinary ones arranged in the order the work actually happens. Here is this receipt, named piece by piece:

  • #includes at the top bring in exactly the parts of the standard library this file uses: <iostream> for printing, <iomanip> for std::setw, <vector> and <string> for the notes at the bottom.
  • std::cout puts each line on the screen. That was the very first thing you wrote.
  • Variables hold the parts that change: name, qty, price.
  • Arithmetic turns them into amounts: qty * price for one row, subtotal / 10 for a tenth of the bill.
  • An if decides whether the service charge applies to this order at all.
  • std::left/std::right with std::setw is what makes the columns land in a straight line instead of wandering — the same pattern from the scoreboard, reused here on four fields instead of two.
  • A std::vector<std::string> and a range-based for loop print the small notes at the bottom without a separate std::cout for each one.
  • A running total collects the order as it goes, exactly as it collected the week of rainfall.

Eight ideas, none of them new here, all of them in one receipt.

The running total, one more time

subtotal = 0 is declared above the items, and then subtotal = subtotal + cost; appears once per item. It is the same line you wrote for the rainfall week, doing the same job on different values: work out the right-hand side first, using whatever subtotal holds right now, then store the answer back under the same name. The rainfall chart had a loop repeat that line automatically; here the three items sit one under the other, so the line is repeated by hand instead. The pattern does not mind either way.

A worked example

A market stall rather than a cafe, so the receipt in the editor stays yours to finish:

C++
#include <iostream>
#include <iomanip>
#include <string>

int main() {
    int total = 0;

    std::string name = "Apples";
    int qty = 4;
    int price = 12;
    int cost = qty * price;
    total = total + cost;
    std::cout << std::left << std::setw(8) << name << std::right << std::setw(5) << cost << std::endl;

    name = "Bread";
    qty = 1;
    price = 30;
    cost = qty * price;
    total = total + cost;
    std::cout << std::left << std::setw(8) << name << std::right << std::setw(5) << cost << std::endl;

    std::cout << "-------------" << std::endl;
    std::cout << "TOTAL" << std::setw(8) << total << std::endl;
}
Output
Apples     48
Bread      30
-------------
TOTAL      78

Two blocks of the same six lines with different values in them, and a total nobody typed in. Change the 4 to a 5 and both the apples row and the total move with it, because both are calculated rather than written down.

Your turn

Press Run before changing anything. Most of the receipt is already correct: the header, the first two item rows, the service charge, the notes at the bottom.

Two lines are marked, and both of them already run. They are wrong, not missing.

  1. The cake's row still sends its four values to std::cout unformatted, so the numbers land nowhere near the columns above them. Rewrite it to match the two rows above it, using the same std::setw pattern.
  2. total is set to 0, so the bottom of the receipt disagrees with the rest of it. Calculate it from the two values the program already has: the amount for the items, and the service charge.

Then change something — the cake to two slices, the chai to a different price — and run it again. The row, the subtotal, the service charge and the total should all move together. That is the difference between a receipt that is calculated and one that is typed.

If something goes wrong

The likeliest slip is the total, and it announces itself: the TOTAL line shows 0, or a number that does not match the two above it. Check that both names on the right of the = are spelled exactly as they are spelled further up, and that the line sits below the service charge — C++ reads top to bottom, so a value has to exist before it can be added to anything.

If the cake row prints but drifts out of line with the two above it, count the widths rather than guessing. Every row needs exactly 12 for the name, 3 for the quantity, 5 for the price and 6 for the amount, in that order, and std::setw only ever applies to the field directly after it.

Nothing here can break. Change the order, run it again, and read your own receipt.

Write your code

Runs in your browser. Press Run (or Ctrl/Cmd+Enter) and the output is checked for you.

Ctrl/Cmd+Enter to run

Press Esc then Tab to move keyboard focus out of the code editor.

Ready
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

Typing the final total in by hand
The number is right this minute and wrong the moment anything changes. Order two slices of cake instead of one and the rows and the subtotal update themselves, while a hand-typed total sits underneath contradicting them. A total is calculated from the values above it, never copied off the screen.
Giving the cake row different widths from the rows above it
The rows only line up because every one of them gives the name 12 characters, the quantity 3, the price 5 and the amount 6. Change one of those numbers on one row and only that row drifts out of column while the others stay put — and because std::setw resets after each value, a width left off entirely just prints that one field at its natural length instead of raising an error.
Writing total = cost + service
cost holds the amount for the last item only, because each block overwrites it with that item's own figure — the three items were never added into one running number the way subtotal was. The receipt would total 69 instead of 154. subtotal is the variable that has been collecting the whole order.
Declaring int total a second time by accident, such as copying int total = 0; below the real line
Two declarations of the same name in the same block is a redefinition, and the compiler refuses to build the program: error: redefinition of 'total'. Once you have written the real total = subtotal + service; line, the placeholder above it needs replacing, not leaving in place alongside a new one.

Want a blank editor instead? Open the C++ playground.