Variables and Fundamental Types

Variable Scope and Shadowing

Each variable exists in a region of the program where the variable name is known.

This region is known as its scope.

If an inner scope defines a variable with the same name as a variable in an outer scope, then the variable in the inner scope hides the other one. This practice is called shadowing.

Most variables you declare inside a function have block scope.

They are visible from the point of declaration through the end of the closest enclosing curly brace block.

#include <iostream>

int main()
{
    int x{10};

    {
        int y{20};

        std::cout << x << ' '
                  << y << '\n';
    }

    // std::cout << y << '\n';

    std::cout << x << '\n';
}

A variable placed within an inner block is created when the inner block starts and destroyed when it ends.

After the closing brace, its name is no longer in scope, so trying to use it results in a compile error.

Variables that are defined in the outer block are still accessible inside the nested block, but they will be hidden if the inner block declares another variable with the same name.

If you declare a new variable with the same name as a variable that exists in an outer scope, then the new variable hides the outer one.

#include <iostream>

int main()
{
    int value{100};

    {
        int value{200};

        std::cout << value << '\n';
    }

    std::cout << value << '\n';
}

In the nested block, the shared name refers to the nested variable.

The outer variable is still there, but its name is temporarily hidden.

When the inner block ends, the outer name becomes visible again.

Shadowing is allowed, but it usually makes code harder to understand.

The reader needs to remember which variable is currently referred to by a name.

It is possible to declare a variable outside of a loop in order to store a result to be used throughout a function.

If a variable with the same name is declared inside the loop, it will shadow the outer variable.

#include <iostream>

int main()
{
    int total{0};

    // Increment the value before the expression uses it
    for (int i{0}; i < 3; ++i)
    {
        int total{i * 10};

        std::cout << "Inner total: "
                  << total
                  << '\n';
    }

    std::cout << "Outer total: "
              << total
              << '\n';
}

Changes made to the inner variable do not change the outer variable because they are separate objects.

The programmer might have wanted to update the outer variable but created a new variable inside the loop.

The outer value does not change, and it is easy to miss the mistake during a quick scan of the code.

I try to avoid shadowing in almost every situation.

Writing a different name for the inner variable unambiguously reveals the programmer's intent.

Exercise: Variable Scope and ShadowingStarter code, hints and solutionOpenClose
Guided practiceBeginner · 10–15 min

Practice: Variable Scope and Shadowing

Work through the mission, reveal hints only when needed, and compare your result with the model solution.

Your challenge

Change the inner total initializer from i * 10 to i * 20. Predict all inner totals and the final outer total.

Mission checklist

  1. Run the starter as a baseline, then predict the change requested in Your challenge.
  2. Make that change in your editor; use the lesson-specific hints if you need help.
  3. Compile and run your answer, then compare with the worked solution and explain the result.

Starter program

This is the working baseline, not the completed answer. Compile as C++20, then make the change described above.

#include <iostream>

int main()
{
    int total{0};

    // Increment the value before the expression uses it
    for (int i{0}; i < 3; ++i)
    {
        int total{i * 10};

        std::cout << "Inner total: "
                  << total
                  << '\n';
    }

    std::cout << "Outer total: "
              << total
              << '\n';
}

Hints

Hint 1

There are two variables named total. The declaration inside the loop creates a new inner total on each iteration; it does not assign to the outer one.

Hint 2

Make two columns for the two totals. Changing i * 10 changes the inner values only, so check which declaration the final output statement can see.

Worked solution

The inner initializer now multiplies i by 20, producing inner totals 0, 20, and 40. That inner declaration shadows the outer total; the final outer total is still 0.

#include <iostream>

int main()
{
    int total{0};

    // Increment the value before the expression uses it
    for (int i{0}; i < 3; ++i)
    {
        int total{i * 20};

        std::cout << "Inner total: "
                  << total
                  << '\n';
    }

    std::cout << "Outer total: "
              << total
              << '\n';
}

Example output

Inner total: 0
Inner total: 20
Inner total: 40
Outer total: 0

0 comments

No comments yet. Be the first.

Add a comment

About CppLearn

CppLearn is an interactive, free reference for modern C++. In each lesson, you'll find out how the language works, rather than just lines of code that you can copy and paste. We cover concepts starting from beginner lessons on fundamentals and proceed to templates, move semantics, smart pointers, and areas that usually trap or scare C++ learners.