520 likes | 635 Views
0. Functions. Illustration of: Pass by value, reference Scope Allocation Reference: See your CS115/215 textbook. 0. Function Definition. Function name. Formal parameter. float CircleArea (float r) { const float Pi = 3.1415; return Pi * r * r; }. Return type.
E N D
0 Functions Illustration of: Pass by value, reference Scope Allocation Reference: See your CS115/215 textbook
0 Function Definition Function name Formal parameter float CircleArea (float r) { const float Pi = 3.1415; return Pi * r * r; } Return type Local object definition Function body Return statement
0 Function Prototype float CircleArea (float r); Function prototype (or actual function) must appear in file before the function is called
0 Function Invocation cout << CircleArea(MyRadius) << endl; Actual parameter To process the invocation, the function that contains the insertion statement is suspended and CircleArea() does its job. The insertion statement is then completed using the value supplied by CircleArea().
0 // Include statements first #include <iostream> using namespace std; // Using statement float CircleArea(float r); // function prototypes // main(): manage circle computation int main() { // Always a main function cout << "Enter radius: "; float MyRadius; cin >> MyRadius; float Area = CircleArea(MyRadius); cout << "Circle has area " << Area; return 0; } // CircleArea(): compute area of radius r circle float CircleArea(float r) { const float Pi = 3.1415; return Pi * r * r; }
0 Two Characteristics of Variables • Scope – where can you reference the variable name • Allocation – where is the variable kept in storage
0 Variable Scope • Global – can be referenced within any function in any source file of the program • Static – can be referenced within any function in the source file where it is declared • Function – can be referenced within a function • Block – can be referenced within a block - set of curly braces {}
0 Global Scope • Variables defined outside of functions are global • A global variable can be used by any function in the file that is defined after the global variable • It is best to avoid programmer-defined global variables • Exceptions tend to be important constants • Globals with appropriate declarations can even be used in other program files • Local variables can reuse a global variable's name • scope resolution operator :: can provide access to global even if name reuse has occurred
0 Global Example float pi = 3.14159; // usual use of global int i = 1; // example to illustrate scope resolution int main() { cout << i << endl; // print 1 { char i = 'a'; cout << i << endl; // print a ::i = 2; cout << i << endl; // print a cout << ::i << endl; // print 2 } cout << i << endl; // print 2 return 0; }
0 Use of Global in Other Source Files File 1: float pi = 3.14159; // pi can be used (and modified) in file1 File 2: extern float pi; // pi can be used (and modified) in file 2 // pi cannot be initialized (except in file 1) There is only one global variable pi. Code in either file can access or change it. A global variable can be initialized in only one file. All other files that need to access it use the extern keyword.
0 Static Scope • Similar to global scope (declared outside of any function) but: • Use static keyword • Can only be referenced in this file (never any other file) • For example: static float pi = 3.14159;
0 Function Scope • Parameters passed to a function and any variables declared at the start of the function have function scope • Function scope means that they can be referenced anywhere in the function (including all blocks in the function)
0 Block Scope Blocks can be put anywhere a statement can be put Blocks within blocks are nested blocks Typical use of blocks are for while, for, if clauses A variable is known only within the block in which it is defined and in nested blocks of that block • A block is a list of statements within curly braces
0 Block Scope Example void f(int a) { // a has function scope int i = 1; // this i has function scope cout << i << endl; // print 1 { int j = 10; // j has block scope cout << i << j << endl; // print 1 10 int i = 2; // this i has block scope cout << i << endl; // print 2 } cout << i << endl; // print 1 cout << j << endl; // illegal }
0 For, While, If Blocks • For variables only used within a while, for, or if, clause, use block scope for (int i = 0; i < MAX; i++) { …… } A for block iterator is a typical example
0 Name Reuse • If a nested block defines an object with the same name as enclosing block, the new definition is in effect in the nested block • Each scope area can have a variable of the same name: • Global, static (one variable only) • Function (each function) • Block (each block)
0 However, Don’t Do This At Home void f() { float i = 3.14159; // function scope i { int i = 1; // block 1 scope i cout << i << endl; // print 1 { cout << i << endl; // print 1 char i = 'a'; // block 2 scope i cout << i << endl; // print a } cout << i << endl; // print 1 } cout << i << endl; // print 3.14159 }
0 Calling a function to swap variables // Will Swap swap Number1, Number 2?????? int main() { int Number1 = PromptAndRead(); int Number2 = PromptAndRead(); if (Number1 > Number2) { Swap(Number1, Number2); // Swap? } cout << "The numbers in sorted order:" << Number1 << ", " << Number2 << endl; return 0; }
0 Will Swap swap? • IF parameters passed by value: NO • If parameters passes by reference: YES
0 Using Pass by Value void Swap(int a, int b) { int Temp = a; a = b; b = Temp; return; }
0 Doesn’t change the caller’s variables!
0 Pass by Value Rules • Formal parameter is created on function invocation and it is initialized with the value of the actual parameter Changes to formal parameter do not affect actual parameter Reference to a formal parameter produces the value for it in the current activation record New activation record for every function invocation Formal parameter name is only known within its function Formal parameter ceases to exist when the function completes Activation record memory is automatically released at function completion
0 Pass by Reference • If the formal argument declaration is a reference parameter then • Formal parameter becomes an alias for the actual parameter • Changes to the formal parameter change the actual parameter • Function definition determines whether a parameter’s passing style is by value or by reference • Reference parameter form ptypei &pnamei void Swap(int &a, int &b)
0 Same Call to Swap But… void Swap(int &a, int &b); int main() { int Number1 = PromptAndRead(); int Number2 = PromptAndRead(); if (Number1 > Number2) { Swap(Number1, Number2); } cout << "The numbers in sorted order: " << Number1 << ", " << Number2 << endl; return 0; }
0 Swap defined as Pass by Reference void Swap(int &a, int &b) { int Temp = a; a = b; b = Temp; return; } Passed by reference -- in aninvocation the actualparameter is given ratherthan a copy Return statement notnecessary for void functions
int i = 5; int j = 6; Swap(i, j); int a = 7; int b = 8; Swap(b, a); void Swap(int &a, int &b) { int Temp = a; a = b; b = Temp; return; } 0 Correct Pass By Reference
0 C Style Reference Parameters void IndirectSwap(char *Ptr1,char *Ptr2){ char c = *Ptr1; *Ptr1 = *Ptr2; *Ptr2 = c; } int main() { char a = 'y'; char b = 'n'; IndirectSwap(&a, &b); cout << a << b << endl; return 0; }
int i = 0; int* ptrj = &i; FuncA(ptrj); // i is now 5 // ptrj is now NULL void FuncA(int* &a) { // Caller’s variables // can be changed *a = 5; a = NULL; return; } 0 Pass Address By Reference
int i = 0; int* ptrj = &i; FuncA(ptrj); // i is now 5 // ptrj is still &i void FuncA(int* a) { // Cannot change ptrj // Can change i *a = 5; a = NULL; return; } 0 Pass Address By Value
Passing Data/Addresses • Variables can be data or the addresses of data • Both can be passed by value or reference • Passing a variable by value: the called function cannot change the caller’s variable • Passing a variable by reference: the called function can change the callers variable • If an address is passed by value, the called function can change the caller’s data that the address is pointing to, but not the caller’s passed address • If an address is passed by reference, the called function can change the caller’s data that the address is pointing to, and the caller’s passed address
0 Arrays are passed by reference • The name of the array is its address int myarray1[10], myarray2[10]; ….. copyArray(myarray1, myarray2,arraysize); ….. void copyArray (int array1[], int array2[], int size) { // int* array1, int* array2 works also for (int i = 0; i < size; i++) array1[i] = array2[i]; // Copies caller’s array2 into array1 }
0 Passing Array Elements • You can pass individual array elements if needed: printArrayIndex(array1[4]); …. void printArrayIndex (int element) { cout << element; element++; // Does not change caller’s array }
0 Passing a File Stream • Function to extract a value from a given stream (opened in the caller) void GetNumber(int &MyNumber, istream &sin) { sin >> MyNumber; return; } Why is MyNumber a reference parameter? Why is the stream a reference parameter?
0 Language Parameter Passing • These are the rules for C++ • Pass by value, pass by reference are general terms, but… • Each language has its own rules • You must not assume the language follows C++ rules
0 Allocation: Global and Static • Global and static scope variables: • Included with program instructions • Only one copy referenced by all
0 Allocation: Function and Block • Allocated on the stack (activation record) when the function is called • Deallocated (stack storage is freed for reuse) when function returns
0 Stack Activation Frames • the activation record contains the return address for this function call, and also the parameters, and local variables, and space for the function’s return value, if non-void • the activation record for a particular function call is popped off the run-time stack when the final closing brace in the function code is reached, or when a return statement is reached in the function code • at this time the function’s return value, if non-void, is brought back to the calling block return address for use there
0 // A recursive function int Func ( /* in */ int a, /* in */ int b ) // Pre: Assigned(a) && Assigned(b) // Post: Function value == ?? { int result; if ( b == 0 ) // base case result = 0; else if ( b > 0 ) // first general case result = a + Func ( a , b - 1 ) ; // instruction 50 else // second general case result = Func ( - a , - b ) ; // instruction 70 return result; } 38
0 Run-Time Stack Activation Recordsx = Func(5, 2);// original call at instruction 100 FCTVAL ? result ? b 2 a 5 Return Address 100 original call at instruction 100 pushes on this record for Func(5,2)
record for Func(5,2) 0 Run-Time Stack Activation Recordsx = Func(5, 2);// original call at instruction 100 FCTVAL ? result ? b 1 a 5 Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 a 5 Return Address 100 call in Func(5,2) code at instruction 50 pushes on this record for Func(5,1)
record for Func(5,1) record for Func(5,2) 0 Run-Time Stack Activation Recordsx = Func(5, 2);// original call at instruction 100 call in Func(5,1) code at instruction 50 pushes on this record for Func(5,0) FCTVAL ? result ? b 0 a 5 Return Address 50 FCTVAL ? result 5+Func(5,0) = ? b 1 a 5 Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 a 5 Return Address 100
0 Run-Time Stack Activation Recordsx = Func(5, 2);// original call at instruction 100 FCTVAL 0 result 0 b 0 a 5 Return Address 50 FCTVAL ? result 5+Func(5,0) = ? b 1 a 5 Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 a 5 Return Address 100 record for Func(5,0) is popped first with its FCTVAL record for Func(5,1) record for Func(5,2)
0 Run-Time Stack Activation Recordsx = Func(5, 2);// original call at instruction 100 FCTVAL 5 result 5+Func(5,0) = 5+ 0 b 1 a 5 Return Address 50 FCTVAL ? result 5+Func(5,1) = ? b 2 a 5 Return Address 100 record for Func(5,1) is popped next with its FCTVAL record for Func(5,2)
0 Static Declaration in a Function • To have a variable in a function keep its value, you can declare the variable static • Its scope is function (or block) • But it is put in the global/static storage with the program • Its value is initialized only once (first call) • After that it retains its value between calls
0 Function Scope Example To count how many times a function was called: void readFile( …… ) { static int numberOfCalls = 0; numberOfCalls++; …….. cout << “This function has been called “ << numberOfCalls << “ times” << endl; }
0 Dynamic Allocation • Use of new operator allocates variable in dynamic storage (or heap) • Stays allocated until delete operator is used • Can only be accessed via a pointer • If you lose access to the pointer, you lose access to the variable
0 Memory Leak • Variable allocated in dynamic storage within a function • Function returns without deallocation via delete void funca() { float *pi = new float; *pi = 3.14159; ….. return; }
0 Allocation Summary • Global, static variables get loaded into storage with program, initialized once (on start of program) • Function, block variables get allocated on stack when function accessed, deallocated when function exits • Dynamic storage variables allocated with new operator, freed with delete operator, referenced indirectly via pointer
0 Scope Summary • Global variables known anywhere in any source file • Static variables (declared outside of function) known in any function in their file • Function variables known anywhere in the function • Block variables known in its block (and nested blocks)
0 Language Rules • These are the rules for C++ • Each language (for example, Java, Perl) has the concepts of scope and allocation, but… • Each language has its own rules • You must not assume the language has the same rules as C++