Range-Based for Loops: “Do This for Each Value”

Sometimes you don’t want to count; you want to act on each element of a known set. The range-based for loop expresses exactly that:

for (/* element */ : /* range */) {
    // do something with element
}

It reads naturally: “for each element in this range.” This is great for finite sums/products, evaluating a function at a handful of sample points, or scanning a short list of special cases.

We’ll later use range-based loops with arrays and standard containers (vectors, maps, …). For now, our examples use only initializer lists like {1, 3, 5} so we don’t rely on topics we haven’t covered yet.

Syntax in one glance

for (int k : {1, 3, 5, 7, 9}) {
    // k takes values 1, 3, 5, 7, 9 (in that order)
}
  • The part before the colon declares a new variable that receives each element in turn.
  • The part after the colon is any range expression. Here it’s an initializer list { ... }.
  • Use braces {} for the loop body—even for one line—for clarity.

Example 1 — A finite sum over a selected set

Compute \(\sum_{k \in {1,3,5,7,9}} k^2\):

#include <iostream>

int main() {
    int sum = 0;

    for (int k : {1, 3, 5, 7, 9}) {
        sum = sum + k * k;
    }

    std::cout << "Sum of odd squares = " << sum << '\n';
    return 0;
}

This pattern matches math notation directly: pick exactly the indices you care about and add them up.

Example 2 — Horner’s method via coefficients

Evaluate \(P(x) = 2x^3 – 3x^2 + 0x + 1\) using Horner’s method (coefficients from highest to lowest):

#include <iostream>

int main() {
    double x;
    std::cout << "Evaluate P(x)=2x^3-3x^2+0x+1 at x = ";
    std::cin >> x;

    double y = 0.0;
    for (double c : {2.0, -3.0, 0.0, 1.0}) {
        y = y * x + c;   // Horner step
    }

    std::cout << "P(" << x << ") = " << y << '\n';
    return 0;
}

Here the range is the finite list of coefficients.

Example 3 — Early exit with break: first small divisor test

Scan a small set of primes and stop at the first hit:

#include <iostream>

int main() {
    int n;
    std::cout << "Enter n (>= 2): ";
    std::cin >> n;

    int first_divisor = -1;

    for (int d : {2, 3, 5, 7, 11, 13, 17, 19}) {
        if (n % d == 0) {
            first_divisor = d;
            break;               // we’re done scanning the set
        }
    }

    if (first_divisor == -1) {
        std::cout << "No small prime divisor found\n";
    } else {
        std::cout << "First small prime divisor: " << first_divisor << '\n';
    }
    return 0;
}

break exits the loop immediately (ties back to the previous post).

Example 4 — Skip cases with continue: sum only positives

#include <iostream>

int main() {
    int sum = 0;

    for (int v : {3, -1, 4, 0, -2, 5}) {
        if (v <= 0) {
            continue;            // ignore non-positive values
        }
        sum = sum + v;
    }

    std::cout << "Sum of positives = " << sum << '\n';
    return 0;
}

This matches a common mathematical “filter”: include only values that satisfy a property.

Example 5 — Sampling a function at chosen points

Evaluate \(f(x)=x^2\) at a few handpicked points:

#include <iostream>

int main() {
    double total = 0.0;

    for (double x : {0.0, 0.25, 0.5, 0.75, 1.0}) {
        total = total + x * x;
    }

    std::cout << "Sum of samples of x^2 = " << total << '\n';
    return 0;
}

Range-based loops shine whenever you want to name the points explicitly.

Notes and gotchas (for now)

  • The loop variable receives a copy of each element here; that’s fine for numbers.
  • With initializer lists, elements are not modifiable (there’s nothing to mutate). We’ll see how to iterate by reference once we introduce arrays and containers.
  • Range-based for doesn’t give you an index automatically. If you need one, keep a counter:
int i = 0;
for (int k : {2, 4, 6, 8}) {
    // use i as the position (0,1,2,3)
    i = i + 1;
}
  • If you simply need to repeat a fixed small number of times, a classic for is clearer. A range like {0,0,0,0,0} also works—but it’s a teaching trick, not a habit.

Mini-reference

  • Form: for (Type name : {v1, v2, v3}) { ... }
  • Works today with initializer lists; later with arrays and containers.
  • break ends the loop; continue skips to the next element.

What’s next

We’ll revisit range-based loops when we cover arrays and standard containers—that’s where they really shine. For now, keep them in mind whenever your problem is naturally “for each chosen value, do X.”