Variable Scope and Lifetime

Start course
2h 27m

Functions in C++ are reusable named pieces of code that we can call or invoke when we need them to do something. They help us to take large problems and break them down so that they are more manageable. This course explores functions and puts them to use in a range of projects.

Intended Audience

  • Beginner coders, new to C++
  • Developers looking to upskill by adding C++ to their CV
  • College students and anyone studying C++


To get the most out of this course, you should have a basic understanding of the fundamentals of C++.


In the previous lecture, we looked at different ways to pass parameters to functions. In this lecture, we'll discuss where it is valid to refer to different types of variables and how long they live. This largely involves the topics of variable scope also called identifier scope and also lifetime, which we'll talk about in a little bit. As far as variable scope is concerned or identifier scope, we want to ask the question what parts of my program can see or access certain identifiers? We will focus on variables but scope applies to other constructs as well like functions, but we'll again look more into that in later sections. We will specifically discuss global variables, local variables, and static local variables. We have in fact, seen scope being used throughout the course so far, but didn't really look into it very deeply. We have seen parameters and functions which have scope in the function. In other words, if a parameter named myNum being passed to a function named myFunction1, and then another function, my other function exists, it can't directly access the parameter myNum. This is an informal look at scope. Let's be a little more deliberate with our discussion about scope. Scope refers to the range or area of code in which an identifier, and in our case for right now, specifically, a variable identifier is accessible. We'll look at variables with different scope with an example project. So, let's create a new project called ScopeFun. So, we will create the new project and we will make it empty and call it ScopeFun, and then hit 'Create'. And as usual, we will, of course, create our main file, Add, New Item, main.cpp, and we will fill in some skeleton code. And I'm going to create a function called someFunction. Again, not great names, but again, these are just demonstrations. So, we've got someFunction which takes a parameter and then down below here, we have some parameter as well, and this function does this. So, it has int myLocalNum = 100, and we have the my local number is myLocalNum. We have the parameter is aParam, and we have my global double in someFunction is myGlobalDouble. Now, we're going to create that double real quick here. And notice it's outside of main, so I'm calling this myGlobalDouble = 3.14159. There we go. And, okay, nothing missing. All right. So, we need to fill in main here. Int localToMain = 20 and we're going to say "The local to main variable is localToMain". And then we're going to put global double (in main) is myGlobalDouble and then we're going to call someFunction on the value 25, okay? So, let's give this a run, shall we? Debug, Start Without Debugging, and we have it printing out the local to main variable is 20. Global double inside of main is 3.14159. My local number which is down here in someFunction is 100, which it is. We have the parameter as 25 which it was what we passed in, and then we have my global double. I got to fix that but it says (in someFunction) is 3.14159. So, I'm going to fix that right there. Good. You'll notice the global variable, myGlobalDouble, is accessible in both someFunction and also inside of main. The global scope for identifiers allows them to be accessed anywhere in our program. So, because I declared it outside of any function, myGlobalDouble is accessible inside of main and someFunction and any other function in this file because it's global. Now, if we try to access myLocalNum which is declared inside of someFunction inside of another function, say main, let's see what happens. So, if I try to print say, myLocalNum in main, myLocalNum, or maybe if I try to print down here localToMain inside of someFunction, do we have a problem? Let's see if we have a problem. So, if we try to get it to work, you'll notice actually I can already see red lines under here. So, I don't even have to try to compile or run the code because it tells me what the problem is if I hover over it. Identifier myLocalNum is undefined, but you might say, "well, it's over here", and that's right. It's defined inside of my function. It was declared and defined inside of my function. But that does not mean main can access it. It is not global. Likewise, localToMain is a local variable that is inside of main, but we can only access it inside of main. We cannot access it inside of someFunction. All right? So, let's remove this offending code. All right. So, another thing we should pay attention to in addition to scope, a closely related topic is called the lifetime of the variable. In other words, how long do they live in the program? To test this, I'm going to add some basic code to someFunction and change the value of myLocalNum. We will also modify the global variable MyGlobalDouble inside someFunction as well, and finally, call someFunction more than once to see if there are any lasting effects. So, to set it up, I'm going to actually call main or call someFunction from main rather, couple other times. 32. So, we'll pass 25, 28, and 32. We have myLocalNum declared here. I'm going to say myLocalNum++ and then I'm going to say myGlobalDouble++. It's not as common to increment a double, but we can. So, let's run it and see what we get. All right. So, if we look at what we're doing here, we have local domain variables being printed here. So, the local domain variable is 20, global double in main is, and that says 3.14159. And now when we get into someFunction, myLocalNum is initialized to 100 but it is immediately incremented before it is printed down here. So, my local number is myLocalNum right there. And when we print that it says 101, which is what we expect. My global is now 4.14159, and then that's because we called this, so it printed out the 25. Then it goes and calls someFunction again on 28, so we get the print out of 28. And then it says myGlobalDouble is 5.14159  because it incremented again. And then, it says my local number is 101 again. So, it did not become 102. It's 100 and then 101 again. And then finally, we call someFunction on the value 32 as its argument. And that becomes aParam. We print that out and that's 32. And then the parameter is 32, the local number again is 101. It's not 102 or 103. It has not changed from each call. The global, on the other hand though has. The changes that we made to it  have persisted because it is global. The global variable lives for the entire lifetime of this program whereas, the local variable is actually created and destroyed each time. It's very interesting. So, again, you'll notice the value of my local variable or myLocalNum rather, is increased from 100-101 and then printed, but in each subsequent call of someFunction it does not keep increasing. This is because, again, local variables like this one are created when they are encountered and then destroyed. That is the memory containing the values return to runtime stack, which basically means the memory is automatically freed up and made available for something else. We'll learn more about the runtime stack later in the course. However, notice that our global variable, myGlobalDouble, does get increased across multiple calls of someFunction. That's because global variables are not only accessible in any of the functions in our program because of their scope, their lifetime extends as long as the program is running. So, we've got scope and we've got lifetime. Now, if you re-run the programs, all the variables have reset of course, because the memory for anything that was left, including the global variables have been freed up since the last time we ran the program. But as long as our program is running, the global variables remain alive. So, we've made a bit of a distinction between scope and lifetime of variables. A good question might be, can we have a variable that is only accessible in a specific function, i.e. it's a local variable, it has scope to the function, can't access it in other functions, but has a lifetime that extends the life of the program? So, we're protecting it by having it only accessible inside of one particular function, but it lives the whole life of the entire program. It's a hybrid between global and local in some ways. Now, the answer is yes. What we're going to use is called a static local variable. So, if we create a new variable inside of someFunction. So, I'm going to create it as static int myStatic = 500, and then myStatic++,  okay? So, we want it to call that every time this function is called, it should go to that line. Now, at the very end of someFunction, I'll put my static variable and then myStatic endl. Now you can see that the variable myStatic is declared locally but has the special use modifier static attached to it. Therefore, it will live for the entire program's lifetime but is only accessible inside of someFunction. It's the best of both worlds, okay? A global and a local variable in terms of their lifetimes, but when you need it to behave like this with local scope. So, let's run this and see what happens. So, we run this and we're paying really close attention to the static variable. So, the first time through, someFunction when it's called on 25, you see right here that's where we start because the local numbers are printed right there. So, the first time that occurs, it prints out 25 and then the static variable is declared and initialized to the value 500, and then it becomes immediately 501. When we print it out, it does print 501, in fact. The local number prints 101, okay? So far so good. The next call to someFunction of 28. The 28 comes in here. We know that we're down here now. It says my global and then my static variable is now 502. So, it was 501 the last time we called it, now it's 502. And then the next time it is 503. So, the static local variable is actually accessible only inside of this function because of its scope. So, it's local. But it's static, which means it behaves like a global variable in that its lifetime extends for the entire lifetime of the program. So, this is very interesting. And also you'll note that only the first time when it sees the declaration does it set this value. And you have to do it all on one line because if you did it on another line like we do with some variables, like if I said MyStatic = 500, it will keep resetting it. So, you have to put the declaration and the initialization on one line with static variables if you want it to actually behave statically the way you would expect. So, excellent. Excellent. Now, before we move on, let's do a small challenge. For this challenge, I'd like you to create a program called ScopeChallenge. In this program, you should create a function called modifyGlobal that is void and takes no parameters. You will also create a global variable called counter, which is an integer. Make sure to initialize the counter variable, this global variable, to zero when you declare it. Inside the function modifyGlobal, you will simply increment the counter by one every time the function is called. Then inside main, call modifyGlobal function inside of a for loop that iterates a 100 times, and then print out the value of counter before and after the loop. So, we're mixing our repetition control statements with scope and lifetime. It's very interesting. So, pause the video and work on this challenge. Come back when you're finished or if you need some help. How did that work out for you? Great job if you were able to solve the challenge. Regardless, let's take a look at it together. Again, even if you did it slightly different than me, that's  okay. It doesn't necessarily mean that you got it incorrect. So, we're going to create the ScopeChallenge program. So, this was our ScopeFun program. We have to say bye bye. File close. Now let's create the ScopeChallenge program. So, we've got Empty Project. We will call this ScopeChallenge, hit 'Create'. And of course, we create our main file right here, main.cpp, include iostream using namespace standard. We'll create the skeleton as always, and we want to create the global counter. That was one of the things we had to do, so int counter equals one. And then we want a modifyGlobal function that is void and takes no parameters. Inside of main, we're going to print the counter before and after a loop. So, we need to put counter here and then we're going to have counter below the loop. I guess I should probably give the function a body or we're going to have a problem. It may not like that. So, all we're doing is taking the counter and incrementing it. Now we'll put the loop in between the two prints of the counter. So, we're going to put for (int i = 0;. We want to reiterate it a 100 times, so i < 100 i++. And again, since we're starting at zero, it goes up to less than 100 but that's 100 times because we count zero as the first iteration and then 99 would be the 100th iteration. All right, now we call modifyGlobal. Perfect. Perfect. And let's run it, of course. Check it out. All right, now we didn't print it every time it went through the loop; we just did the incrementation. So, right here we started with zero, which is what we initialized this global variable to. And then since it has both scope and lifetime throughout the entire course of the program, that means that it is accessible inside of modifyGlobal which does change it by incrementing it each time modifyGlobal is called, and then we modified it 100 times. We incremented it 100 times from zero, so that gives us 100. Now surprise. Great job everyone. Let's move on to the next lecture in which we will learn about function overloading. I'll see you there.


About the Author
Learning Paths

John has a Ph.D. in Computer Science and is a professional software engineer and consultant, as well as a computer science university professor and department chair.

Covered Topics