c++pointersdereference

How does a reference variable in a range-based for loop allow you to change container elements?


I'm exploring how reference variables work within range-based for loops in C++. While I understand that "&" typically refers to memory addresses in pointer contexts, its behavior in loops seems different.

I have two examples:

  1. Modifying the Original String:
#include <iostream>
#include <string>
int main() { 
     std::string a = "HELLO";
     for (char &x : a) {
          x = tolower(x);
     }
     std::cout << a;
     return 0;
}
  1. Not Modifying the Original string:
#include <iostream>
#include <string>
int main() {
     std::string a = "HELLO";
     for (char x : a) {
          x = tolower(x);
     }
     std::cout << a;
     return 0;
}

Question:

Most resources I've found discuss range-based loops generally, but it's don't explain this reference behavior clearly. Could someone break down what's happening?


Solution

  • The ranged based for-loop:

    for (char &x : a) {
       // ...
    }
    

    Is practically the same as this pre-C++11 loop:

    for(std::string::iterator it = a.begin(), end = a.end(); it != end; ++it) {
        char& x = *it; // declares a reference to an existing instance of char
        // ...
    }
    

    That is, the dereferencing of the iterator, it above, is done by the built-in range based for loop, and the variable you bind to the result, x, is declared as a reference, hence you can then modify what it's referencing.

    Note: Make sure that you never pass a negative value to the <cctype> functions (like std::tolower). Always cast to an unsigned char:

    x = std::tolower(static_cast<unsigned char>(x));