Video Coming Soon...
16: Basic Containers
You've been using simple data types like integers (int
) and strings (string
) so now it's time you learn about containers. A container is a piece of code that knows how to hold multiple similar pieces of data into a structure. The structure can be something like a list, a key=value
store, or even a matrix that's similar to an Excel spreadsheet. Programmers typically call these structures by the incredibly creative name of "data structures"...because they...structure...the data.
Really, any time you think programmers are insane geniuses just remember they're regular people too who will name things fairly closely to what they actually do. This may help you avoid overthinking solutions in the future.
Introducing vector
In this exercise we'll learn a single data structure called the vector
. A "vector" is simply a fancy name for an ordered (but not sorted) list of things. I think the name was chosen mostly to make it sound more fancy than it actually is. You put things in it, find those things, take things out, just like you might a list of names for a party.
The "things" you can put in a vector
are any data type that C++ can identify and knows its size. That means, string
, int
, and even other another vector
, but don't do that yet.
Code Example
Here is an example of using a vector
to store a list of int
numbers.
View Source file ex16.cpp Only
#include <fmt/core.h>
#include <vector>
using namespace fmt;
using std::vector;
int main() {
vector<int> ages = {10,34,25,19,87,5};
println("I have {} cousins of different ages:", ages.size());
size_t i = 0; // initializer
while(i < ages.size()) { // test
int cousin_age = ages.at(i);
println("cousin #{} is {} years old.", i, cousin_age);
++i; // incrementer
}
}
I want you to get this working and walk through the code with me. Then you're going to complete a series of challenges to learn more.
Code Walkthrough
Instead of doing each line by number I'm going to instead talk about pieces of code directly. Everything else you already know, so I'm going to stop holding your hand and make you study the code yourself more and more.
#include <vector>
- This is how you tell C++ you want to use vectors in your code.
using std::vector;
- If you don't do this then you have to type
std::vector
all the time so C++ knows where thevector
is. Remember that thestd
is anamespace
that holds a lot of built-in C++ modules. vector<int> ages = {10,34,25,19,87,5};
- This creates the list of your cousins' ages. You first state you want a
vector
, then you have to say what type thisvector
holds. The<int>
is how you indicate the type. Next you give it a nameages
and set it equal to the list of ages. The{}
syntax may look like your code blocks, but when you see it used like this it is an initializer and it will be used in C++ a lot. Finally, your list of numbers has each number separated by a,
(comma). println("I have {} cousins of different ages:", ages.size());
- Now for the best part, you can "ask"
ages
how big it is (how manyint
it holds) by typingage
a.
and the function namesize()
. You already now about functions so this is a new style that is kind of like doingsize(ages)
but targeted directly atages
. You'll learn more about this when you learn about Object Oriented Programming but think about this like "askingages
do to something" or "sendingages
thesize()
command." size_t
- This isn't a line, but just this one keyword. A
size_t
is a special integer that is only positive and typically used to index into data structures. We use this instead of anint
because you can't askages
for negative indexes. int cousin_age = ages.at(i);
- You should know how your
while
loop works already, but this one line is new. Theint cousing_age =
part isn't new. What is new is theages.at(i)
. This does pretty much what it says, "ages
, give me theint
at indexi
." It is probably self-explanatory but you'll notice when you run this code thati
is going to go from0
to5
rather than what you would expect of1
to6
.
That should be all the new stuff. If there's something you don't understand be sure to figure out how you missed it and study this as much as possible. Definitely, definitely play with this code before you continue.
Why 0
Indexing
Humans normally think about lists of things in order. If you think of dates on a calendar we have "first", "second", "thirty-first", and so on. If you watch people run a marathon you'd ask things like, "Who came in first place?" This use of the "st" and "nd" in words like "first" and "second" tells me that this is an "ordered" list. I can't have "second place" without having "first place." I can't have the "second of the month" without having the "first of the month."
A vector
isn't a strictly ordered list though. You can grab elements from it at any point. If you want the 4th cousin's age you just write vector.at(4)
so there really isn't a "first" element. Instead we have to say, "I want the cousin at index 3" to get the 4th cousin.
This is different from the days of a month because you can't time travel and jump forward or backward in time to any random date you want. Dates are strictly ordered, and that means they use an ordered numbering scheme starting at 1. Random structures like vector
start with 0
because to make random access math work right you need to start at 0. All kinds of indexing math doesn't work right if you start at 1. Some languages like Lua do start at one, and they are annoying to deal with when you need random indexing math.
So, the way you translate from "human who lives in a world with time and only deals with strictly ordered things" to a "human who must pick a random thing out of a vector" is you use this formula:
Ask what ordered one you want, then subtract one to get the random index.
This means if you say, "I want the FOURTH cousin's age." Then you have an ordered number 4, so subtract 1 and you get 3. You want index 3, so ages.at(3)
.
Challenge Time
I will now give you a series of challenges to accomplish using this code. You should be able to do all of these with only what you know so far, but if you get stuck jump to the end and read the documentation for vector
mentioned in Further Study.
- Make a
vector
ofstring
that holds your cousins names. If you don't have that many cousins jsut use the names of fruits and veggies. - In the
while-loop
print both the cousin's name and their age using onlyi
for the index to both vectors. - When you index into a
vector
you start at0
so that certain math works, but most humans find this weird. Change yourprintln()
to make it more human without breaking youri
index. - Add up all the ages for all your cousins then print the total and average ages after the loop.
- After the loop print one line for the 4th cousin, then 2nd cousin, and the 6th cousin. Remember your "human ordered to random index" math.
Breaking It
Breaking this code is super easy:
- Instead of using
ages.size()
use a fixed number, then change theages
vector to have fewer contents. - Give
ages.at()
a negative number. - Give
ages.at()
a way bigger number. - Remove the
++i
incrementer and watch the world burn. - Give fewer names than
ages
in your modified challenge code. - Get rid of the
using std::vector
to see what C++ says about your mistake.
Get creative. There's many ways to break this, and in Further Study you'll get even more by reading the documentation. Go crazy, because breaking your own code is how you get familiar with errors and reduce your fear of making mistakes.
Further Study
- Read the documentation for
vector
. - Get all of the examples on this page working. You may not understand everything there, but you should be able to get it working.
- See how much of the example code you can study to learn more. Usually you can click on anything you don't recognize in the code and it will go to the documentation for that thing.
- You should also definitely take note of the alternative
ages[i]
syntax toages.at(i)
and rewrite your code to use that. Also redo your Breaking It with this new way of indexing.
Register for Learn C++ the Hard Way
Register to gain access to additional videos which demonstrate each exercise. Videos are priced to cover the cost of hosting.