Skip to content

Exercise 8 of 10 · Vectors

Packing List

What you will make

A travel packing checklist with a banner, one tick-box line for every item on the list, and a footer that counts them for you.

The one new idea: std::vector holds many values in order, and a range-based for loop walks through them

Real programs almost never hold one value at a time. They hold a basket of them — orders, messages, students, rows in a table — and walk through the basket doing the same thing to each one. std::vector and a range-based for loop are how C++ does that, and it is a pairing you will reach for constantly.

Go straight to the code ↓

Many values under one name

Every variable so far has held exactly one thing. A packing list is not like that — it is one thing made of many things, kept in the order you wrote them down.

C++
std::vector<std::string> items = {"Passport", "Charger"};

std::vector is C++'s general-purpose container for a run of values, all of the same type, that can grow or shrink while the program runs. The <std::string> in angle brackets says what kind of values this particular vector holds — a std::vector<std::string> holds text, a std::vector<int> would hold whole numbers, and the compiler will not let you mix the two inside one vector. The curly braces list the starting elements, in order, separated by commas.

A loop that hands you values, not numbers

This is the part worth slowing down on, because it looks like the counting loops you have already written and behaves differently.

C++
for (int n = 0; n < 3; n++) {
    std::cout << n << std::endl;
}

for (const std::string& word : {"yes", "no", "maybe"}) {
    std::cout << word << std::endl;
}
Output
0
1
2
yes
no
maybe

The first loop counts. It hands you 0, then 1, then 2 — three numbers, and you are the one comparing them against the vector's size if you want to reach every element that way. The second loop, the range-based form, does not count at all: it walks along the container and hands you the value sitting there directly, with no index in sight. item in this exercise is one of these — on each pass it refers to whichever element of items that pass has reached.

const std::string& is doing two jobs in that declaration. std::string& means "a reference to the actual element, not a copy of it," which avoids duplicating every string just to look at it. const in front promises the loop will not modify what it is looking at — reasonable for a loop that only prints. You will meet the version without const, for a loop that changes each element in place, later in this path.

.size() asks fresh, every time

items.size() returns how many elements the vector currently holds. Unlike a value you calculated once and stored, it is worked out again on every call, so a vector that has grown since the last time you asked reports the new, larger number without you doing anything else.

A worked example

A shed rather than a suitcase, so the answer to this one stays yours to write:

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

int main() {
    std::vector<std::string> colours = {"red", "green", "blue"};

    for (const std::string& colour : colours) {
        std::cout << "Paint the shed " << colour << std::endl;
    }

    std::cout << colours.size() << " tins on the shelf" << std::endl;
}
Output
Paint the shed red
Paint the shed green
Paint the shed blue
3 tins on the shelf

Three values in the vector, three lines of output, then one line that counted them. Add a fourth colour inside the braces and you get a fourth line and a 4 at the bottom, with nothing else edited.

Your turn

The editor holds a checklist with two items on it. Press Run before changing anything.

The loop is already doing its job: two items in the vector, two lines of output. But both lines read [ ] item, because the line inside the loop prints the word item in plain quotes rather than the value the variable refers to.

Two things to do:

  1. Rewrite the line inside the loop so it prints the value instead, joining "[ ] " and item with << the way the worked example joins fixed text and a variable. Keep the [ ] box and the space after it.
  2. Add "Socks" and "Towel" to the vector, in that order, inside the curly braces.

The footer needs no attention at all. It is already calling .size(), so it will say 4 by itself the moment the two new items are in place.

If something goes wrong

The likeliest slip is leaving the quotes around item in the loop. You will spot it straight away, because every line reads the literal word item rather than a real item, and the number of lines still matches the number of elements — the loop itself was never broken.

If the checklist prints one item fewer than you expect and one line reads two words squashed together, a comma went missing between two entries inside the vector's braces. C++ quietly joins two neighbouring string literals with nothing between them into one, so that is your only warning.

And if the compiler complains about a missing <vector> or an unknown type, check the #include <vector> line at the top is still there — std::vector is declared there, not in <iostream>.

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

Writing for (std::string item : items) without the reference
Dropping the & still compiles and still runs correctly here, because std::string is cheap enough for ten short words that the difference is invisible. It stops being invisible the moment a vector holds larger objects: without &, every pass copies the whole element just to read it, work that a reference skips entirely. The habit of reaching for const std::string& is worth building on a small vector, before it costs anything to have skipped it.
Leaving the item in quotes: std::cout << "[ ] item" << std::endl;
Quotes mean plain text, so every line prints the literal word item rather than whatever the loop is currently holding. The compiler sees nothing wrong with this — a fixed piece of text is a perfectly legal thing to print — so the two identical lines are the only sign something is off.
Forgetting the comma when adding an item to the vector's braces
{"Passport", "Charger" "Socks"} with no comma between two adjacent string literals does not error — C++ silently concatenates neighbouring string literals into one, so the vector ends up with three elements instead of four and one of them reads CargerSocks or similar. The checklist's own output is the only warning you get.
Typing the count into the footer by hand instead of calling .size()
items.size() already tells you exactly how many elements the vector holds, worked out fresh every time the line runs. Replacing it with a typed number means the footer stops telling the truth the next time an item is added or removed.

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