3

I have read about scope and have thought that I understood it up to now. I had a problem with another program and while trying to fix it I found that variables in the scope of a loop behave quite unusually to what I expected. So I made this program to show what I mean:

#include <iostream>

using namespace std;

int main()
{
    int num = 6;
    for (int i = 0; i < 5; i++)
    {
        cout << num;
        int num = 5;
        cout << num;
    }
}

I expected for the first run through of the for loop, the first cout << num would be undefined as it is a new scope and num hasn't been defined yet. But instead, it just used the value of num from the previous scope. Then when num is initialized to 5 inside of the loop, after that, all the outputs for num should be 5. But instead the output was 656565...

So using this information I made a model of what I think the scope of variables worked like and it looks like this:

Scope Diagram

So in the image you can see how I think the scope works and I think that for each iteration through the loop, the loop gets a new scope of variables and then removes its scope at the end of the loop and gets a new one at the beginning of the next iteration which explain why the for loop uses num from the previous scope until num is re-initialized in the current scope. Is my understanding correct?

melpomene
  • 84,125
  • 8
  • 85
  • 148

3 Answers3

4

Is my understanding correct?

Yes but num is not re-initialized. It defines another variable.
"inner" num shadows the "outer" num.

Since both nums have block scope, as per basic.scope.block:

A name declared in a block is local to that block; it has block scope. Its potential scope begins at its point of declaration and ends at the end of its block. A variable declared at block scope is a local variable.

int main() {
   int num = 6; // block scope (a) ---- point of declaration for (a) begins
   for (int i = 0; i < 5; i++)
   {
      cout << num; // uses (a)
      int num = 5; // block scope (b) ---- point of declaration for (b) begins
      cout << num; // uses (b)         ||
   }               //                 ---- (b) goes out of scope here
} // ---- (a) goes out of scope here
Joseph D.
  • 11,804
  • 3
  • 34
  • 67
2

Your diagram is correct if scope 1 is the most outer scope and scope 4 is the most inner scope. Your use of the word "overwritten" is not the convention for C++. The variables are not overwritten but rather shadowed. Similar shadowing is part of many programming languages.

snow_abstraction
  • 408
  • 6
  • 13
1

I expected for the first run through of the for loop, the first cout << num would be undefined as it is a new scope and num hasn't been defined yet. But instead, it just used the value of num from the previous scope. Then when num is initialized to 5 inside of the loop, after that, all the outputs for num should be 5. But instead the output was 656565...

Your understanding here is incorrect, and the output you are seeing is correct.

Within the loop, the first cout << num will print the variable num that was defined before the loop. The second will print the variable that was defined inside the loop.

The int num = 5 in the loop does not affect the previously defined variable (in the outer scope). It defines a completely new variable, and initialises that to 5. There is no impact whatsoever on the value of the num that was defined before the loop. Therefore the num defined outside will keep the value 6, and the one defined inside (created in every loop iteration) will have the value 5. Although your code gives them the same name (num) they are completely distinct variables, and occupy different addresses in memory - so changing one does not change the other.

Practically your code

int num = 6;
for (int i = 0; i < 5; i++)
{
    cout << num;
    int num = 5;
    cout << num;
}

is notionally equivalent to

int num = 6;
for (int i = 0; i < 5; i++)
{
    cout << num;
    {                   //  note another scope introduced here
        int num = 5;
        cout << num;
    }
}

This notional equivalence results from requirements in a standard that, if multiple variables of automatic storage duration are created in a block, that they cease to exist in reverse order of their order of construction. (i.e. if you track calls of constructors and destructors of class objects, the most recently constructed object of automatic storage duration will be destructed first).

The cout statements cannot access a value of num unless it is in the current scope or in a containing scope. Viewing it this way, therefore, means that the first cout << num only has visibility of the outer num (the one initialised to 6) and not the inner one. Whereas the second cout << num accesses the variable defined in the inner scope.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • Im not very familiar with constructors and destructors but the last paragraph answered my question, thanks –  Jun 17 '18 at 12:09