Download presentation
Presentation is loading. Please wait.
1
chapter 8 Scope,Lifetime,and More on Functions
Goals To be able to do the following tasks,given a C++ program composed of several functions: 1.) Determine whether a variable is being referenced globally. 2.) Determine which variables are local variables. 3.) Determine which variables are accessible within a given block. To be able to determine the lifetime of each variable in a given block. To understand and be able to avoid unwanted side effects. To know when to use a value-returning function. To be able to design and code a value-returning function for a specific task. To be able to invoke a value-returning function properly.
2
8.1 Scope of identifiers Any block can contain variable and constant declarations. If we listed all the places from which an identifier could be accessed legally, we could describe that identifier’s scope of visibility or scope of access, often just call its scope. Scope: The region of program code where it is legal to reference (use )an identifier.
3
C++ defines several categories of scope for any identifier
C++ defines several categories of scope for any identifier. We begin by describing three of these categories. Class scope This term refers to the data type called a class. We postpone a detailed discussion of class scope until chapter 11. Local scope The scope of an identifier declared inside a block extends from the point of declaration to the end of that block. Also , the scope of a function parameter (formal parameter )extends from the point of declaration to the end of the block that is the body of the function. Global scope The scope of an identifier declared outside all functions and classes extends from the point of declaration to the end of the entire file containing the program code.
4
C++ function names have global scope
C++ function names have global scope . (There is an exception to this rule , which we discuss in chapter 11 when we examine C++ classes.) Once a function name has been declared, the function can be invoked by any other function in the rest of the program. In C++, there is no such thing as a local function-that is ,you cannot nest a function definition inside another function definition.
5
Global variables and constants are those declared outside all functions. When a function declares a local identifier with the same name as a global identifier, the local identifier takes precedence within the function. This principle is called name precedence or name hiding. Name precedence : the precedence that a local identifier in a function has over a global identifier with the same name in any references that the function makes to that identifier; also called name hiding. example. p283
6
Scope Rules The rules for accessing identifiers that are not declared locally are called scope rules. Scope rules : The rules that determine where in the program an identifier may be accessed, given the point where that identifier is declared. Nonlocal identifier : With respect to a given block,any identifier declared outside that block. In addition to local and global access, the C++ scope rules define what happens when blocks are nested within other blocks. Anything declared in a block that contains a nested block is nonlocal to the inner block. (Global identifiers are nonlocal with respect to all blocks in the program.) If a block accesses any identifier declared outside its own block , it is a nonlocal access.
7
Here are the detailed scope rules , excluding class scope and certain language features we have not yet discussed: A function name has global scope . The scope of a function parameter is identical to the scope of a local variable declared in the outermost block of the function body. The scope of a global variable or constant extends from its declaration to the end of the file, except as noted in rule 5. The scope of a local variable or constant extends from its declaration to the end of the block in which it is declaration . This scope includes any nested blocks, except as noted in rule 5. The scope of an identifier does not include any nested block that contains a local declared identifier with the same name (local identifiers have name precedence.)
8
// scopeRules program #include <iostream> using namespace std; void Block1(int, char &); void Block2(); int a1; // One global variable char a2; // Another global variable int main() { : } //************************************************** void Block1(int a1, //Prevents access to global a1 char& b2) //has same scope as c1 and d2 int c1; //A variable local to Block1 int d2; //Another variable local to Block1 void Block2() int a1; //Prevents access to global a1 int b2; //Local to Block2; no conflict with b2 in Block1 while(...) { //Block3 int c1; //Local Block3; no conflict with c1 in Block1 int b2; //Prevents nonlocal access to b2 in Block2;no //conflict with b2 in Block1
9
int a1; // One global variable
char a2; // Another global variable int main() { : } void Block1( int a1, char& b2) int c1; int d2; void Block2() int a1; int b2; while(...) { //Block3
10
Name precedence is implemented by the compiler as follows
Name precedence is implemented by the compiler as follows. When an expression refers to an identifier, the compiler first checks the local declarations. If the identifier isn’t local, the compiler works its way outward through each level of nesting until it finds an identifier with the same name. There it stops. If there is an identifier with the same name declared at a level even further out, it is never reached. If the compiler reaches the global declarations (including identifiers inserted by #include directives) and still can’t find the identifier, an error message such as “UNDECLARED IDENTIFIER” is issued.
11
Variable Declarations and Definition
A variable declaration becomes a variable definition if it also reserves memory for the variable.
12
In the previous chapter,we talked about the concept of a multifile program,a program that physically occupies several files containing individual pieces of the program. C++ has a reserved word extern that lets you reference a global variable located in another file. A “normal” declarationsuch as int someInt; Cause the compiler to reserve a memory locating for someInt. On the other hand, the declaration extern int someInt is an external declaration. It states that someInt is a global variable located in another file and that no storage should be reserved for it here.
13
Header files such as iostream contain external declarations so that user programs can access important variable defined in system files. For example, iostream includes declarations like these: extern istream cin; extern ostream cout; These declarations allow you to reference cin and cout as global variables in your program, but the variable definition are located in another file supplied by the C++ system.
14
In C++ terminology, the statement
extern int someInt; is a declaration but not a definition of someInt. It associates a variable name with a data type so that the compiler can perform type cheching. But the statement int someInt; is both a declaration and a definition of someInt. It is a definition because it reserves memory for someInt. In C++,you can declare a variable or a function many times,but there can be only one definition.
15
Namespaces For some time,we have been including the following using directive in our program: using namespace std; What exactly is a namespace? As a general concept,namespace is another word for scope. However, as a specific C++ language feature, a namespace is a mechanism by which the programmer can create a named scope.
16
For example, the standard header file cstdlib contains function prototypes for several library functions, one of which is the absolute value function,abs. The declarations are contained within a namespace definition as follows: // In head file cstdlib: namespace std { : int abs(int); }
17
A namespace definition consists of the word namespace, then an identifier of the programmer’s choice, and then the namespace body between braces. Identifiers declared within the namespace body are said to have namespace scope. Such identifiers cannot be accessed outside the body except by using one of three methods: To use a qualified name: the name of the namespace,followed by the scope resolution operator(::) ,followed by the desired identifier. Here is an example: #include <cstdlib> int main() { int alpha; int beta; alpha=std::abs(beta); //A qualified name : }
18
2. To use a statement called a using declaration as follows:
#include <cstdlib> int main() { int alpha; int beta; using std::abs; //A using declaration alpha=abs(beta); : } This using declaration allows the identifier abs to be used throughout the body of main as a synonym for the longer std::abs.
19
3.To use a using directive (not to be confused with a using declaration)
#include <cstdlib> int main() { int alpha; int beta; using namespace std; //A using directive alpha=abs(beta); : } With a using directive , all identifiers from the specified namespace are accessible, but only in the scope in which the using directive appears.
20
On the other hand , if we put the using directive outside all functions (as we have been doing ), like this: #include <cstdlib> using namespace std; int main() { : } then the using directive is in global scope; consequently, identifiers form the std namespace are accessible globally.
21
8.2 Lifetime of a variable Lifetime : The period of time during program execution when an identifier has memory allocation to it. Automatic variable : A variable for which memory is allocated and deallocated when control enters and exits the block in which it is declared. Static variable : A variable for which memory remains allocated throughout the execution of the entire program.
22
All global variables are static variables
All global variables are static variables. By default, variables declared within a block are automatic variable. However ,you can use the reserved word static when you declare a local variable. If you do so, the variable is a static variable and its lifetime persists form function call to function call: void someFunc( ) { float someFloat; //Destroyed when function exits static int someInt; //Retains its value from call to call : }
23
It is usually better to declare a local variable as static than to use a global variable. Like a global variable, its memory remains allocated throughout the lifetime of the entire program. But unlike a global variable, its local scope prevents other functions in the program from tinkering with it.
24
Initialization in Declarations
In a declaration, the expression that specifies the initial value is called an initializer. int sum=0; the initializer is the constant 0. Implicit type coercion takes place if the data type of the initializer is different from the data type of the variable.
25
An automatic variable is initialized to the specified value each time control enters the blocks:
void SomeFunc( int someParam) { int i=0; // Initialized each time int n=2*someParam + 3 ; // Initialized each time : }
26
In contrast, initialization of a static variable (either a global variable or a local variable explicitly declared static) occurs only once, the first time control reaches its declaration. void AnotherFunc(int param) { static char ch=‘A’; // Initialized only once static int m=param + 1; // Initialized only once : } Although an initialization gives a variable an initial value, it is perfectly acceptable to reassign it another value during program execution.
27
8.3 Interface Design Data flow for a Parameter Argument-Passing Mechanism Incoming Pass by value Outgoing Pass by reference Incoming/outgoing
28
Side Effects Side effect : Any effect of one function on another that is not a part of the explicitly defined interface between them. Side effects are sometimes caused by a combination of reference parameter and careless coding in a function. Side effects also can occur when a function accesses a global variable. The symptoms of a side-effect error are misleading because the trouble shows up in one part of the program when it really is caused by something in another part. when a function is free of side effects, we can treat it as an independent module and reuse it in other programs. It is hazardous or impossible to reuse functions with side effects.
29
Global Constants There are two advantages to referencing constants globally: ease of change, and consistency. This is not to say that you should declare all constants globally. If a constant is needed in only one function, then it makes sense to declare it locally within that function.
30
8.4 Value-Returning Functions
From the caller’s perspective ,the main difference between void functions and value-returning functions is that a call to a void function is a complete statement; a call to a value-returning function is part of an expression. From a design perspective, value-returning functions are used when there is only one result returned by a function and that result is to be directly in an expression.
31
A value-returning function returns one value, not through a parameter but by means of a Return statement. The data type at the beginning of the heading declares the type of value that the function returns. This data type is called the function type, although a more precise term is function value type ( or function return type or function result type) . Function value type : The data type of the result value returned by a function.
32
The syntax template to cover both void functions and value-returning functions:
Datatype FunctionName ( ParameterList ) { Statement : } If you omit the data type of a function , int is assumed.
33
Boolean Functions We can use value-returning functions , for example, to evaluate a condition and return a Boolean result. Boolean functions can be useful when a branch or loop depends on some complex condition. Rather than code the condition directly into the If or While statement, we can call a Boolean function to form the controlling expression.
34
The C++ standard library provides a number of helpful functions that let you test the contents of char variable . To use them , you #include the head file cctype. Here are some of the available functions. header File function function Type function Value <cctype> isalpha(ch) int Nonzero, if ch is a letter(‘A’-’Z’, ‘a’-’z’); 0, otherwise isalnum(ch) Nonzero, if ch is a letter or a digit(‘A’-’Z’, ‘a’-’z’, ‘0’-’9’); 0, otherwise Although they return int values, the “is…” functions behave like Boolean functions. They return an int value that is nonzero (coerced to true in an If or While condition) or 0 (coerced to false in an If or While condition). These functions are convenient to use and make programs more readable.
35
For example, the test if ( isalnum( inputChar )) is easier to read and less prone to error than if you coded the test the long way: if ( inputChar >=‘A’ && inputChar <=‘Z’ || inputChar >=‘a’ && inputChar <=‘z’ || inputChar >=‘0’ && inputChar <=‘9’ )|
36
Interface Design for Value-Returning functions
We simply write down a list of what the function needs and what it must return. Because value-returning functions return only one value , there is only one item labeled “outgoing” in the list: the function return value. Everything else in the list is labeled “incoming” and there aren’t any “incoming/outgoing” parameters. Returning more than one value from a value-returning function (by modifying the caller’s arguments) is a side effect and should be avoided. If you interface design calls for multiple values to be returned, then you should use a void function. A rule of thumb in never to use reference parameters in the parameter list of a value-returning function,but to use value parameters exclusively.
37
An exception is the case in which an I/O stream object is passed to a value-returning function. Remember that C++ allows a stream object to be passed only to a reference parameter. Within a value-returning function, the only operation that should be performed is testing the state of the stream ( for EOF or I/O errors). A value-returning function should not perform input or output operations. Such operations are considered to be side effects of the function.
38
When to Use Value-Returning Functions
There aren’t any formal rules for determining when to use a void function and when to use a value-returning function, but here are some guidelines: If the module must return more than one value or modify any of the caller’s arguments, do not use a value-returning function. If the module must perform I/O , do not use a value-returning function. If there is only one value returned from the module and it is a Boolean value , a value-returning function is appropriate. If there is only one value returned and that value is to be used immediately in an expression, a value-returning function is appropriate. When in doubt, use a void function. you can recode any value-returning function as a void function by adding an extra outgoing parameter to carry back the computed result. If both a void function and a value-returning function are acceptable, use the one you feel more comfortable implementing.
39
Ignoring a Function Value
The C++ language lets you ignore the value returned by a value-returning function.
40
Testing and Debugging One of the advantages of a modular design is that you can test it long before the code has been written for all of the modules. If we test each module individually , then we can assemble the modules into a complete program with much greater confidence that the program is correct. In this section, we introduce a technique for testing a module separately.
41
Stubs and Drivers Stubs : A dummy function that assists in testing part of a program. A stub has the same name and interface as a function that actually would be called by the part of the program being tested, but it is usually much simpler. Driver : A simple main function that is used to call a function being tested. The use of a driver permits direct control of the testing process.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.