C++ Tutorial
C++ Vectors
vector is a resizable array. Prefer it over raw arrays when the length is not known at compile time.
A list that can grow
A raw array has a size the compiler must know: int xs[4]. If you do not know how many values you will get, that type is the wrong tool. vector from the standard library starts empty (or with a count) and grows as you push_back.
Include <vector>. The type is vector<int>, vector<string>, or vector of whatever element type you need. StudyGrid compiles this as C++17.
push_back and size
push_back adds one element at the end. size() returns how many you have. Size is a number of elements, not bytes. It can change after each push.
Example
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> nums;
nums.push_back(8);
nums.push_back(3);
nums.push_back(5);
cout << nums.size() << endl;
return 0;
}Output is 3. You never wrote a capacity in the type. The vector asked the heap for space as needed.
Index with [i]
The first element is still index 0. nums[i] reads or writes that slot, the same idea as a raw array. Valid indices run from 0 to size() - 1. Walking off the end is undefined behavior, just as it is with arrays.
Example
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> nums;
nums.push_back(8);
nums.push_back(3);
nums.push_back(5);
for (int i = 0; i < nums.size(); i++) {
cout << nums[i] << endl;
}
return 0;
}nums[1] = 9; would replace 3. There is also at(i), which throws if the index is out of range. [] does not check. Use [] when you already know i is in range.
Range-for
When you only need the values, not the index, a range-based for loop is shorter. Each step bindsn to the next element.
Example
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> nums;
nums.push_back(8);
nums.push_back(3);
nums.push_back(5);
for (int n : nums) {
cout << n << endl;
}
return 0;
}Write for (int& n : nums) if you need to change each element. Writefor (const int& n : nums) if the elements are large and you only read them. Forint, a copy is cheap.
Strings work the same way
The element type is a template argument. A list of names is vector<string>. Include<string> as well.
Example
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
vector<string> names;
names.push_back("Ada");
names.push_back("Linus");
cout << names.size() << endl;
for (const string& name : names) {
cout << name << endl;
}
return 0;
}Vector versus raw array
| int xs[4] | vector<int> | |
|---|---|---|
| Length | Fixed at compile time | Grows with push_back |
| Header | None | <vector> |
| size() | You track it yourself | Built in |
| Copies | You copy each element | The vector copies as a whole |
Keep raw arrays for tiny fixed tables (days in a week, a 3-D point). For everything you collect while the program runs, start with vector.
Example
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> temps = {12, 9, 15, 11};
int total = 0;
for (int t : temps) {
total += t;
}
cout << "count: " << temps.size() << endl;
cout << "sum: " << total << endl;
cout << "mean: " << total / static_cast<double>(temps.size()) << endl;
return 0;
}What the vector owns
When the vector variable goes out of scope, it frees its buffer. You do not call delete. That is why the next chapter tells beginners to prefer containers over bare new.
Open /cpp/try from the buttons under the examples. Next: how new anddelete work, and why you can often skip them.
Worked examples
The short listings above are there so you can see the grammar. The programs here use the same statements on quantities that already have units: a speed, a pH, a count of bases. They are classroom numbers. Air resistance is ignored. g is 9.81 m/s² unless a line says otherwise.
Open them in the C++ editor at /cpp/try. Change one measurement and check whether the result still has the right unit.
Statistics
Marks in a vector
vector grows. You do not pick a length at compile time. Five marks average 76.8, the same arithmetic as the raw-array chapter, with size() instead of a magic 5.
mean = (Σ xᵢ) / n
Example
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> marks = {72, 81, 64, 90, 77};
int sum = 0;
for (int n : marks) sum += n;
cout << "mean = " << sum / double(marks.size()) << endl;
return 0;
}Physics
Temperatures, then the hottest
push_back appends a reading as it arrives. After five samples the peak is still 19.1 °C. Prefer vector over a raw array when the logger does not know n in advance.
Example
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<double> celsius;
celsius.push_back(18.2);
celsius.push_back(18.5);
celsius.push_back(19.0);
celsius.push_back(18.8);
celsius.push_back(19.1);
cout << "hottest = " << *max_element(celsius.begin(), celsius.end()) << " C" << endl;
return 0;
}