functions illustration of: pass by value, reference scope allocation reference: see your cs115/215...
TRANSCRIPT
Functions
Illustration of: Pass by value, referenceScopeAllocationReference: See your CS115/215 textbook
float CircleArea (float r) {const float Pi = 3.1415;
return Pi * r * r;
}
Function Definition
Function bodyReturn statement
Local object definition
Formal parameterReturn type Function name
Function Prototype
float CircleArea (float r);
Function prototype (or actual function) must appear in file before the function is called
Function Invocation
cout << CircleArea(MyRadius) << endl;
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().
Actual parameter
// Include statements first#include <iostream> using namespace std; // Using statementfloat CircleArea(float r); // function prototypes// main(): manage circle computationint 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 circlefloat CircleArea(float r) { const float Pi = 3.1415; return Pi * r * r;}
Two Characteristics of Variables
Scope – where can you reference the variable nameAllocation – where is the variable kept in storage
Variable Scope
Global – can be referenced within any function in any source file of the programStatic – can be referenced within any function in the source file where it is declaredFunction – can be referenced within a functionBlock – can be referenced within a block - set of curly braces {}
Global Scope
Variables defined outside of functions are globalA 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
Global Example
float pi = 3.14159; // usual use of globalint i = 1; // example to illustrate scope resolutionint 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;}
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.
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;
Function Scope
Parameters passed to a function and any variables declared at the start of the function have function scopeFunction scope means that they can be referenced anywhere in the function (including all blocks in the function)
Blocks can be put anywhere a statement can be put
Blocks within blocks are nested blocksTypical 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
Block Scope
A block is a list of statements within curly braces
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}
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
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 blockEach scope area can have a variable of the same name: Global, static (one variable only) Function (each function) Block (each block)
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 }
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;
}
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
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 parameterFunction 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)
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;
}
Swap defined as Pass by Reference
void Swap(int &a, int &b) {
int Temp = a;
a = b;
b = Temp;
return;
}
Return statement notnecessary for void functions
Passed by reference -- in aninvocation the actual
parameter is given ratherthan a copy
Correct Pass By Reference
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;
}
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;
}
Pass Address By Reference
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;
}
Pass Address By Value
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;
}
Passing Data/AddressesVariables can be data or the addresses of dataBoth can be passed by value or referencePassing a variable by value: the called function cannot change the caller’s variablePassing a variable by reference: the called function can change the callers variableIf 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 addressIf 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
Arrays are passed by reference
The name of the array is its addressint 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 }
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}
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 the stream a reference parameter?
Why is MyNumber a reference parameter?
Language Parameter Passing
These are the rules for C++Pass by value, pass by reference are general terms, but…Each language has its own rulesYou must not assume the language follows C++ rules
Allocation: Global and Static
Global and static scope variables: Included with program instructions Only one copy referenced by all
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
37
Stack Activation Framesthe 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
38
// 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 caseresult = Func ( - a , - b ) ; // instruction 70
return result;
}
38
39
FCTVAL ? result ? b 2 a 5Return Address 100
Run-Time Stack Activation Records
x = Func(5, 2); // original call at instruction 100
original call at instruction 100 pushes on this record for Func(5,2)
40
FCTVAL ? result ? b 1 a 5Return Address 50
FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return Address 100
record for Func(5,2)
call in Func(5,2) codeat instruction 50 pushes on this recordfor Func(5,1)
Run-Time Stack Activation Records
x = Func(5, 2); // original call at instruction 100
41
FCTVAL ? result ? b 0 a 5Return Address 50
FCTVAL ? result 5+Func(5,0) = ? b 1 a 5Return Address 50
FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return Address 100
record for Func(5,2)
record for Func(5,1)
call in Func(5,1) codeat instruction 50pushes on this record for Func(5,0)
Run-Time Stack Activation Records
x = Func(5, 2); // original call at instruction 100
42
FCTVAL 0 result 0 b 0 a 5Return Address 50
FCTVAL ? result 5+Func(5,0) = ? b 1 a 5Return Address 50
FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return Address 100
record for Func(5,0)is popped first with its FCTVAL
Run-Time Stack Activation Records
x = Func(5, 2); // original call at instruction 100
record for Func(5,2)
record for Func(5,1)
43
record for Func(5,2)
record for Func(5,1)is popped nextwith its FCTVAL
Run-Time Stack Activation Records
x = Func(5, 2); // original call at instruction 100
FCTVAL 5 result 5+Func(5,0) = 5+ 0 b 1 a 5Return Address 50
FCTVAL ? result 5+Func(5,1) = ? b 2 a 5Return Address 100
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
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;}
Dynamic Allocation
Use of new operator allocates variable in dynamic storage (or heap)Stays allocated until delete operator is usedCan only be accessed via a pointerIf you lose access to the pointer, you lose access to the variable
Memory Leak
Variable allocated in dynamic storage within a functionFunction returns without deallocation via delete
void funca() {float *pi = new float;*pi = 3.14159;…..return;}
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 exitsDynamic storage variables allocated with new operator, freed with delete operator, referenced indirectly via pointer
Scope Summary
Global variables known anywhere in any source fileStatic variables (declared outside of function) known in any function in their fileFunction variables known anywhere in the functionBlock variables known in its block (and nested blocks)
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 rulesYou must not assume the language has the same rules as C++
Passing an Object
Objects can be passed by value or referenceIf you don’t want the object modified, you can pass by value. This is safer, but execution is slower and the destructor will be calledYou can pass by reference but use the const keyword for faster execution (and to not call the destructor):
void funca(const rational & rationalObject)
Pass an Object by Reference
If you pass by value, the class destructor is called when the function returns to destroy the passed copy of the objectThis can lead to unwanted side effects. Your destructor may be doing cleanup operations that you only wanted done when the object is no longer used (for example, a linked list object).Always pass an object by reference. Use the const keyword if you do not want the object modified.