Arrays and vectors
Starting out12 min readLesson 6 of 6
6.1 Many values under one name
A collection stores several values of the same type. An array has a fixed size chosen when it is created. A std::vector can grow and shrink at runtime. Both keep their elements next to each other in memory and use indexes that start at zero.
Use an array when the count is known and will not change. Use a vector when the number of entries depends on input or grows during the program. Vectors also carry their size, which removes a common source of errors.
#include <iostream>
int main() {
int marks[4] = {72, 85, 91, 64};
std::cout << "First: " << marks[0] << "\n";
std::cout << "Last: " << marks[3] << "\n";
return 0;
}Output
First: 72 Last: 64
6.1.1 Fixed arrays
An array declaration names the element type and the number of elements: int marks[4];. You can initialize it with a brace list, and the compiler fills the remaining elements with zero. int marks[] = {72, 85, 91, 64}; lets the compiler count the elements.
The valid indexes are 0 through size - 1. Accessing marks[4] in a four-element array reads past the end. C++ does not check a plain array subscript, so the program can produce garbage, crash, or appear to work. Check the index before using it.
The standard library also provides std::array<int, 4> from <array>. It has a fixed size like a raw array and keeps that size available through .size(). Raw arrays remain common in older code and in function parameters, so learn both forms.
#include <iostream>
int main() {
double prices[] = {2.5, 4.0, 1.5, 3.0};
double total = 0.0;
for (double price : prices) {
total += price;
}
std::cout << "Items: " << sizeof(prices) / sizeof(prices[0]) << "\n";
std::cout << "Total: " << total << "\n";
return 0;
}Output
Items: 4 Total: 11
6.1.2 Walking through an array
A counted for loop works when you need the index. A range-based for loop works when you only need each value.
for (int mark : marks) copies each element into mark. With for (int& mark : marks), mark refers to the element, so changes reach the array. With for (const int& mark : marks), the loop reads without copying and cannot modify. For small integers a copy is cheap. For strings or large objects, a const reference avoids the copy.
#include <iostream>
int main() {
int marks[] = {72, 85, 91, 64};
for (int& mark : marks) {
mark += 5;
}
for (int mark : marks) {
std::cout << mark << "\n";
}
return 0;
}Output
77 90 96 69
6.1.3 Vectors that grow
Include <vector> and write std::vector<int> scores; for an empty vector. push_back adds to the end, pop_back removes the last element, and .size() reports the element count. front() and back() read the ends.
You can also initialize with a list: std::vector<double> prices = {2.5, 4.0};. Vector indexes work the same way as array indexes. The .at() function performs a bounds check and throws std::out_of_range when the index is invalid. Use .at() when the index comes from user input or a calculation that might be wrong.
#include <iostream>
#include <vector>
int main() {
std::vector<int> scores;
scores.push_back(70);
scores.push_back(85);
scores.push_back(92);
std::cout << "Count: " << scores.size() << "\n";
std::cout << "First: " << scores.front() << "\n";
std::cout << "Last: " << scores.back() << "\n";
return 0;
}Output
Count: 3 First: 70 Last: 92
6.1.4 Size, indexes, and empty containers
size() returns an unsigned type, often std::size_t. Comparing it with a signed int can produce warnings. Prefer std::size_t or std::vector<int>::size_type for an index that walks a vector.
Do not call front() or back() on an empty vector. Check .empty() first when the container might be empty. The same rule applies to an array: know its length before indexing.
#include <iostream>
#include <vector>
int main() {
std::vector<double> temps = {21.5, 23.0, 19.5, 22.0};
double total = 0.0;
for (double t : temps) {
total += t;
}
std::cout << "Average: " << total / temps.size() << "\n";
return 0;
}Output
Average: 21.5
6.1.5 A worked comparison
Suppose a class stores marks for exactly four tests. An array fits because the count is fixed. Suppose a quiz can accept any number of questions. A vector fits because the count is unknown. The access syntax looks similar: marks[0] works for both.
Vectors can reallocate their storage when they grow. A pointer or reference into the vector can become invalid after a size change. Beginner code should avoid storing long-lived references to vector elements while modifying the vector.
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> tasks = {"read", "code", "test"};
tasks.at(1) = "write";
tasks.push_back("review");
for (const std::string& task : tasks) {
std::cout << task << "\n";
}
return 0;
}Output
read write test review
6.1.6 Common mistakes
- Forgetting that the last index is one less than the length.
- Mixing the element count with the last index.
- Asking an empty vector for its first element.
- Forgetting
#include <vector>or#include <string>. - Assuming a plain array knows its own size. Use
std::sizeor pass the length along. - Modifying a vector while a range-based loop is walking it. Add or remove elements in a separate loop.
6.1.7 Practice
- Store five temperatures in an array and print the highest value.
- Move the same values into a vector and add one more before printing.
- Reverse the output with a counted loop that starts at
size - 1. - Print the average and then read about
<iomanip>to control the number of decimal places.
