When trying to visualize a vector, you should think of the name of the vector as a box containing a list of values. For example, you should imagine that the code `vector<int> counts = {12, 6, 3, 14}` creates something like this:
There are times when we will just use the name of the vector to refer to the whole package. But most of the time, we want to access one of the elements of the vector. To do so we use the same syntax that we do with strings. We use the .at(index) function to specify the element we wish to work with:
cout << "The first element is " << counts.at(0) << endl;
You can use the element retrieved by .at(index) as if it was a variable that contains that one element. You can assign it new values and use any appropriate operators on the result:
counts.at(0) = 7; // change the first element to 7
counts.at(1) = counts.at(0) * 2; // change the second element to twice the first
++counts.at(2); // increment the third element
counts.at(3) -= 6; // reduce the fourth element by 6
Note that the naming of elements can be tricky. The first element has the index 0. So some programmers refer to it as the โzerothโ element. But that means โfirstโ can refer to the element at index 0 or 1, depending on the convention being used. For this reason, it is often best to explicitly refer to items by their index โthe item at index 1โ is much clearer than โfirstโ. In this book, if we use casual language (first, second, etc...) it will be to refer to the โhuman numberingโ of elements where โfirstโ means the first, not the item at index 1. When using C++ numbering (0 based), we will refer to โthe element at index Xโ or โelement index xโ.
If you use .at(index) to ask for an index that is not valid (less than 0 or >= .size()), there will be a runtime error when that statement executes. This program runs fine until we try to access counts.at(4):
As usual, the error message is a little cryptic. The important part is the out_of_range message. This means that the index you provided was not valid. After that, there is vector::_M_range_check: __n (which is 4) >= this->size() (which is 4). This tells us that the problem comes from a vector and we asked for index 4 in a vector with size of 4. Unfortunately, we do not get a line number, so we have to use print statements or a debugger to help track down the exact location.
As with strings, vectors support bracket notation (vectorName[index]) notation for accessing elements. However, when using that syntax, there is no bounds checking. You can ask for element 100 in a 4 element vector and will be given some piece of memory that is unrelated to the vector (it will be whatever is in memory where element 100 would be if it existed).
This kind of unchecked access is one of the most important sources of bugs in code (do a web search for โbuffer overflowโ). The very minimal overhead required by the safe syntax (.at(index)) is worth it to avoid these kinds of bugs in the vast majority of situations.
Construct a block of code that changes the first element of vec to a 6, multiplies the third element of vec by 2, and increments the last element of vec by 1 (in that order). This should work no matter what vec is.