Kodewick
Lesson 11 of 30Contents

vector: a row of boxes

Lesson 11 of 30 · Part 3 · Containers · about 15 minutes

An int variable holds one number. To store a class's scores or a shopping list, use std::vector: a row of boxes side by side, and the number of boxes can change. To use it, #include <vector>.

main.cpp
1#include <iostream>2#include <vector>3 4int main() {5    std::vector<int> scores{90, 85, 77};6    std::cout << "First: " << scores[0] << '\n';7    std::cout << "Count: " << scores.size() << '\n';8    return 0;9}
Output
First: 90
Count: 3

In std::vector<int>, the int in angle brackets says each box holds an int. The values in the boxes are the elements. scores[0] is the first element; the number in square brackets is the index, and it starts at 0. size() tells you how many elements there are now. Press Step and see scores drawn as a row of three boxes.

Making a vector

The usual ways to write it:

You writeYou get
std::vector<int> v;empty, no elements at all
std::vector<int> v{4, 8, 15};three elements: 4, 8, 15
std::vector<int> v(5, 0);five elements, all 0
std::vector<std::string> v;empty, for strings later

Curly braces and parentheses are different: curly braces list the elements themselves; parentheses say "how many, and what each one is".

Guess first

What does this show?

1#include <iostream>2#include <vector>3 4int main() {5    std::vector<int> a(3, 7);6    std::vector<int> b{3, 7};7    std::cout << a.size() << " " << b.size() << '\n';8    return 0;9}

push_back: add to the end

push_back adds a new element at the end, and the vector grows one more box by itself. Press Step and watch the boxes fill one by one:

main.cpp
1#include <iostream>2#include <string>3#include <vector>4 5int main() {6    std::vector<std::string> list;7    std::cout << "Start: " << list.size() << " items\n";8    list.push_back("milk");9    list.push_back("eggs");10    list.push_back("bread");11    std::cout << "Now: " << list.size() << " items\n";12    std::cout << "Last one: " << list[2] << '\n';13    return 0;14}
Output
Start: 0 items
Now: 3 items
Last one: bread

You don't have to say up front how many boxes you need: start with an empty one and add things as they come. That is the most common way to use a vector.

Indexes and loops

v[i] reads an element, and can change it too. To go through every element, let the index run from 0 up to size() - 1:

main.cpp
1#include <iostream>2#include <vector>3 4int main() {5    std::vector<int> scores{90, 85, 77, 68};6    scores[1] = 88;7    int total = 0;8    for (std::size_t i = 0; i < scores.size(); i++) {9        std::cout << i << ": " << scores[i] << '\n';10        total += scores[i];11    }12    std::cout << "Average: " << static_cast<double>(total) / scores.size() << '\n';13    return 0;14}
Output
0: 90
1: 88
2: 77
3: 68
Average: 80.75

The index i is a std::size_t: an integer type that is never negative, made for sizes and indexes, and the type size() gives you.

Note: Because size() is never negative, size() - 1 on an empty vector is not -1 but a huge number. Write i < v.size(), not i <= v.size() - 1.

Going out of range

The vector below has only three elements, so the index can only be 0, 1 or 2. What happens when you read prices[5]?

main.cpp
1#include <iostream>2#include <vector>3 4int main() {5    std::vector<int> prices{12, 30, 8};6    std::cout << "First: " << prices[0] << '\n';7    std::cout << "Sixth: " << prices[5] << '\n';8    return 0;9}
Output
First: 12
Sixth: 
index out of range

What happened: Stopped at line 7. This goes past the end of a vector, an array or a string. Real C++ would read or overwrite whatever is next in memory.

Square brackets don't check the index. With a real compiler this is undefined behavior: it may show a strange number, it may crash, or it may look like nothing went wrong, which is the most dangerous case. Our engine stops on that line and tells you where it went out of range.

at(i) gets an element just like [i], but checks the index first. If the index is wrong, it throws a std::out_of_range exception; when nothing handles the exception, the program ends right there:

main.cpp
1#include <iostream>2#include <vector>3 4int main() {5    std::vector<int> prices{12, 30, 8};6    int sixth = prices.at(5);7    std::cout << "Sixth: " << sixth << '\n';8    std::cout << "This line never runs either\n";9    return 0;10}
Output
terminate called after throwing an instance of 'std::out_of_range'
  what():  vector::_M_range_check: __n (which is 5) >= this->size() (which is 3)
