Video Coming Soon...
17: Classic for-loops
You are now going to learn about using for-loops in C++ to process lists of items. You should have the documentation for vector open while you do this exercise for reference.
Problems With while-loops
The while-loop has a problem because you can get it wrong very easily. You can forget the initializer, forget to increment, or maybe you make the incrementer too complex. You can also get the test wrong. Because of this it's difficult to reason about when a while-loop will end. This becomes even more of a problem when the while-loop gets more complicated over time.
Classic for-loop as Solution
To solve the problems with while-loops there's three general solutions:
- The topic of this exercise which I'm calling "classic for-loops" that take the elements necessary for awhile-loopand make them obvious and explicit.
- The topic of the next exercise called "range for-loops" where you allow thevectorto control the looping, effectively ensuring it will always end.
- A future topic called "functional programming" to run code over your data and/or tell your data to run functions for you.
The Code
This code is exactly the same as the previous code but it uses a for-loop instead of a while-loop to iterate through the age vector:
View Source file ex17a.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());
  for(size_t i = 0; i < ages.size(); i++) {
    int cousin_age = ages.at(i);
    println("cousin #{} is {} years old.", i, cousin_age);
  }
}
Code Walkthrough
I'll skip the usual starting code you have to write, as it's similar to the previous exercise and will only focus on the part with the for-loop. You should open both ex16.cpp and this ex17a.cpp file to compare them side-by-side:
- 12
- This starts the for-loopand consists of three parts separated by;(semi-colon) characters. First is the initializer which issize_t i = 0; then there's the test which isi < ages.size(); and finally the incrementer which isi++. This matches my comments fromex16.cppfor thewhile-loopbut all on one line.
- 13
- This line gets a cousin's age from agesusingages.at(i)just like in thewhile-loopversion.
- 14
- Then just print it out like normal using println().
The way to think about a for-loop's initialization is it's like three lines of code every while-loop needs smashed onto a single line with ; characters. You can actually do this with any C++ code. Imagine I want to create an integer, add a number to it, and print it:
int i = 0;
i += 10;
println("i={}", i);
I could simply put all those on one line like this:
int i = 0; i += 10; println("i={}", i);
That's because C++ doesn't care as long as you have ; separating things. That's effectively what a for-loop does. It just takes those three lines you'd normally have to write for a while-loop and pulls them up to the top on one line (separated by ;).
Challenge Mode
Here's another example that's more complicated and shows a ffew more features of both for-loops and vector:
View Source file ex17.cpp Only
#include <fmt/core.h>
#include <vector>
using std::string, std::vector;
using namespace fmt;
int main() {
  vector<string> fruit = {
    "Apple", "Orange", "Pear",
    "Grape", "Durian", "Mango"
  };
  // loop through fruit
  for(size_t i = 0; i < fruit.size(); i++) {
    println("Fruit #{} is {}", i, fruit[i]);
  }
  // another way to get it using at()
  for(size_t i = 0; i < fruit.size(); i++) {
    println("Fruit #{} is {}", i, fruit.at(i));
  }
  // set them all to something else
  vector<string> guitars = {
    "Stratocaster", "Telecaster", "Bass VI",
    "P-Bass", "ASAT Special", "G&L S500"
  };
  for(size_t i = 0; i < guitars.size(); i++) {
    println("Changing fruit #{} to guitar {}", i, guitars[i]);
    fruit[i] = guitars[i];
  }
  for(size_t i = 0; i < fruit.size(); i++) {
    println("Fruit...I mean Guitar #{} is {}", i, fruit.at(i));
  }
}
As usual do not blast all this code in one session the try to fix it. Get this working a little bit at a time, compiling and running constantly as you work.
Once you get this working I then want you to take everything you know about vector and use for-loops to work with them. You can start with the documentation for vector and study each operation possible. Try to get as many to work as you possibly can with what you know, and any take notes on any that you don't understand.
WARNING: Remember that challenge sections like this are meant to push your understanding, not to make you feel like a failure. You can't fail these because I'm not grading you and I don't care how well you do. You won't impress me or disappoint me. Your only goal is to learn what you can and come back when you learn more.
Breaking It
Breaking classic for-loops is harder but not impossible:
- If you're using ias an iterator then try changing it inside thefor-loopso that the loop never ends.
- We're using size_twhich is a large number that isunsigned long inton most platforms. If you take a0number of this type and subtract one it will "underflow" and become the largest number possible on your computer. See if you can do this on accident so your loops don't end.
- A simpler one is to not use vector::size()as inages.size()to set the ending of the loop. This happens if you use a variable in one place for the size, but then give thevectora different number of items.
Further Study
Look at other data structures you can use. Try some of these:
Again, try to use them but don't worry if they don't make sense yet. In the great words of a Jedi Master:
"There is only try, no fail." -- Gandalf
I think that's what he said. It's been a while since I've seen Fight Club.
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.