Arrays Vectors
By the end of this lesson you'll be able to store a whole list of values in one variable, read and change any item by its index, and grow a collection on demand with std::vector int — the container you'll reach for in almost every C++ program you write.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
Part of the free C++ course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
A C-style array is a fixed row of post-office boxes . You decide how many boxes to build, and that number can never change. Each box has a number on it starting at 0 , and you reach a box by its number — scores[0] , scores[1] , and so on. There's no security guard: if you ask for box number 5 on a 5-box wall (boxes 0–4), nobody stops you — you just grab whatever is in the next bit of wall, which is a bug.
A std::vector is the same wall of boxes, but magic and expandable : you can add a new box on the end any time with push_back , it always knows how many boxes it has with size() , and its .at() door has a guard that refuses an invalid box number. That's why modern C++ reaches for vector first.
1. C-Style Arrays
An array stores many values of one type in a single named block. You declare it as type name[count] , and you reach each value by its index — an offset that starts at 0 . So int a[5] holds five ints at indexes 0, 1, 2, 3, and 4; the last valid index is always count - 1 . Two things to burn in now: the size is fixed (you can't grow it), and there is no bounds checking (reading past the end is undefined behaviour, not an error). Read this worked example, run it, then you'll write your own.
Your turn. The program below is almost complete — fill in the three blanks marked ___ using the hints, then run it. Watch the indexes carefully.
2. std::array — a Safer Fixed Array
A C-style array forgets its own length, so you end up passing a separate size around by hand. std::array type, count fixes that: it's still fixed-size and lives on the stack like a raw array, but it knows its size() and offers a bounds-checked .at() . You need #include array to use it. Reach for it when the count is known up front and never changes.
3. std::vector — the One You'll Use Most
A vector is a resizable array. You add to the end with push_back , ask how big it is with size() , and read items with [] (fast, unchecked) or .at() (checked — it throws if the index is invalid). front() and back() grab the first and last item, and a range-based for visits every element without you managing an index. You need #include vector . For almost every list of data, this is the container to use.
Now you build one. Start from an empty vector and add items to it, then read it back. Fill in the blanks:
4. 2D Vectors (a Grid)
Sometimes data is a grid — a board, a spreadsheet, an image. A vector vector int is a vector whose elements are themselves vectors, so you index it with two brackets: grid[row][col] . The outer size() gives the number of rows, and grid[row].size() gives the columns in that row. A nested for visits every cell.
v[i] trusts you completely — it does no bounds checking . If i is out of range you get undefined behaviour : maybe a crash, maybe garbage, maybe a silent corruption that bites you ten lines later. It's the fast path for indexes you've already validated (like a clean for loop).
v.at(i) does the same read but checks the index first and throws a std::out_of_range exception if it's invalid. Use it whenever the index could be wrong — for example, an index that came from user input. A loud, immediate error beats a mysterious one.
No blanks this time — just a brief and an outline to keep you on track. Build it, run it, and check your output against the example in the comments. Finding the max and the sum of a list is a pattern you'll use constantly.
Practice quiz
What is the index of the FIRST element in a C-style array?
- 1
- 0
- -1
- It depends on the type
Answer: 0. Array indexing starts at 0; the first element sits 0 steps from the start.
For an array of size 5, what is the last valid index?
- 5
- 6
- 4
- 0
Answer: 4. Valid indexes are 0..size-1, so the last is 4 for a size-5 array.
What is true about a C-style array's size?
- It grows automatically
- It is fixed and cannot grow
- It is always 10
- It changes with push_back
Answer: It is fixed and cannot grow. C-style arrays are fixed-size; you cannot push_back or grow them.
Which container is the resizable, grow-on-demand array of modern C++?
- std::array
- C-style array
- std::vector
- std::list only
Answer: std::vector. std::vector resizes on demand and is the go-to container in modern C++.
Which method adds an element to the end of a std::vector?
- append()
- push_back()
- add()
- insert_end()
Answer: push_back(). push_back() adds an element to the end and grows the vector.
What is the difference between v[i] and v.at(i)?
- They are identical
v.at(i) checks bounds and throws std::out_of_range; v[i] does no checking.
Which header must you include to use std::vector?
- <array>
- <vector>
- <list>
- <collection>
Answer: <vector>. std::vector requires #include <vector>.
How do you index a 2D vector named grid at row 1, column 2?
- grid(1,2)
A vector of vectors is indexed with two brackets: grid[row][col].
What does reading a[5] on a size-5 array cause?
- A compile error
- Undefined behavior
- It returns 0
- It throws std::out_of_range
Answer: Undefined behavior. Index 5 is out of range on a size-5 array; C-style [] does no bounds checking, so it is undefined behavior.
What does grid.size() return for a 2D vector?
- The total number of cells
- The number of rows
- The number of columns
- Always 1
Answer: The number of rows. The outer size() gives the number of rows; grid[r].size() gives that row's columns.