2.4 — Introduction to local scope

Local variables

Function parameters, as well as variables defined inside the function body, are called local variables (as opposed to global variables, which we’ll discuss in a future chapter).

In this lesson, we’ll take a look at some properties of local variables in more detail.

Local variable lifetime

In lesson 1.3 -- Introduction to objects and variables, we discussed how a variable definition such as int x; causes the variable to be instantiated (created) when this statement is executed. Function parameters are created and initialized when the function is entered, and variables within the function body are created and initialized at the point of definition.

For example:

The natural follow-up question is, “so when is an instantiated variable destroyed?”. Local variables are destroyed in the opposite order of creation at the end of the set of curly braces in which it is defined (or for a function parameter, at the end of the function).

Much like a person’s lifetime is defined to be the time between their birth and death, an object’s lifetime is defined to be the time between its creation and destruction. Note that variable creation and destruction happen when the program is running (called runtime), not at compile time. Therefore, lifetime is a runtime property.

For advanced readers

The above rules around creation, initialization, and destruction are guarantees. That is, objects must be created and initialized no later than the point of definition, and destroyed no earlier than the end of the set of the curly braces in which they are defined (or, for function parameters, at the end of the function).

In actuality, the C++ specification gives compilers a lot of flexibility to determine when local variables are created and destroyed. Objects may be created earlier, or destroyed later for optimization purposes. Most often, local variables are created when the function is entered, and destroyed in the opposite order of creation when the function is exited. We’ll discuss this in more detail in a future lesson, when we talk about the call stack.

Here’s a slightly more complex program demonstrating the lifetime of a variable named x:

In the above program, x’s lifetime runs from the point of definition to the end of function main. This includes the time spent during the execution of function doSomething.

Local scope

An identifier’s scope determines where the identifier can be accessed within the source code. When an identifier can be accessed, we say it is in scope. When an identifier can not be accessed, we say it is out of scope. Scope is a compile-time property, and trying to use an identifier when it is not in scope will result in a compile error.

A local variable’s scope begins at the point of variable definition, and stops at the end of the set of curly braces in which they are defined (or for function parameters, at the end of the function). This ensures variables can not be used before the point of definition (even if the compiler opts to create them before then).

Here’s a program demonstrating the scope of a variable named x:

In the above program, variable x enters scope at the point of definition and goes out of scope at the end of the main function. Note that variable x is not in scope anywhere inside of function doSomething. The fact that function main calls function doSomething is irrelevant in this context.

Note that local variables have the same definitions for scope and lifetime. For local variables, scope and lifetime are linked -- that is, a variable’s lifetime starts when it enters scope, and ends when it goes out of scope.

Another example

Here’s a slightly more complex example. Remember, lifetime is a runtime property, and scope is a compile-time property, so although we are talking about both in the same program, they are enforced at different points.

Parameters x and y are created when the add function is called, can only be seen/used within function add, and are destroyed at the end of add. Variables a and b are created within function main, can only be seen/used within function main, and are destroyed at the end of main.

To enhance your understanding of how all this fits together, let’s trace through this program in a little more detail. The following happens, in order:

  • execution starts at the top of main
  • main‘s variable a is created and given value 5
  • main‘s variable b is created and given value 6
  • function add is called with values 5 and 6 for arguments
  • add‘s variable x is created and initialized with value 5
  • add‘s variable y is created and initialized with value 6
  • operator+ evaluates expression x + y to produce the value 11
  • add copies the value 11 back to caller main
  • add‘s y and x are destroyed
  • main prints 11 to the console
  • main returns 0 to the operating system
  • main‘s b and a are destroyed

And we’re done.

Note that if function add were to be called twice, parameters x and y would be created and destroyed twice -- once for each call. In a program with lots of functions and function calls, variables are created and destroyed often.

Functional separation

In the above example, it’s easy to see that variables a and b are different variables from x and y.

Now consider the following similar program:

In this example, all we’ve done is change the names of variables a and b inside of function main to x and y. This program compiles and runs identically, even though functions main and add both have variables named x and y. Why does this work?

First, we need to recognize that even though functions main and add both have variables named x and y, these variables are distinct. The x and y in function main have nothing to do with the x and y in function add -- they just happen to share the same names.

Second, when inside of function main, the names x and y refer to main’s locally scoped variables x and y. Those variables can only be seen (and used) inside of main. Similarly, when inside function add, the names x and y refer to function parameters x and y, which can only be seen (and used) inside of add.

In short, neither add nor main know that the other function has variables with the same names. Because the scopes don’t overlap, it’s always clear to the compiler which x and y are being referred to at any time.

Key insight

Names used for function parameters or variables declared in a function body are only visible within the function that declares them. This means local variables within a function can be named without regard for the names of variables in other functions. This helps keep functions independent.

We’ll talk more about local scope, and other kinds of scope, in a future chapter.

Where to define local variables

Local variables inside the function body should be defined as close to their first use as reasonable:

In the above example, each variable is defined just before it is first used. There’s no need to be strict about this -- if you prefer to swap lines 5 and 6, that’s fine.

