Search

6.3 — Local variables

In lesson 2.4 -- Introduction to local scope, we introduced local variables, which are variables that are defined inside a function (including function parameters).

It turns out that C++ actually doesn’t have a single attribute that defines a variable as being a local variable. Instead, local variables have several different properties that help differentiate how local variables behave from other kinds of (non-local) variables. We’ll explore these properties in this and upcoming lessons, as well as a few other local variable related topics of note.

Local variables have block scope

An identifier’s scope determines where an identifier can be accessed within the source code. Scope is a compile-time property.

Local variables have block scope, which means they are in scope from their point of definition to the end of the block they are defined within.

Although function parameters are not defined inside the function body, for typical functions they can be considered to be part of the scope of the function body block.

The exception case is for function-level exception handling (which we cover in lesson 14.7 -- Function try blocks).

All variable names within a scope must be unique

Variable names must be unique within a given scope, otherwise any reference to the name will be ambiguous. Consider the following program:

The above program doesn’t compile because the variable x defined inside the function body and the function parameter x have the same name and both are in the same block scope.

Local variables have automatic storage duration

A variable’s storage duration (usually just called duration) determines what rules govern when and how a variable will be created and destroyed. In most cases, a variable’s storage duration directly determines its lifetime.

For example, local variables have automatic storage duration, which means they are created at the point of definition and destroyed at the end of the block they are defined in. For example:

For this reason, local variables are sometimes called automatic variables.

Local variables in nested blocks

Local variables can be defined inside nested blocks. This works identically to local variables in function body blocks:

In the above example, variable y is defined inside a nested block. Its scope is limited from its point of definition to the end of the nested block, and its lifetime is the same. Because the scope of variable y is limited to the inner block in which it is defined, it’s not accessible anywhere in the outer block.

Note that nested blocks are considered part of the scope of the outer block in which they are defined. Consequently, variables defined in the outer block can be seen inside a nested block:

Local variables have no linkage

Identifiers have another property named linkage. An identifier’s linkage determines whether other declarations of that name refer to the same object or not.

Local variables have no linkage, which means that each declaration refers to a unique object. For example:

Scope and linkage may seem somewhat similar. However, scope defines where a single declaration can be seen and used. Linkage defines whether multiple declarations refer to the same object or not.

Linkage isn’t very interesting in the context of local variables, but we’ll talk about it more in the next few lessons.

Variables should be defined in the most limited scope

If a variable is only used within a nested block, it should be defined inside that nested block:

By limiting the scope of a variable, you reduce the complexity of the program because the number of active variables is reduced. Further, it makes it easier to see where variables are used (or aren’t used). A variable defined inside a block can only be used within that block (or nested blocks). This can make the program easier to understand.

If a variable is needed in an outer block, it needs to be declared in the outer block:

The above example shows one of the rare cases where you may need to declare a variable well before its first use.

New developers sometimes wonder whether it’s worth creating a nested block just to intentionally limit a variable’s scope (and force it to go out of scope / be destroyed early). Doing so makes that variable simpler, but the overall function becomes longer and more complex as a result. The tradeoff generally isn’t worth it. If creating a nested block seems useful to intentionally limit the scope of a chunk of code, that code might be better to put in a separate function instead.

Best practice

Define variables in the most limited existing scope. Avoid creating new blocks whose only purpose is to limit the scope of variables.

Quiz time

Question #1

Write a program that asks the user to enter two integers, one named smaller, the other named larger. If the user enters a smaller value for the second integer, use a block and a temporary variable to swap the smaller and larger values. Then print the values of the smaller and larger variables. Add comments to your code indicating where each variable dies. Note: When you print the values, smaller should hold the smaller input and larger the larger input, no matter which order they were entered in.

The program output should match the following:

Enter an integer: 4
Enter a larger integer: 2
Swapping the values
The smaller value is 2
The larger value is 4

Show Solution

Question #2

What’s the difference between a variable’s scope, duration, and lifetime? By default, what kind of scope and duration do local variables have (and what do those mean)?

