Keep many values under one name: C arrays, std::vector, the range-based for and averaging sensor data.
When you take 100 readings from a sensor, declaring 100 separate variables makes no sense. To keep many values of the same type under one name, we use an array. C++ has raw arrays (inherited from C) and their modern counterpart, std::vector. As a beginner, I recommend using std::vector.
Raw arrays
int arr[5] = {10, 20, 30, 40, 50};
std::cout << arr[0] << ' ' << arr[4] << '\n'; // 10 50
The size must be fixed at compile time, and the array does not know its own length. On top of that, there is no bounds checking: if you write arr[7], the program may not crash; it simply reads or corrupts some other region of memory. A large share of undefined-behavior bugs come from here.
std::vector
std::vector is an array that can grow. Its header is #include <vector>. The element type is given inside angle brackets.
#include <iomanip>
#include <iostream>
#include <vector>
int main() {
std::vector<double> readings = {20.5, 21.0, 19.8, 22.1, 20.6};
readings.push_back(21.4); // add an element at the end
double sum = 0.0;
double smallest = readings[0];
double largest = readings[0];
for (double x : readings) { // range-based for
sum += x;
if (x < smallest) smallest = x;
if (x > largest) largest = x;
}
double average = sum / readings.size();
std::cout << std::fixed << std::setprecision(1);
std::cout << "Number of readings: " << readings.size() << '\n';
std::cout << "Average: " << average << '\n';
std::cout << "Smallest: " << smallest << '\n';
std::cout << "Largest: " << largest << '\n';
return 0;
}
Number of readings: 6
Average: 20.9
Smallest: 19.8
Largest: 22.1
The sum is 125.4 and there are 6 elements, so the average comes out as 20.9.
Common operations
| Operation | What does it do? |
|---|---|
v.push_back(x) | Adds an element at the end |
v.pop_back() | Removes the last element |
v.size() | Gives the number of elements |
v.empty() | Asks whether it is empty |
v[i] | Accesses element i (no bounds checking) |
v.at(i) | Accesses element i, throws an exception if it is out of range |
v.clear() | Removes all elements |
The range-based for
The form for (double x : readings) reads as "for each x in readings". You don't need to keep an index. If you want to change the elements, take a reference with for (double& x : readings); if you are only reading, you can avoid the copy with const double&. We will cover references two lessons from now.
Things to watch out for
size()returns an unsigned integer. Comparing it withint imay trigger a compiler warning; usestd::size_tfor indexes.- Don't try to calculate the average of an empty vector: that means dividing by zero. Check
empty()first. - The elements sit next to each other in memory; this is very fast in terms of the cache.
Embedded systems note: std::vector uses heap memory and reallocates it as it grows. On small microcontrollers this can lead to memory fragmentation and unpredictable delays. If the number of elements is known in advance, it is safer to use std::array<double, 8> (header: <array>) or to reserve space up front with readings.reserve(100).
Array indexes start at 0. The valid indexes of a vector with 6 elements are 0-5. To access the last element, use v[v.size() - 1] or v.back().
Try it yourself
- Add 5 readings of your own to the vector and calculate the average.
- Count the readings above a threshold (e.g. greater than 21).
- Print the readings in reverse order (use
forand an index). - Ask the user for readings with
cin; keep adding them to the vector until 0 is entered.
// Mini quiz
Click an option; you will see right away, with the reason, whether it is correct or not.
Mark it when you finish: your progress is saved and you earn +20 XP.
Tip: ← → keys let you move between lessons.