Best practice

Define your local variables as close to their first use as reasonable.

Quiz time

Question #1

What does the following program print?

Show Solution

2.5 -- Why functions are useful, and how to use them effectively
2.3 -- Introduction to function parameters and arguments

217 comments to 2.4 — Introduction to local scope

  • Armando I G

    Hello I learned a few basics on programming some years ago, I'm trying to learn properly, but I remember my teacher telling me to declare local variables at the beginning of the function, not necessarily near its first use, why is it better practice to declare them just before using them compared to declaring them at the beginning?
    I remember being easier to identify my variables so I didn't repeat them within the same function

    • nascardriver

      Your teacher might be a C programmer, where declaring the functions at the start was necessary. That's not how it goes in C++.
      If you have so many variables that you're starting to repeat them, your functions are too long.

      The benefits of declaring variables at the first use are
      - They're never uninitialized. If you declare them at the start, you might not know which value they should have.
      - Initialization is faster and safer than default-initialization+assignment.
      - You're not creating variables and then not using them. If a function exits early, only the variables that were required up to that point have been created (Exceptions apply to fundamental types).

  • Haldhar Patel

    "Local variables are destroyed in the opposite order of creation at the end of the set of curly braces in which it is defined (or for a function parameter, at the end of the function)"

    Que--> what do you mean by "at the end of function", isn't the function
           ended when closing curly braces are encountered. Is end of curly
           braces not the end of function? Or this is a thing which we will
           learn later in this tutorial. Please explain..

    • Alex

      Yes, the function is ended when the closing curly braces are encountered.

      I make the distinction because technically function parameters aren't defined inside a set of curly braces.

      • Haldhar Patel

        Thanks for the clarification Alex, and I greatly appreciate your tutorials and the help & support you are providing. Thanks again..

  • Martin H.

    Very well done explanation! I work a lot with 3D software and it's very comforting to see some concept of 3D programs and actual programming match.

    It's like a hierarchy. If you'd view a program like one above from a zoomed out total view there would be (fake global) variables visible like:

    funktion add → x and y
    funktion print → x and y
    funktion main → x and y

    So they are all at all times distinguishable. I guess the major difference is that they really are local, and have a lifetime, really get created and destoyed very so in runtime other then exist all the time. That's probably way better to handle for computation.
    Is that the reason or a major reason why there are local and global variables?

    I hope I got that right. Thank you very much for this lessons!

  • pss

    Void returns nothing, then in quiz time question 1 how void dolt return X, y values to the main function?

  • Mohammad

    Hi, " Define your local variables as close to their first use as reasonable. "

    Why we use should from this?


    • nimo

      i think avoid memory last

    • Zookeeper

      I think it will be helpful when you are going through your code you will easily find out when an variable created and to find out it's scope

      At starting we are more prone to make silly and small misakes and defining local variables as close to their first use will help us tackle them easily

      for e.g -> In the below code the program will compile and work fine but don't give the desired output

      In this e.g when you will compile it you will get an compilation error
      "  error: ‘y’ was not declared in this scope "
      which means "y" is not declared till now (in the "main" for this e.g)

      So this will prevent you to do mistake and get frustrated more often

      #include <iostream>
      using namespace std;

      int main()
          int x{};
          cout<<"Enter x\n";
          cin>>y; // It will throw an error because we are assigning the value to the variable which
                  //is still not declared
          int y{};
          cout<<"Enter y\n";

          return 0;

      :- There may be more benefits of using this practice. This is what I think of :)

    • Jonas


      There are many reasons for this. Amongst other, it is easier to read and understand the code if variables are defined as close as possible to where they are used (or else you might have forgotten the definition when you get to where they are used)

  • O.N.J

    Hi am a beginner I do appreciate this tutorial. I read this page a couple times well trying too get it. And this is the best I could do it works for me.

    #include <iostream>

    void doPrint(int n)
          std::cout << "Character # for 'n' is: " << n << '\n';

    void doPrint2(int y)
        std::cout << "And 'y' is the #: " << y << '\n';
    int main()

        char x{'n'};
        char y{'y'};
        std::cout << "And i.e of passing a character value. " << '\n';
        std::cout << ("It's that ez, ") << '\n';
        return 0;

    • Fendralor

      If I read this correctly, you get the character number of a char by returning it's int-value via a function, is that correct? In that case, you probably can optimize a bit. You could do something like this:

      But it can be even simpler, if you only want to output the ASCII number of a character. You don't even need a function. You can simply convert the char into an int by explicitly casting it into an int for the output. (casting, put simply, is forcing a data type to convert into another. It is not possible to cast every type into every other type, they have to be compatible). The variable itself will still hold the char afterwards.
      All you would need to do is this:

      Of course you can also go and optimize that as well. But these are other possibilities to accomplish what you want.</iostream></iostream>

      • Fendralor

        A little correction, since I messed up and can't edit:
        In regards to the second example I gave you, ignore that and instead use this (fixes a little error I did because I'm stupid and makes the code actually compile).

Leave a Comment

Put all code inside code tags: [code]your code here[/code]