functions illustration of: pass by value, reference scope allocation reference: see your cs115/215...

52
Functions Illustration of: Pass by value, reference Scope Allocation Reference: See your CS115/215 textbook

Upload: lawrence-griffin

Post on 19-Jan-2016

276 views

Category:

Documents


0 download

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;

}

Will Swap swap?

IF parameters passed by value: NOIf parameters passes by reference: YES

Using Pass by Value

void Swap(int a, int b) {

int Temp = a;

a = b;

b = Temp;

return;

}

Doesn’t change the caller’s variables!

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.