官术网_书友最值得收藏!

Local and Global Variables

The body of a function is a code block that can contain valid statements, one of which is a variable definition. As we learned in Lesson 1, Getting Started, when such a statement appears, the function declares a local variable.

This is in contrast to global variables, which are the variables that are declared outside of functions (and classes, which we will look at in Lesson 3, Classes).

The difference between a local and a global variable is in the scope in which it is declared, and thus, in who can access it.

Note

Local variables are in the function scope and can only be accessed by the function. On the contrary, global variables can be accessed by any function that can see them.

It is desirable to use local variables over global variables because they enable encapsulation: only the code inside the function body can access and modify the variable, making the variable invisible to the rest of the program. This makes it easy to understand how a variable is used by a function since its usage is restricted to the function body and we are guaranteed that no other code is accessing it.

Encapsulation is usually used for three separate reasons, which we will explore in more detail in Lesson 3, Classes:

  • To restrict the access to data used by a functionality
  • To bundle together the data and the functionality that operates on it
  • Encapsulation is a key concept that allows you to create abstractions

On the other hand, global variables can be accessed by any function.

This makes it hard to be sure of the function's value when interacting with them, unless we know not only what our function does, but also what all the other code in the program that interacts with the global variable does.

Additionally, code that we add later to the program, might start modifying the global variable in a way that we did not expect in our function, breaking the functionality of our function without ever modifying the function itself. This makes it extremely difficult to modify, maintain, and evolve programs.

The solution to this problem is to use the const qualifier so that no code can change the variable, and we can treat it as a value that never changes.

Note

Always use the const qualifier with global variables whenever possible.

Try to avoid using mutable global variables.

It is a good practice to use global const variables instead of using values directly in the code. They allow you to give a name and a meaning to the value, without any of the risks that come with mutable global variables.

Working with Variable Objects

It is important to understand the relationship between variables, objects, and the lifetime of objects in C++ to write programs correctly.

Note

An object is a piece of data in the program's memory.

A variable is a name we give to an object.

There is a distinction in C++ between the scope of a variable and the lifetime of the object it refers to. The scope of a variable is the part of the program where the variable can be used.

The lifetime of an object, on the contrary, is the time during execution wherein the object is valid to access.

Let's examine the following program to understand the lifetime of an object:

#include <iostream>

/* 1 */ const int globalVar = 10;

int* foo(const int* other) {

/* 5 */ int fooLocal = 0;

std::cout << "foo's local: " << fooLocal << std::endl;

std::cout << "main's local: " << *other << std::endl;

/* 6 */ return &fooLocal;

}

int main()

{

/* 2 */ int mainLocal = 15;

/* 3 */ int* fooPointer = foo(&mainLocal);

std::cout << "main's local: " << mainLocal << std::endl;

std::cout << "We should not access the content of fooPointer! It's not valid." << std::endl;

/* 4 */ return 0;

}

Figure 2.1: Lifetime of an object

The lifetime of a variable starts when it is initialized and ends when the containing block ends. Even if we have a pointer or reference to a variable, we should access it only if it's still valid. fooPointer is pointing to a variable which is no longer valid, so it should not be used!

When we declare a local variable in the scope of a function, the compiler automatically creates an object when the function execution reaches the variable declaration; the variable refers to that object.

When we declare a global variable instead, we are declaring it in a scope that does not have a clear duration – it is valid for the complete duration of the program. Because of this, the compiler creates the object when the program starts before any function is executed – even the main() function.

The compiler also takes care of terminating the object's lifetime when the execution exits from the scope in which the variable has been declared, or when the program terminates in the case of a global variable. The termination of the lifetime of an object is usually called destruction.

Variables declared in a scope block, either local or global, are called automatic variables, because the compiler takes care of initializing and terminating the lifetime of the object associated with the variables.

Let's look at an example of a local variable:

void foo() {

int a;

}

In this case, the variable a is a local variable of type int. The compiler automatically initializes the object it refers to with what is called its default initialization when the execution reaches that statement, and the object will be destroyed at the end of the function, again, automatically.

Note

The default initialization of basic types, such as integers, is doing nothing for us. This means that the variable a will have an unspecified value.

If multiple local variables are defined, the initialization of the objects happens in the order of declaration:

void foo() {

int a;

int b;

}

Variable a is initialized before b. Since variable b was initialized after a, its object is destroyed before the one a refers to.

If the execution never reaches the declaration, the variable is not initialized. If the variable is not initialized, it is also not destroyed:

void foo() {

if (false) {

int a;

}

int b;

}

Here, the variable a is never default initialized, and thus never destroyed. This is similar for global variables:

const int a = 1;

void main() {

std::cout << "a=" << a << std::endl;

}

Variable a is initialized before the main() function is called and is destroyed after we return the value from the main() function.

Exercise 4: Using Local and Global Variables in a Fibonacci Sequence

We want to write a function that returns the 10th number in a Fibonacci sequence.

Note

The nth Fibonacci number is defined as the sum of the n-1th and the n-2th, with the first number in the sequence being 0 and the second being 1.

Example:

10th Fibonacci number = 8th Fibonacci number + 9th Fibonacci number

We want to use the best practice of giving a name and a meaning to values, so instead of using 10 in the code, we are going to define a const global variable, named POSITION.

We will also use two local variables in the function to remember the n-1th and the n-2th number:

  1. Write the program and include the following constant global variable after the header file:

    #include <iostream>

    const int POSITION = 10;

    const int ALREADY_COMPUTED = 3;

  2. Now, create a function named print_tenth_fibonacci() with the return type as void:

    void print_tenth_fibonacci()

  3. Within the function, include three local variables, named n_1, n_2, and current of type int, as shown here:

    int n_1 = 1;

    int n_2 = 0;

    int current = n_1 + n_2;

  4. Let's create a for loop to generate the remaining Fibonacci numbers until we reach the 10th, using the global variables we defined previously as starting and ending indices:

    for(int i = ALREADY_COMPUTED; i < POSITION; ++i){

    n_2 = n_1;

    n_1 = current;

    current = n_1 + n_2;

    }

  5. Now, after the previous for loop, add the following print statement to print the last value stored in the current variable:

    std::cout << current << std::endl;

  6. In the main() function, call print_tenth_fibonacci() and print the value of the 10th element of the Fibonacci sequence:

    int main() {

    std::cout << "Computing the 10th Fibonacci number" << std::endl;

    print_tenth_fibonacci();

    }

Let's understand the variable data flow of this exercise. First, the n_1 variable is initialized, then n_2 is initialized, and right after that, current is initialized. And then, current is destroyed, n_2 is destroyed, and finally, n_1 is destroyed.

i is also an automatic variable in the scope that's created by the for loop, so it is destroyed at the end of the for loop scope.

For each combination of cond1 and cond2, identify when initialization and destruction occurs in the following program:

void foo()

if(cond1) {

int a;

}

if (cond2) {

int b;

}

}

主站蜘蛛池模板: 内乡县| 井冈山市| 房山区| 定西市| 紫阳县| 阜康市| 措勤县| 淅川县| 温宿县| 靖江市| 五常市| SHOW| 东乌珠穆沁旗| 阿坝县| 大连市| 阿巴嘎旗| 扎鲁特旗| 门头沟区| 邯郸市| 叙永县| 永寿县| 金秀| 喀喇沁旗| 安国市| 巴林右旗| 深州市| 三门县| 鹿邑县| 大竹县| 阜新| 罗甸县| 祥云县| 蒲江县| 平阳县| 吕梁市| 青州市| 万全县| 夹江县| 石阡县| 永修县| 洛扎县|