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 it’s 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

195 comments to 6.3 — Local variables

  • Dudz

  • DemonKingSheon

  • Raul

    I've used the swap function provided by the standard library.

    • nascardriver

      If you know how to swap manually, that's fine.

      Line 28-29 is a duplicate of line 37-38. The point of swapping in this case is that you don't have to repeat your code.

      • Raul

        Much appreciation for your contribution.

  • Eric

    My program does not successfully switch the larger and smaller when needed.
    What am I missing?

    1    
    2    #include <iostream>
    3    
    4    //Here the numbers are collected.
    5    int getNumber()
    6    {
    7    std::cout << "Enter an integer : ";
    8    int x{};
    9    std::cin >> x;
    10    return x;
    11    }
    12    
    13    //Here the numbers are printed, smaller first.
    14    void printNumbers(int x, int y)
    15    {
    16    std::cout << "The smaller value is " << x << "\n";
    17    std::cout << "The larger value is " << y << "\n";
    18    }
    19    
    20    //Here the program evaluates whether the first number is larger than the second.
    21    int evaluateNumbers(int x, int y)
    22    {
    23        if (x > y)
    24        {
    25            int k{ y };
    26            y = x;
    27            x = k;
    28            std::cout << "Swapping the values\n";
    29            return (x, y);
    30        }    
    31    }
    32    
    33    int main()
    34    {
    35        int x{ getNumber() };
    36        int y{ getNumber() };
    37        evaluateNumbers(x, y);
    38        printNumbers(x, y);
    39        return 0;
    40    }

    • nascardriver

      Please use code tags when posting code (See yellow message below the comment text field).

      `evaluateNumbers` can't modify `x` and `y` of `main`. Line 26, 27 change the local copies of `x` and `y`.
      Line 29: That's a comma operator, the `x` is ignored, `y` is returned. Your compiler should've warned you.
      Line 37: You're not using the return value of `evaluateNumbers`.

      For now, you have to swap the variables in `main`. We'll talk about how to modify arguments in a later lesson.

      • Eric

        OK, and thanks for your reply.  In Visual Studio how is posting code tags achieved?  
        I could not find any information in their help feature.  And clipping a pasting did not get the effect I see others using.

        • nascardriver

          [-code]
          // your code here
          [-/code]
          Without the -

        • Eric

          Sorry to be obtuse.  Please be more specific.  I have tried compiling and running a sample program in a variety of ways with a varied combination of [-code] and [-/code].  As of yet, I have been unsuccessful.  Also searching [-code], [-\code] has returned nothing.

  • koe

    The ODR from section 2.7 doesn't seem to cover shadow variables

    • nascardriver

      I added an exception of shadow variables to lesson 2.7 and wrote that shadow variables don't violate the ODR in this lesson.
      Thank you for your continuous feedback!

  • BooGDaaN

    Hi!
    Can you modify code blocks in this tutorial using Uniform Initialization?
    Also, I think it's a good idea to include "Rule: Define variables in the smallest scope and as close to the first use as possible.." in a hightlighted green block.

    Thanks for all the tutorials so far!

    • nascardriver

      Updated, thanks!

      • BooGDaaN

        Sorry for the insistent comments, but all the lessons in this chapter need to be updated. Also, in "S.4.1 Blocks" we use uninitialized variables, please update this if you can.

        • nascardriver

          I'll update the lessons as I go along when I have the time. Note that

          is safe even if extraction fails. That doesn't mean it's good. I initialized the variables in S.4.1 and in this lesson.
          Thanks for your feedback :)

  • int input()
    {

        std::cout << " enter two integers, the second larger than the first:\n";
        int x{};
        std::cin >> x;
        return x;
    }

    int main()
    {
        int x{ input() };
        int y{ input() };
        {
            if (x > y)
                
                std::cout << "Rearranging your numbers from smallest to greatest:\n" << "The smaller value is: " << y << '\n'<< "The larger value is: " << x;
            else
                std::cout << " Your numbers from smallest to greatest are:\n" <<  "The smaller value is: " << x<< '\n' << "The larger value is: " << y;
        }
    }

    Is this a good way of writing the program? If its not can you explain why ?thank you.

    • nascardriver

      Hi,

      please use code tags when posting code.
      The code is good, but it doesn't do what the quiz asked for. At the end of `main`, `x` should be smaller than `y`, no matter which order they were entered in.

  • Adriano

    Hey, is this actually ok? it worked to me just for the quiz, but i didn't use the way you did maybe i'm wrong? if yes please tell me where, i used 2 functions in header.h just for semplicity .Would i have problems this way?

    • Hey Adriano!

      - Don't use `using namespace`, it can lead to name conflicts.
      - Use your editor's auto-formatting feature.
      - Use single quotation marks for characters.
      - If you program prints anything, the last thing it prints should be a line feed ('\n').
      - Line 14 creates a new variable. If you want to assign to the existing `x`, remove `int`.
      - You're not swapping the values. Line 18 and 22 should be outside of the ifs. One of them should print `x`, the other should print `y`. The logic before that should make sure that one of the variables is always the smaller one.

      > i used 2 functions in header.h just for semplicity .Would i have problems this way?
      If the functions are defined in a source file, no. If they're defined in the header, you'll run into problems.

  • Edgar J. Wurst

    I used a separate function for inputting the integers.  Is that too much clutter for such a small program?

  • Josh

    Do constants have a scope too or do I have to define them in header file?

  • Napalm

    Was the swap technique

    actually shown somewhere previous to this tutorial page? I was already aware of it's use so I was able to work out the answer pretty easily, but I remember when I saw it for the first time I really had to look at it to see how it worked. I'm not surprised absolute beginners aren't coming up with it themselves.

    • Alex

      I don't think it was presented. But I'm okay letting readers have a go at finding a solution themselves. Not everyone will make it -- and that's okay too. The solutions are provided for them to learn if they can't figure it out themselves.

  • elvis

    i added an additional variable to maintain the value of x so that way i can reffer back to it later

  • andrey

    Hey guys here is my try to solve the question, is this ok for a beginner ?

    • Hi Andrey!

      * Line 6-8 and 14-16 are equivalent, move them into their own function.
      * @c is unnecessary, as it's the same as @b.
      * Don't use @std::endl unless you have a reason to. Use '\n' instead.

      Although your program produces the correct output, it doesn't do what the quiz asked for. At the end of @main, @a is supposed to hold the smaller value and @b the larger, no matter in which order they were entered.

      @Alex This is a common misconception.

  • Anonymous

    I think the previous example where first the variables a,b and x,y were used in diff functions, later using the x,y naming for both functions was particularly enlightening and ought to be included. I don't remember though if it was from a previous version of the site or from a previous lesson discussing scope.

  • Behzad

    Defining variables in the most limited scope makes the program very readable and safe. But what if the block including the variable definition is in a loop. Doesn't that cause performance issues? Particularly when the number of iterations are not known at the compile time?

    • Alex

      In many cases, putting variables inside the loop can improve performance, because the compiler knows it doesn't need to persist the value, so it can optimize more highly. The only way to know for sure which is more performant is to test and measure. Given that, starting from the standpoint that variables should go inside the loop rather than outside (which is more maintainable) is reasonable.

  • George Stoney

    This works for me, I'm not sure if there's a better way

    • Hi George!

      Although it works, it's not what the quiz asked you to do. At the end of @main (before printing), one of the variables should always be smaller than or equal to the other.

      @Alex
      There are a lot of submissions of people who understood this quiz in the wrong way. The quiz could use rephrasing or clarification.

  • Alex A

    Hi All,

    below is my solution that works and i believe fulfils all that the question specified, but its not the same as the given solution. Have i got something wrong?

    • Hi Alex!

      You were supposed to swap the values.
      When you call

      @x should be the smaller and @y the larger number, no matter in which order they were entered.

      Suggestions so far
      * Line 7, 17, 26, 27, 29, 30: Initialize your variables with uniform initialization (as you did in line 40 and 42)
      * Line 7-10 is equivalent to line 17-20. Don't repeat yourself.

      • Alex A

        Ok thanks Nascar for the feedback.
        do initialise a value taken from cin do i just put the whole statement within {} ? so it would be
        int x{ std::cin >> x }? as this hasn't worked when iv tried it (hence i didn't use uniform initialisation).
        to not repeat i guess best to put the std::cout "enter value" or "larger value" in the main function then just keep 1 function for get value?

        • For @x and @y in main

          For @a and @b there is no one-liner. Initialize variables of which you don't yet know the value to 0, 0.0, 0.0f, etc.

  • Fateh Chadha

    Hi in this example. the value inside the if statement (apples >= 5) still refer to the apples in outer block? or does it now refer to the apples in nested block once we define it?

  • totoro

    is that fine?

    • Hi Totoro!

      * Line 3 and 4 should be moved inside of @main, because they're not used elsewhere.
      * Line 8, 9: Initialize your variables with uniform initialization.

      Your code doesn't swap the values. Try completing the following code

  • Hi,

    My final solution is thus:

    I did try putting the calls to input the integers in separate routines but it confused issues and put them out of scope.  It seems that it really is a case of simple is best.

    • Hi Nigel!

      Line 10, 14, 22: Initialize your variables with uniform initialization.

      If you had trouble moving the input code into separate functions you might not understand functions or scopes correctly. If you share the code you've tried I'll gladly point out what's wrong.

      • The problem arises at lines 32 and 33.

        • Line 24, 25: You're creating uninitialized variables, you should never do that.

          The problem is that you're using uninitialized variables (line 26, 27). To fix this, you have to initialize them.
          But you don't need to, because @getDigit1 and @getDigit2 don't even use their parameters. You should declare the parameters of @getDigit1 and @getDigit2 to be local variables instead.

          And change main to

          • Ah yes, got it now, thanks.  I can see where I was going wrong.

          • So I end up with this, which functions as it should and follows the target of the question:

            Thank you again.  I know I could have just done everything within main() but I think it is much tidier and easier to read if functions are separated.

  • Aditi

    My solution

    • Hi Aditi!

      * Line 6: Initialize your variables with uniform initialization
      * Line 15, 16 and line 24, 25 are equivalent, move them outside of the conditional blocks, that's what the swap is for.

  • Tulsi das

    Hi Henry,

    If the program is for purpose only the display to user than it is 100% correct but if need to extend the program and later again use these number than it would required a swap.

  • Tubbs

    /******************************************************************************
    Q: Any errors here or could I do better in certain coding practices anywhere?

    *******************************************************************************/

    • nascardriver

      Hi Tubbs!

      Good job solving the quiz!

      Suggestions:
      * Initialize your variables with uniform initialization.
      * @userSmallInput and @userBigInput2 are almost equivalent, don't repeat yourself.
      * Try limiting your lines to 80 characters in length. Most editors have an options to display a vertical line.
      * Line 26, 35: Repetition of "Smaller Integer:[...]", don't repeat yourself.
      * @main The variables in there are most likely destroyed before Line 52, Line 53 is just where they go out of scope.

      • Tubbs

        Ok thanks for the reply but I didn't get these things that you said:
        @userSmallInput and @userBigInput2 are almost equivalent, don't repeat yourself. (I think you meant I can save some space by using 1 function and calling it twice?)
        Line 26, 35: Repetition of "Smaller Integer:[...]", don't repeat yourself.
        and I was wondering where the variables are destroyed in:
        @main The variables in there are most likely destroyed before Line 52, Line 53 is just where they go out of scope.

        • nascardriver

          > you meant I can save some space by using 1 function and calling it twice?
          Exactly. Not only that but you'll also have an easier time if you decide to update the function, because otherwise you'd need to change the same thing in two places.

          > Repetition of "Smaller Integer:[...]",

          Lines 6-8 are equivalent to lines 18-20, move those lines outside the if-else blocks.

          > I was wondering where the variables are destroyed
          They can be destroyed as soon as they aren't used anymore. The return statement doesn't use any of those variables so they could be destroyed before the return is encountered.

  • Henry

    Look at my code, I used just if else statement and i still got a desired result

    • nascardriver

      Hi Henry!

      Fist of all, nice code!

      You got away without a temporary variable, because you didn't actually swap the values, you just printed them in a different order.
      You should be able to run

      at the end of @main and get the expected results, which is not the case with your code.

      • Henry

        But the code is syntactically correct?

        • nascardriver

          Yes, if it wasn't you wouldn't have been able to compile it. It's behavior is also correct. So mission accomplished, but this quiz is about the way to the target, not the target itself.

          Filling that gap is the quiz.

Leave a Comment

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