6.096 Lecture 3: Functions How to reuse code Geza Kovacs #include using namespace std; int main() { int threeExpFour = 1; for (int i = 0; i < 4; i = i + 1) { threeExpFour = threeExpFour * 3; } cout << "3^4 is " << threeExpFour << endl; return 0; } #include using namespace std; int main() { int threeExpFour = 1; for (int i = 0; i < 4; i = i + 1) { threeExpFour = threeExpFour * 3; } cout << "3^4 is " << threeExpFour << endl; int sixExpFive = 1; for (int i = 0; i < 5; i = i + 1) { sixExpFive = sixExpFive * 6; } cout << "6^5 is " << sixExpFive << endl; return 0; } Copy-paste coding #include using namespace std; int main() { int threeExpFour = 1; for (int i = 0; i < 4; i = i + 1) { threeExpFour = threeExpFour * 3; } cout << "3^4 is " << threeExpFour << endl; int sixExpFive = 1; for (int i = 0; i < 5; i = i + 1) { sixExpFive = sixExpFive * 6; } cout << "6^5 is " << sixExpFive << endl; int twelveExpTen = 1; for (int i = 0; i < 10; i = i + 1) { twelveExpTen = twelveExpTen * 12; } cout << "12^10 is " << twelveExpTen << endl; return 0; } Copy-paste coding (bad) #include using namespace std; //some code which raises an arbitrary integer //to an arbitrary power int main() { int threeExpFour = raiseToPower(3, 4); cout << "3^4 is " << threeExpFour << endl; return 0; } With a function With a function #include using namespace std; //some code which raises an arbitrary integer //to an arbitrary power int main() { int threeExpFour = raiseToPower(3, 4); cout << "3^4 is " << threeExpFour << endl; int sixExpFive = raiseToPower(6, 5); cout << "6^5 is " << sixExpFive << endl; return 0; } With a function #include using namespace std; //some code which raises an arbitrary integer //to an arbitrary power int main() { int threeExpFour = raiseToPower(3, 4); cout << "3^4 is " << threeExpFour << endl; int sixExpFive = raiseToPower(6, 5); cout << "6^5 is " << sixExpFive << endl; int twelveExpTen = raiseToPower(12, 10); cout << "12^10 is " << twelveExpTen << endl; return 0; } Why define your own functions? • Readability: sqrt(5) is clearer than copy-pasting in an algorithm to compute the square root • Maintainability: To change the algorithm, just change the function (vs changing it everywhere you ever used it) • Code reuse: Lets other people use algorithms you’ve implemented Function Declaration Syntax int raiseToPower(int base, int exponent) { int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } return result; } Function name Function Declaration Syntax int raiseToPower(int base, int exponent) { int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } return result; } Return type Function Declaration Syntax int raiseToPower(int base, int exponent) { int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } return result; } Argument 1 • Argument order matters: – raiseToPower(2,3) is 2^3=8 – raiseToPower(3,2) is 3^2=9 Function Declaration Syntax int raiseToPower(int base, int exponent) { int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } return result; } Argument 2 • Argument order matters: – raiseToPower(2,3) is 2^3=8 – raiseToPower(3,2) is 3^2=9 Function Declaration Syntax int raiseToPower(int base, int exponent) { int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } return result; } signature Function Declaration Syntax int raiseToPower(int base, int exponent) { int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } return result; } body Function Declaration Syntax int raiseToPower(int base, int exponent) { int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } return result; } Return statement #include using namespace std; int raiseToPower(int base, int exponent) { int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } return result; } int main() { int threeExpFour = raiseToPower(3, 4); cout << "3^4 is " << threeExpFour << endl; return 0; } Function invocation Function declaration Returning a value • Up to one value may be returned; it must be the same type as the return type. int foo() { return "hello"; //error } char* foo() { return "hello"; //ok } Returning a value • Up to one value may be returned; it must be the same type as the return type. • If no values are returned, give the function a void return type void printNumber(int num) { cout << "number is " << num << endl; } int main() { printNumber(4); //number is 4 return 0; } Returning a value • Up to one value may be returned; it must be the same type as the return type. • If no values are returned, give the function a void return type – Note that you cannot declare a variable of type void int main() { void x; //ERROR return 0; } Returning a value • Return statements don’t necessarily need to be at the end. • Function returns as soon as a return statement is executed. void printNumberIfEven(int num) { if (num % 2 == 1) { cout << "odd number" << endl; return; } cout << "number is " << num << endl; } int main() { int x = 4; printNumberIfEven(x); //number is 3 int y = 5; printNumberIfEven(y); //odd number } Argument Type Matters • printOnNewLine(3) works • printOnNewLine("hello") will not compile void printOnNewLine(int x) { cout << x << endl; } Argument Type Matters • printOnNewLine(3) will not compile • printOnNewLine("hello") works void printOnNewLine(char *x) { cout << x << endl; } Argument Type Matters • printOnNewLine(3) works • printOnNewLine("hello") also works void printOnNewLine(int x) { cout << x << endl; } void printOnNewLine(char *x) { cout << x << endl; } Function Overloading • Many functions with the same name, but different arguments • The function called is the one whose arguments match the invocation void printOnNewLine(int x) { cout << "Integer: " << x << endl; } void printOnNewLine(char *x) { cout << "String: " << x << endl; } Function Overloading • printOnNewLine(3) prints “Integer: 3” • printOnNewLine(“hello”) prints “String: hello” void printOnNewLine(int x) { cout << "Integer: " << x << endl; } void printOnNewLine(char *x) { cout << "String: " << x << endl; } Function Overloading • printOnNewLine(3) prints “1 Integer: 3” • printOnNewLine(2, 3) prints “2 Integers: 2 and 3” void printOnNewLine(int x) { cout << "1 Integer: " << x << endl; } void printOnNewLine(int x, int y) { cout << "2 Integers: " << x << " and " << y << endl; } • Function declarations need to occur before invocations int foo() { return bar()*2; //ERROR -bar hasn’t been declared yet } int bar() { return 3; } • Function declarations need to occur before invocations – Solution 1: reorder function declarations int bar() { return 3; } int foo() { return bar()*2; //ok } • Function declarations need to occur before invocations – Solution 1: reorder function declarations – Solution 2: use a function prototype; informs the compiler you’ll implement it later int bar(); int foo() { return bar()*2; //ok } int bar() { return 3; } function prototype • Function prototypes should match the signature of the method, though argument names don’t matter int square(int); int cube(int x) { return x*square(x); } int square(int x) { return x*x; } function prototype • Function prototypes should match the signature of the method, though argument names don’t matter int square(int x); int cube(int x) { return x*square(x); } int square(int x) { return x*x; } function prototype • Function prototypes should match the signature of the method, though argument names don’t matter int square(int z); int cube(int x) { return x*square(x); } int square(int x) { return x*x; } function prototype • Function prototypes are generally put into separate header files – Separates specification of the function from its implementation //myLib.h -header //contains prototypes int square(int); int cube (int); //myLib.cpp -implementation #include "myLib.h" int cube(int x) { return x*square(x); } int square(int x) { return x*x; } Recursion • Functions can call themselves. • fib(n) = fib(n-1) + fib(n-2) can be easily expressed via a recursive implementation int fibonacci(int n) { if (n == 0 || n == 1) { return 1; } else { return fibonacci(n-2) + fibonacci(n-1); } } Recursion • Functions can call themselves. • fib(n) = fib(n-1) + fib(n-2) can be easily expressed via a recursive implementation base case int fibonacci(int n) { if (n == 0 || n == 1) { return 1; } else { return fibonacci(n-2) + fibonacci(n-1); } } Recursion • Functions can call themselves. • fib(n) = fib(n-1) + fib(n-2) can be easily expressed via a recursive implementation recursive step int fibonacci(int n) { if (n == 0 || n == 1) { return 1; } else { return fibonacci(n-2) + fibonacci(n-1); } } Global Variables • How many times is function foo() called? Use a global variable to determine this. – Can be accessed from any function int numCalls = 0; void foo() { ++numCalls; } int main() { foo(); foo(); foo(); cout << numCalls << endl; //3 } Global variable Scope • Scope: where a variable was declared, determines where it can be accessed from int numCalls = 0; int raiseToPower(int base, int exponent) { numCalls = numCalls + 1; int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } return result; } int max(int num1, int num2) { numCalls = numCalls + 1; int result; if (num1 > num2) { result = num1; } else { result = num2; } return result; } Scope • Scope: where a variable was declared, determines where it can be accessed from • numCalls has global scope – can be accessed from any function int numCalls = 0; int raiseToPower(int base, int exponent) { numCalls = numCalls + 1; int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } return result; } int max(int num1, int num2) { numCalls = numCalls + 1; int result; if (num1 > num2) { result = num1; } else { result = num2; } return result; } Scope • Scope: where a variable was declared, determines where it can be accessed from • numCalls has global scope – can be accessed from any function • result has function scope – each function can have its own separate variable named result int numCalls = 0; int raiseToPower(int base, int exponent) { numCalls = numCalls + 1; int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } return result; } int max(int num1, int num2) { numCalls = numCalls + 1; int result; if (num1 > num2) { result = num1; } else { result = num2; } return result; } int numCalls = 0; int raiseToPower(int base, int exponent) { numCalls = numCalls + 1; int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } //A return result; } int max(int num1, int num2) { numCalls = numCalls + 1; int result; if (num1 > num2) { result = num1; } else { result = num2; } //B return result; } Global scope raiseToPower function scope max function scope int base int exponent int result int num1 int num2 int result int numCallsint numCalls = 0; int raiseToPower(int base, int exponent) { numCalls = numCalls + 1; int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } //A return result; } int max(int num1, int num2) { numCalls = numCalls + 1; int result; if (num1 > num2) { result = num1; } else { result = num2; } //B return result; } Global scope raiseToPower function scope max function scope int base int exponent int result int num1 int num2 int result int numCalls A • At A, variables marked in green are in scope int numCalls = 0; int raiseToPower(int base, int exponent) { numCalls = numCalls + 1; int result = 1; for (int i = 0; i < exponent; i = i + 1) { result = result * base; } //A return result; } int max(int num1, int num2) { numCalls = numCalls + 1; int result; if (num1 > num2) { result = num1; } else { result = num2; } //B return result; } • At B, variables marked in blue are in scope Global scope raiseToPower function scope max function scope int base int exponent int result int num1 int num2 int result int numCalls Bdouble squareRoot(double num) { double low = 1.0; double high = num; for (int i = 0; i < 30; i = i + 1) { double estimate = (high + low) /2; if (estimate*estimate > num) { double newHigh = estimate; high = newHigh; } else { double newLow = estimate; low = newLow; } } return (high + low) /2; } • Loops and if/else statements also have their own scopes – Loop counters are in the same scope as the body of the for loop squareRoot function scope for loop scope If statement scope else statement scope double low double high double num double estimate int i double newHigh double newLowdouble squareRoot(double num) { double low = 1.0; double high = num; for (int i = 0; i < 30; i = i + 1) { double estimate = (high + low) /2; if (estimate*estimate > num) { double newHigh = estimate; high = newHigh; } else { double newLow = estimate; low = newLow; } } //A return estimate; //ERROR } • Cannot access variables that are out of scope squareRoot function scope for loop scope If statement scope else statement scope double low double high double num double estimate int i double newHigh double newLow Adouble squareRoot(double num) { double low = 1.0; double high = num; for (int i = 0; i < 30; i = i + 1) { double estimate = (high + low) /2; if (estimate*estimate > num) { double newHigh = estimate; high = newHigh; } else { double newLow = estimate; low = newLow; } if (i == 29) return estimate; //B } return -1; //A } • Cannot access variables that are out of scope • Solution 1: move the code squareRoot function scope for loop scope If statement scope else statement scope double low double high double num double estimate int i double newHigh double newLow A Bdouble squareRoot(double num) { double low = 1.0; double high = num; double estimate; for (int i = 0; i < 30; i = i + 1) { estimate = (high + low) /2; if (estimate*estimate > num) { double newHigh = estimate; high = newHigh; } else { double newLow = estimate; low = newLow; } } return estimate; //A } • Cannot access variables that are out of scope • Solution 2: declare the variable in a higher scope squareRoot function scope for loop scope If statement scope else statement scope double low double high double num double estimate int i double newHigh double newLow APass by value vs by reference • So far we’ve been passing everything by value – makes a copy of the variable; changes to the variable within the function don’t occur outside the function //pass-by-value void increment(int a) { a = a + 1; cout << "a in increment " << a << endl; } int main() { int q = 3; increment(q); //does nothing cout << "q in main " << q << endl; } Output a in increment 4 q in main 3 Pass by value vs by reference //pass-by-value void increment(int a) { a = a + 1; cout << "a in increment " << a << endl; } int main() { int q = 3; //HERE increment(q); //does nothing cout << "q in main " << q << endl; } Output a in increment 4 q in main 3 main function scope q=3Pass by value vs by reference //pass-by-value void increment(int a) { //HERE a = a + 1; cout << "a in increment " << a << endl; } int main() { int q = 3; increment(q); //does nothing cout << "q in main " << q << endl; } Output a in increment 4 q in main 3 main function scope q=3 increment function scope a=3Pass by value vs by reference //pass-by-value void increment(int a) { a = a + 1; //HERE cout << "a in increment " << a << endl; } int main() { int q = 3; increment(q); //does nothing cout << "q in main " << q << endl; } Output a in increment 4 q in main 3 main function scope q=3 increment function scope a=4Pass by value vs by reference • If you want to modify the original variable as opposed to making a copy, pass the variable by reference (int &a instead of int a) //pass-by-value void increment(int &a) { a = a + 1; cout << "a in increment " << a << endl; } int main() { int q = 3; increment(q); //works cout << "q in main " << q << endl; } Output a in increment 4 q in main 4 Pass by value vs by reference //pass-by-value void increment(int &a) { a = a + 1; cout << "a in increment " << a << endl; } int main() { int q = 3; //HERE increment(q); //works cout << "q in main " << q << endl; } Output a in increment 4 q in main 4 main function scope q=3Pass by value vs by reference //pass-by-value void increment(int &a) { //HERE a = a + 1; cout << "a in increment " << a << endl; } int main() { int q = 3; increment(q); //works cout << "q in main " << q << endl; } Output a in increment 4 q in main 4 main function scope increment function scope q=3 aPass by value vs by reference //pass-by-value void increment(int &a) { a = a + 1; //HERE cout << "a in increment " << a << endl; } int main() { int q = 3; increment(q); //works cout << "q in main " << q << endl; } Output a in increment 4 q in main 4 main function scope increment function scope q=4 aImplementing Swap void swap(int &a, int &b) { int t = a; a = b; b = t; } int main() { int q = 3; int r = 5; swap(q, r); cout << "q " << q << endl; //q 5 cout << "r " << r << endl; //r 3 } Implementing Swap void swap(int &a, int &b) { int t = a; a = b; b = t; } int main() { int q = 3; int r = 5; //HERE swap(q, r); cout << "q " << q << endl; //q 5 cout << "r " << r << endl; //r 3 } main function scope q=3 r=5Implementing Swap void swap(int &a, int &b) { //HERE int t = a; a = b; b = t; } int main() { int q = 3; int r = 5; swap(q, r); cout << "q " << q << endl; //q 5 cout << "r " << r << endl; //r 3 } main function scope swap function scope q=3 r=5 a bImplementing Swap void swap(int &a, int &b) { int t = a; //HERE a = b; b = t; } int main() { int q = 3; int r = 5; swap(q, r); cout << "q " << q << endl; //q 5 cout << "r " << r << endl; //r 3 } main function scope swap function scope q=3 r=5 a b t=3Implementing Swap void swap(int &a, int &b) { int t = a; a = b; //HERE b = t; } int main() { int q = 3; int r = 5; swap(q, r); cout << "q " << q << endl; //q 5 cout << "r " << r << endl; //r 3 } main function scope swap function scope q=5 r=5 a b t=3Implementing Swap void swap(int &a, int &b) { int t = a; a = b; b = t; //HERE } int main() { int q = 3; int r = 5; swap(q, r); cout << "q " << q << endl; //q 5 cout << "r " << r << endl; //r 3 } main function scope swap function scope q=5 r=3 a b t=3Returning multiple values • The return statement only allows you to return 1 value. Passing output variables by reference overcomes this limitation. int divide(int numerator, int denominator, int &remainder) { remainder = numerator % denominator; return numerator /denominator; } int main() { int num = 14; int den = 4; int rem; int result = divide(num, den, rem); cout << result << "*" << den << "+" << rem << "=" << num << endl; //3*4+2=12 } Libraries • Libraries are generally distributed as the header file containing the prototypes, and a binary .dll/.so file containing the (compiled) implementation – Don’t need to share your .cpp code //myLib.h – header //contains prototypes double squareRoot(double num); myLib.dll myLib.dll //libraryUser.cpp – some other guy’s code #include "myLib.h" double fourthRoot(double num) { return squareRoot(squareRoot(num)); } • Library user only needs to know the function prototypes (in the header file), not the implementation source code (in the .cpp file) – The Linker (part of the compiler) takes care of locating the implementation of functions in the .dll file at compile time //myLib.h – header //contains prototypes double squareRoot(double num); Final Notes • You don’t actually need to implement raiseToPower and squareRoot yourself; cmath (part of the standard library) contains functions pow and sqrt #include double fourthRoot(double num) { return sqrt(sqrt(num)); } MIT OpenCourseWare http://ocw.mit.edu 6.096 Introduction to C++ January (IAP) 2011 For information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms.
Description
Function is a subprogram/submodule. Basically functions are two types system defined functions and user defined functions.Arguments can be passed to the functions with the help of two mechanisams. One is call by value and another one is call by reference. The process of calling the function in the same function is called Recursion. Here the function overloading is discussed. The scope of variables such as global and local and swap is explained here.
“Jesse Dunietz, Geza Kovacs & John Marrero, 6.096-3.Functions, 6.096 Introduction to C++, Electrical Engineering and Computer Science, Engineering, Massachusetts Institute of Technology: MIT Open Course Ware,http://ocw.mit.edu (21-08-2011).License: Creative Commons BY-NC-SA: http://ocw.mit.edu/terms/#cc".