Video Coming Soon...

Created by Zed A. Shaw Updated 2024-11-15 13:50:32

18: Range for-loops

There's one more way to iterate (loop through) items called a range-for. The range-for is easier to use for 90% of your looping tasks, but it does have a small problem which I'll discuss later. I recommend using the range-for to do most of your list processing, followed by classic for-loop for the rest, and only use while-loop in very raare situations.

The Problem with for-loops

The problem with the classic for-loop is it's only a formal way to write a while-loop. You are still manually writing an "initializer", "test", and "incrementer" but it's in one place instead of spread around like in a while-loop. Still, you can write your for-loops wrong or accidentally misuse it in some situations. For example, if you do this:

vector<string> fruit = {
  "Apple", "Orange", "Pear",
  "Grape", "Durian", "Mango"
};

for(int i = 0; i < fruit.size(); i++) {
  println("EVEN FRUIT {}", fruit[i]);
  i += 1; // oops, problems?
  println("ODD FRUIT {}", fruit[i]);
}

This code isn't something you'll do on purpose, but you may accidentally alter the variable without realizing it. Still, it is reasonablly difficult to abuse a for-loop compared to a while-loop so they aren't wrong to use, and many times they're the right thing to use (see below).

The range-for Alternative

The range-for takes advantage of the fact that most C++ containers (vector, array, etc.) have information that describes their contents. Since a vector knows how many elements it contains, the vector can control the loop for you. The range-for leverages this information to do the loop automatically for you:

vector<string> fruit = {
  "Apple", "Orange", "Pear",
  "Grape", "Durian", "Mango"
};

for(auto name : fruit) {
  println("FRUIT {}", name);
}

This will loop the same as the classic for-loop but you don't have to manually track a counter, test it's within range, or even get the variable for the contents. I read for(auto name : fruit) as "for name of fruit" but you could also say "for name in fruit".

The Problem with range-for

There are two problems with range-for to be aware of:

  1. There is an official bug in range-for related to "temporary" variables. It's a bit too out of scope for this point in the course, but you can see a possible example of it in the code below. The way to avoid the bug for now is to only loop over contents of a variable, not the results of calculations. We'll cover it more later.
  2. It's difficult to get the current index in a range-for. You can do it, but it's just easier to use the classic for-loop if you also need the index.

As an example of #2, if you want to print what number each fruit is at you'd do this:

for(int i = 0; i < fruit.size(); i++) {
  println("Fruit #{} is {}", i+1, fruit[i]);
}

The Code

The code for this exercise is large, so take it slow:

View Source file ex18.cpp Only

#include <fmt/core.h>
#include <vector>

using std::string, std::vector;
using namespace fmt;

/* This is a function, just get this working for now
 * and we'll cover them soon.
 */
vector<string> bug_maker() {
  return {"Boo! I'm a Bug!"};
}

int main() {
  vector<string> fruit = {
    "Apple", "Orange", "Pear",
    "Grape", "Durian", "Mango"
  };

  // loop through fruit
  for(auto name : fruit) {
    println("Fruit is {}", name);
  }

  // set them all to something else
  vector<string> guitars = {
    "Stratocaster", "Telecaster", "Bass VI",
    "P-Bass", "ASAT Special", "G&L S500"
  };


  // loop through guitars
  for(auto name : guitars) {
    println("Guitar is {}", name);
  }

  /*
  for(auto name : bug_maker()[0]) {
    println("Probably Crashing: {}", name);
  }
  */
}

Get this working then we'll study the code.

Study Time

It's time to learn to do your own code walk throughs. You actually know everything in this code, but you need to confirm you know it. Your task for this section is to document each line of the code and explain what it does. As you do this keep track of what you really know, and what you're unclear about. All of your explanations should be simple, so if you find yourself trying to bullshit your way through a description then stop, and go read the documentation and then exercises to refresh your memory.

The best way to document each line is to write a little comment above the line like this:

// print hello to the screen
println("Hello");

NOTE: Sometimes I'll say "to the screen" but I almost always mean into your Terminal window. I don't mean randomly to somewhere on your physical screen. I mention this because some people do think that at first.

Breaking It

In the code for the exercise there's a commented out part that is supposed to possibly cause an error if you run it. I couldn't get it to fail, but maybe you can. Or, maybe it's not quite the cause of the error. I leave this as an advanced topic because to really understand as it's unreliable to trigger.

In general you should avoid this pattern in range-for by only using range-for on actual variables you've assigned, and not on immediate return values from functions.

Challenge Mode: std::find

For an advanced challenge I have this code example ex18b.cpp I want you to study and try to figure out:

View Source file ex18b.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"
  };

  std::string target = "Orange";

  auto found = std::find(fruit.begin(), fruit.end(), target);

  if(found == std::end(fruit)) {
    println("DIDN'T FIND IT");
  } else {
    println("FOUND: {}", *found);
  }
}

I'm not going to tell you what this does. Your job is to research everything in there, find what you don't know, then look it up on cppreference.com on your own. Doing your own research to learn code you don't know is a key part of being a programmer, and I think it's about 30% of what I do all day.

Further Study

Previous Lesson Next Lesson

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.