Aborted (core dumped)

The program ends on the at(5) line, and nothing after it runs. The terminate called after throwing an instance of 'std::out_of_range' and Aborted (core dumped) on the page are what a g++ program shows on your own computer too; the what(): line in between says exactly what happened: index 5 (__n), but only 3 elements (size()). Lesson 26 shows how to catch an exception and keep the program going.

Tip: When you aren't sure an index is right, use at(): a mistake shows up at once instead of quietly reading a strange number.

First and last

You writeWhat it does
v.front()the first element, same as v[0]
v.back()the last element, same as v[v.size() - 1]
v.pop_back()removes the last element
v.empty()true when there are no elements
main.cpp
1#include <iostream>2#include <string>3#include <vector>4 5int main() {6    std::vector<std::string> todo{"groceries", "electric bill", "laundry"};7    std::cout << todo.front() << ", " << todo.back() << '\n';8    todo.pop_back();9    std::cout << todo.size() << " left, the last is " << todo.back() << '\n';10    while (!todo.empty()) {11        todo.pop_back();12    }13    std::cout << todo.size() << " left\n";14    return 0;15}
Output
groceries, laundry
2 left, the last is electric bill
0 left

while (!todo.empty()) means "while there is something left". An empty vector has no first or last element: front(), back() or pop_back() on it is undefined behavior, so check empty() first.

Copying and passing to functions

Assigning one vector to another copies all the elements. After that, each one is on its own:

Guess first

What does this show?

1#include <iostream>2#include <vector>3 4int main() {5    std::vector<int> a{1, 2, 3};6    std::vector<int> b = a;7    b[0] = 100;8    std::cout << a[0] << " " << b[0] << '\n';9    return 0;10}

Parameters work the same way: a plain std::vector<int> parameter copies the whole vector. Just like strings in lesson 10, pass const std::vector<int>& to only read it, and std::vector<int>& to change it:

main.cpp
1#include <iostream>2#include <string>3#include <vector>4 5int total_price(const std::vector<int>& prices) {6    int total = 0;7    for (std::size_t i = 0; i < prices.size(); i++) {8        total += prices[i];9    }10    return total;11}12 13void add_item(std::vector<int>& prices, int price) {14    prices.push_back(price);15}16 17int main() {18    std::vector<int> cart{12, 30};19    add_item(cart, 8);20    std::cout << cart.size() << " items, $" << total_price(cart) << " in all\n";21    return 0;22}
Output
3 items, $50 in all

Practice

Write the code, then press Check. A hint costs nothing; the answer is there when you need it.

Exercise 1

A week of steps

steps holds the step counts for seven days. Add them up with a loop and show Total steps: 51300.

It should print
Total steps: 51300
exercise1.cpp
1#include <iostream>2#include <vector>3 4int main() {5    std::vector<int> steps{6200, 8100, 7500, 9000, 5400, 10300, 4800};6 7    return 0;8}
Output
Press Run or Ctrl+Enter
Exercise 2

A numbered shopping list

Start with an empty list, push_back rice, oil and salt in that order, then use a loop to show the list numbered from 1.

It should print
1. rice
2. oil
3. salt
exercise2.cpp
1#include <iostream>2#include <string>3#include <vector>4 5int main() {6    std::vector<std::string> list;7 8    return 0;9}
Output
Press Run or Ctrl+Enter
Exercise 3

Fix it: the last one, off by one

This program wants to show the last price but goes out of range. Fix it so it shows Last: 45.

It should print
Last: 45
exercise3.cpp
1#include <iostream>2#include <vector>3 4int main() {5    std::vector<int> prices{20, 35, 45};6    std::cout << "Last: " << prices[prices.size()] << '\n';7    return 0;8}
Output
Press Run or Ctrl+Enter

What you learned

  • std::vector<type> is a row of boxes and needs #include <vector>. Curly braces list the elements; (n, x) is n copies of x.
  • push_back adds to the end and pop_back removes the last one; size() is the number of elements and empty() tells whether there are none.
  • v[i] reads and changes an element; the index runs from 0 to size() - 1, so loop with i < v.size().
  • v[i] out of range is undefined behavior; v.at(i) out of range throws std::out_of_range and the program ends.
  • front() and back() are the first and last elements; don't use them on an empty vector.
  • Assigning copies the whole vector; pass it to functions as const std::vector<int>& (to read) or std::vector<int>& (to change).