Show Solution


6.4 -- Introduction to global variables
Index
6.2 -- User-defined namespaces

234 comments to 6.3 — Local variables

  • Samira Ferdi

    I see you use "\n" and '\n'. Is it okay to use both of them?

  • J Gahr

    Using {} initialization at line 32 shouldn't have any negative consequences, should it?

    • nascardriver

      Hi J!

      Nope, that's just fine. Uniform initialization is preferred.
      Great code, but your naming convention could need changes. There's no difference between functions and variables and the 'u' in your variable names is easily confused with 'unsigned' (I know it's for 'user').

  • Baljinder

    Hello, I noticed that on line 3 of the fourth example, only add's x is mentioned. However, in all other comments add's x and y are both mentioned, so I believe it would be better if this comment is updated to mention both add's x and y for the sake of completeness and consistency.

  • Silviu

    Hello, it's not exactly the same but it does the job .

    • nascardriver

      Hi Silviu!

      Good job, working as indented.

      Try limiting your lines to 80 characters in length to allow proper formatting on small screens.

      Line 4,11: Initialize your variables.
      @getSmallerInteger and @getLargetInteger are almost identical, DRY (Don't repeat yourself).
      Line 18: Bad function name, something like printOrdered would be better
      Line 25: A variable cannot be "called"
      Line 25, 32: Missing std::endl.

  • Ali Dahud

    I have succeeded with a little help. I moved my functions to main.

    • nascardriver

      Line 5: Missing include
      Line 11, 14, 17: Initialize your variables
      Line 12, 15: <> is not an operator. std::cout is used to output text, you need std::cin.
      Line 26, 28, 29: Missing backslash before 'n'

      • Ali Dahud

        something is wrong with the edit comments.
        here is my original code. :)

  • RryanT

    My code =)

  • RryanT

    My code =)

  • Cosmin

    I wonder if there's a difference in time between the two. In the second case, x is created and then destroyed at every step, so it should probably put the computer to some more work, am I right?

    Note: In the first case I do not intend to use x in the outer block. Also, I know I can print simply (i*i), but using x as a temporary variable is only for the sake of exemplifying.

    • nascardriver

      Hi Cosmin!
      There's no difference. The same question has been discussed today over here http://www.learncpp.com/cpp-tutorial/12-x-chapter-12-comprehensive-quiz/comment-page-1/#comment-314954
      TLDR: Your second loop will be converted to your first loop at compile time.

  • Weckersduffer

    My code works, but I think it is not what you asked for, teacher.

    • nascardriver

      Hi Weckersduffer!
      The program does what the quiz asked you do, however, the code doesn't.
      Instead of simply printing the values in a different order try swapping them.
      Here's an example of what's supposed to happen:

      Comments to your code so far:
      Initialize your variables.
      main should return an int.

      Give it another try, you can do it!

  • Nick

    Is it bad that my code's 62 lines and yours is 27? Am I writing too much code?

    • nascardriver

      Hi Nick!
      You can't compare code by the amount of lines, you could fit a program in one line if you really wanted to.
      More lines can mean that you have unnecessary code, it could also mean that you've got better documented code or you simply took a different approach.
      In your case it's both. I see a lot of comments and your code is easy to understand. But,
      DRY (Don't repeat yourself)! Lines 30-33 and 38-41 are almost the same, Line 16-17, 22-23 are almost the same, Line 49-60 can be wrapped up.
      As for your code itself:
      bool's are true/false, not 1/0. It works, but that's not how they're meant to be used.
      Initialize your variables.
      You wouldn't have needed forward declarations for your functions if you moved main to the bottom, this just adds extra work when changing a functions signature.
      Add some empty lines for readability.
      Use '\n' or std::endl after outputting text unless you need to next output to be on the same line.

  • wayne

    Here is my attempt. I see I did it basically the same way as Alex, except that I assigned the larger value to the temporary variable instead of the smaller one. I then assign the smaller value to the variable that should hold the smaller value and finally I assign the larger value from the temporary variable to the variable that should hold the larger value. But otherwise I think it's the same in principle.

    #include <iostream>

    int getUserInput(int displayRequest)
    {
       int userInput{};
       if(displayRequest == 0)
       {
          std::cout << "Enter an integer: ";
          std::cin >> userInput;
       }
       else
       {
          std::cout << "Enter a larger integer: ";
          std::cin >> userInput;
       }
       return userInput;
    }

    int main()
    {
       int displayRequest{0};
       // numSmall is defined here, and can be seen and used in main() after this point
       int numSmall = getUserInput(displayRequest);
       ++displayRequest;
       // numLarge is defined here, and can be seen and used in main() after this point
       int numLarge = getUserInput(displayRequest);
       if(numSmall > numLarge)
       {
          std::cout << "Swapping the values . . . " << std::endl;
          // numTemp is defined here, and can be seen and used only in this nested block after this point
          int numTemp = numSmall;
          numSmall = numLarge;
          numLarge = numTemp;
       } // numTemp destroyed here, it cannot be seen or used after this point because the poor thing is dead!
       std::cout << "The smaller value is " << numSmall << std::endl;
       std::cout << "The larger value is " << numLarge << std::endl;
       return 0;
    } // numSmall, numLarge and displayRequest all destroyed here, they cannot be seen or used after this point because they are all dead!

  • Shadi

    here is my code

  • Kaj

    Here's what I ended up with:

    Really glad I found this tutorial, its excellent, and I plan on using it to build a strong foundation for learning to create games in UnrealEngine.
    Thank you for making this Alex.

  • ztime

    is this code alright?

    • Alex

      You're close, but not quite there. Your swap function does two different jobs (swaps and prints) and doesn't even do a full swap.

      You also have redundant code to do the printing (in two different places).

      • ztime

        >doesn’t even do a full swap
        I thought you were wrong about this for a second, but after a little bit of thinking you did make sense.

        Is my second attempt alright now?

  • Gavin

    Alex,
         I created a functioning code for the quiz, but I don't understand why it works. Since I'm not returning x and y, why does it switch when it prints outside of the results?

    • Alex

      Returning values is only necessary if you want to pass a value from a function back to the caller. Since you don't make any function calls here, that isn't necessary. The x and y inside the if-statement nested block refer to the x and y declared near the top of main(), so when you swap their values, the values stay swapped even when the nested block is done.

  • Tyler Chapman

    Man that first question really got me angry. I knew exactly how to do it as I had done that on my own when I was first starting to make a calculator program. However, when I try it this time, I type in literally the exact same thing as you after 15 minutes of struggling and trying to figure out what was wrong. and it still doesn't work. But when I actually copy and pasted it worked. I spent another 15 minutes comparing my rewrite to the copy-paste and there was literally no difference at all, even all whitespace was the same. I know this isn't really a question or relevant at all but it's so bizarre I had to.

  • Cyrol

    I have made two programs here, one before looking into the solution and one after looking into it.

    Before:

    After:

    The one after looking into the solution obviously isnt that far away from it.

    I really have to thank you for making these tutorials :).

  • Here for question 1.
    #include<iostream>
    using namespace std;
    int main()
    {
        int x,y;
        cout<<"enter first integer:- ";
        cin>>x;
        cout<<"enter greater integer :-";
        cin>>y;
        if(y<x)
        {
            int swap;
            swap=y;
            y=x;
            x=swap;
            cout<<"numbers not in required order\n\nafter swaping:- "<<endl;
        }
        cout<<"x= "<<x<<endl<<"y= "<<y;
    }

  • I am new to this and already finding this website helpful.
    great work admin AND GREAT MAINTENANCE.

  • Zero Cool

    This is my solution for the Quiz 1:

    io.h

    io.cpp

    main.cpp

  • ukijo

    how about this?

    • Tunacan

      I did the same thing, just made a function and added a bonus feature where if the user enter 2 numbers as the same it will say "Both values are the same!"

    • Zero Cool

      Your code is right but the idea is to use variable scope to do a swap. For that you should override the variables content if it's necesary

  • My dear c++ Teacher,
    Please let me point out that in the solution program of first quiz you use "if" statement though you cover it in a later lesson (5.2).
    With regards and friendship.

  • My dear c++ Teacher,
    Please let me say that if you add "#include <iostream>" in 5th program it could help beginners.
    With regards and friendship.

  • My dear c++ Teacher,
    Please let me say that first program in "Shadowing" subsection outputs 105, and second, 1010. Obviously std::endl is needed.
    With regards and friendship.

  • My dear c++ Teacher,
    Please let me ask what I can not understand. In 4th snippet (program), only variable x is referred in comments, except in line 17 where both variables x and y are referred. What do you mean?
    With regards and friendship.

  • Piyush Agrawal

    This code compiled and executed successfully, but just wanted you to take a peek at it, is it 100% accurate?

    Also could I have used void instead of int compare_values()? Code isn't throwing an error with int even if no value is 'returned'.

    • Alex

      A few thoughts: It's kind of silly to introduce temporary value i just to swap x and y when your print statements are inside the else block. In that case, you might as well keep x and y as they are, and print "the smaller value is" y instead of x. Swapping becomes necessary if you move the print statements outside of the if and else blocks.

      And yes, your function should return a void since you aren't returning a value.

  • AMG

    Alex,
    Would like to suggest to modify one of your example to show a local variable is not accessible and not destroyed.
    int a = 5;
    int b = 6;
    {
        float local_x = 7.f;
        int local_res_1 = x * add(a,b); // local variable x is not accessible inside of add and not destroyed
        int local_res_2 = x / add(a,b); // local variable x is not accessible inside of add and not destroyed
    }

  • James Ray

    Hi Alex, thanks for creating this site, it's very useful. You say: "Then we declare a different variables" (CTRL+F to find where it says that). I think you mean: "Then we declare a different variable".

  • Petross404

    Hey Alex, that article made clear to me how variables should be defined.

    Forgive me if my question touches (and) another topic, but I recently read on stackoverflow that if I define something like:

    it get's out of scope, the moment a right bracket (}) is reached. It also mentioned that if I define a variable like:

    I can access it just before I

    it, but this doesn't work!

    So is there a way to access var outside the block that contains it's definition with new operator, or is it *impossible* to ever do such a thing in C++ (hence the "rare case to define well before the first use")? Did I misinterperted what I read[1]?

    [1] http://stackoverflow.com/questions/6337294/creating-an-object-with-or-without-new (The first answer)
    "The second creates an object with dynamic storage duration and allows two things:

    Fine control over the lifetime of the object, since it **does not go out of scope automatically**; you must destroy it explicitly using the keyword delete;"

    • Alex

      > I recently read on stackoverflow that if I define something like:

      it get’s out of scope, the moment a right bracket (}) is reached

      This is trying to describe the concept of "block scope". It's close but not quite precise enough. This is only true if that right bracket closes the block that the variable was defined in. Closing brackets of nested blocks or called functions don't matter in this context.

      > It also mentioned that if I define a variable like:

      I can access it just before I

      it, but this doesn’t work!

      This is called dynamic memory allocation, and I talk a lot about this in chapter 6. With dynamic memory allocation, the variable itself (var) is subject to the same limitations. But the memory allocated to hold the value isn't automatically destroyed (even when the name var is). The same is true for static variables, which I talk more about later in this chapter.

      > So is there a way to access var outside the block that contains it’s definition with new operator, or is it *impossible* to ever do such a thing in C++

      No, there's no way to _directly_ access variable var outside the block that contains its definition. However, there _are_ ways to indirectly access the _value_ that var had (via pointers or references), in the case where var was defined as static or dynamically.

  • Eric

    Alex,

    You need to switch your cout to std::cout in the first example under the heading "Variables should be defined in the most limited scope possible".

    Thanks again for all the time and effort you put into this site.  I can honestly say that my coding has improved thanks to your tutorials.

Leave a Comment

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