0% found this document useful (0 votes)
16 views66 pages

Functions in C++

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views66 pages

Functions in C++

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 66

Lecture 3:

Functions
How to reuse code
#include <iostream>
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 <iostream>
Copy-paste using namespace std;

coding 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;
}
#include <iostream>
Copy-paste using namespace std;

coding int main() {


int threeExpFour = 1;

(bad) 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;
}
With a #include <iostream>
using namespace std;
function // 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 #include <iostream>
using namespace std;
function // 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 #include <iostream>
using namespace std;
function // 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
Function name

int raiseToPower(int base, int exponent)


{
int result = 1;
for (int i = 0; i < exponent; i = i + 1) {
result = result * base;
}
return result;
}
Function Declaration Syntax
Return type

int raiseToPower(int base, int exponent)


{
int result = 1;
for (int i = 0; i < exponent; i = i + 1) {
result = result * base;
}
return result;
}
Function Declaration Syntax
Argument 1

int raiseToPower(int base, int exponent)


{
int result = 1;
for (int i = 0; i < exponent; i = i + 1) {
result = result * base;
}
return result;
}

• Argument order matters:


– raiseToPower(2,3) is 2^3=8
– raiseToPower(3,2) is 3^2=9
Function Declaration Syntax
Argument 2

int raiseToPower(int base, int exponent)


{
int result = 1;
for (int i = 0; i < exponent; i = i + 1) {
result = result * base;
}
return result;
}

• Argument order matters:


– raiseToPower(2,3) is 2^3=8
– raiseToPower(3,2) is 3^2=9
Function Declaration Syntax

signature int raiseToPower(int base, int exponent)


{
int result = 1;
for (int i = 0; i < exponent; i = i + 1) {
result = result * base;
}
return result;
}
Function Declaration Syntax

int raiseToPower(int base, int exponent)


{
int result = 1;
for (int i = 0; i < exponent; i = i + 1) {
body result = result * base;
}
return result;
}
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 <iostream>
using namespace std;

Function int raiseToPower(int base, int exponent) {


declaration int result = 1;
for (int i = 0; i < exponent; i = i + 1) {
result = result * base;
}
return result;
}
Function invocation
int main() {
int threeExpFour = raiseToPower(3, 4);
cout << "3^4 is " << threeExpFour << endl;
return 0;
}
Returning a value
• Up to one value may be returned; it must be the same type as
the return type.

int foo() char* foo()


{ {
return "hello"; // error 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 << "even number; number is "
<< num << endl;
}

int main() {
int x =
4;
printNumberI
fEven(x);
// even number; number is 3
int y = 5;
Argument Type Matters

void printOnNewLine(int x)
{
cout << x << endl;
}

• printOnNewLine(3) works
• printOnNewLine("hello") will not compile
Argument Type Matters

void printOnNewLine(char *x)


{
cout << x << endl;
}

• printOnNewLine(3) will not compile


• printOnNewLine("hello") works
Argument Type Matters
void printOnNewLine(int x)
{
cout << x << endl;
}

void printOnNewLine(char *x)


{
cout << x << endl;
}

• printOnNewLine(3) works
• printOnNewLine("hello") also works
Function Overloading
void printOnNewLine(int x)
{
cout << "Integer: " << x << endl;
}

void printOnNewLine(char *x)


{
cout << "String: " << x << endl;
}

• Many functions with the same name, but


different arguments
• The function called is the one whose
arguments match the invocation
Function Overloading
void printOnNewLine(int x)
{
cout << "Integer: " << x << endl;
}

void printOnNewLine(char *x)


{
cout << "String: " << x << endl;
}

• printOnNewLine(3) prints “Integer: 3”


• printOnNewLine(“hello”) prints “String: hello”
Function Overloading
void printOnNewLine(int x)
{
cout << "1 Integer: " << x << endl;
}

void printOnNewLine(int x, int y)


{
cout << "2 Integers: " << x << " and " << y << endl;
}

• printOnNewLine(3) prints “1 Integer: 3”


• printOnNewLine(2, 3) prints “2 Integers: 2 and 3”
• 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(); function prototype

int foo()
{
return bar()*2; // ok
}

int bar()
{
return 3;
}
• Function prototypes should match the signature of the
method, though argument names don’t matter

int square(int); function prototype

int cube(int x)
{
return x*square(x);
}

int square(int x)
{
return x*x;
}
• Function prototypes should match the signature of the
method, though argument names don’t matter

int square(int x); function prototype

int cube(int x)
{
return x*square(x);
}

int square(int x)
{
return x*x;
}
• Function prototypes should match the signature of the
method, though argument names don’t matter

int square(int z); function prototype

int cube(int x)
{
return x*square(x);
}

int square(int x)
{
return x*x;
}
• Function prototypes are generally put into separate
header files
– Separates specification of the function from its
implementation

// myLib.h - header // myLib.cpp - implementation


// contains prototypes #include "myLib.h"

int square(int); int cube(int x)


int cube (int); {
return x*square(x);
}

int square(int x)
{
return x*x;
}
Recursio
n
• 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);
}
}
Recursio
n
• 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) {
base case return 1;
} else {
return fibonacci(n-2) +
fibonacci(n-1);
}
}
Recursio
n
• 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 {
recursive step 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; Global variable

void foo() {
++numCalls;
}

int main() {
foo(); foo(); foo();
cout << numCalls << endl; // 3
}
int numCalls = 0;

Scope int raiseToPower(int base, int exponent) {


numCalls = numCalls + 1;
int result = 1;
for (int i = 0; i < exponent; i = i + 1) {
• Scope: where a result = result * base;
variable was declared, }
determines where it return result;
}
can be accessed from
int max(int num1, int num2) {
numCalls = numCalls + 1;
int result;
if (num1 > num2) {
result = num1;
}
else {
result = num2;
}
return result;
}
int numCalls = 0;

Scope int raiseToPower(int base, int exponent) {


numCalls = numCalls + 1;
int result = 1;
for (int i = 0; i < exponent; i = i + 1) {
• Scope: where a result = result * base;
variable was declared, }
determines where it return result;

can be accessed from }


• numCalls has global int max(int num1, int num2) {
scope – can be numCalls = numCalls + 1;
int result;
accessed from any
if (num1 > num2) {
function result = num1;
}
else {
result = num2;
}
return result;
}
int numCalls = 0;

Scope int raiseToPower(int base, int exponent) {


numCalls = numCalls + 1;
int result = 1;
for (int i = 0; i < exponent; i = i + 1) {
• Scope: where a result = result * base;
variable was declared, }
determines where it return result;

can be accessed from }


• numCalls has global int max(int num1, int num2) {
scope – can be numCalls = numCalls + 1;
int result;
accessed from any
if (num1 > num2) {
function result = num1;
• result has function }
scope – each function else {
result = num2;
can have its own }
separate variable return result;
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;
}
// A
return result;
}
int max(int num1, int num2) {
numCalls = numCalls + 1; Global scope
int result;
if (num1 > num2) { int
result = num1; numCalls

}
else {
result = num2;
}
// B raiseToPower function scope max function scope
return result;
}
int int int int int int
base exponent result num1 num2 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 • At A, variables marked in
return result;
}
green are in scope
int max(int num1, int num2) {
numCalls = numCalls + 1; Global scope
int result;
if (num1 > num2) { int
result = num1; numCalls

}
else {
result = num2;
}
// B raiseToPower function scope max function scope
return result;
}
int int int int int int
base exponent result A
num1 num2 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 • At B, variables marked in
return result;
}
blue are in scope
int max(int num1, int num2) {
numCalls = numCalls + 1; Global scope
int result;
if (num1 > num2) { int
result = num1; numCalls

}
else {
result = num2;
}
// B raiseToPower functi on scope max functi on scope
return result;
}
int int int int int int
base exponent result B
num1 num2 result
double 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) { squareRoot function scope
double newHigh = estimate;
high = newHigh;
double double double
} else { num low high
double newLow = estimate;
low = newLow;
}
} for loop scope
return (high + low) / 2;
}
double
• Loops and if/else int i estimate

statements also have


their own scopes If statement scope else statement scope

– Loop counters are in the


same scope as the body of double
newHigh
double
newLow

the for loop


double 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) { squareRoot function scope
double newHigh = estimate;
high = newHigh;
double double double
} else { num low high
A

double newLow = estimate;


low = newLow;
}
} for loop scope
// A
return estimate; // ERROR
double
} int i estimate

• Cannot access variables


that are out of scope If statement scope else stateme nt scope

double double
newHigh newLow
double 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) { squareRoot function scope
double newHigh = estimate;
high = newHigh; double double double
A
} else { num low high
double newLow = estimate;
low = newLow;
}
if (i == 29) for loop scope
return estimate; // B
}
double
return -1; // A int i estimate
B
}
• Cannot access variables
that are out of scope If statement scope else statement scope

• Solution 1: move the double double


newLow
code
newHigh
double 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; squareRoot function scope
if (estimate*estimate > num) {
double newHigh = estimate;
double double double double
high = newHigh; num low high estimate
A

} else {
double newLow = estimate;
low = newLow;
} for loop scope
}
return estimate; // A
} int i

• Cannot access variables


that are out of scope If statement scope else stateme nt scope

• Solution 2: declare the double double

variable in a higher scope


newHigh newLow
Pass 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() {
Output
int q = 3;
increment(q); // does nothing a in increment 4
cout << "q in main " << q << endl;
}
q in main 3
Pass by value vs by reference
main functi on scope

q=3

// pass-by-value
void increment(int a) {
a = a + 1;
cout << "a in increment
" << a << endl;
}
int main() {
Output
int q = 3; // HERE
increment(q); // does nothing a in increment 4
cout << "q in main " << q <<
endl;
q in main 3
}
Pass by value vs by reference
main functi on scope increment functi on scope

q=3 a=3

// pass-by-value
void increment(int a) { // HERE
a = a + 1;
cout << "a in increment " << a
<< endl;
}
int main() {
Output
int q = 3;
increment(q); // does nothing a in increment 4
cout << "q in main " << q << endl;
}
q in main 3
Pass by value vs by reference
main functi on scope increment functi on scope

q=3 a=4

// pass-by-value
void increment(int a) {
a = a + 1; // HERE
cout << "a in increment
" << a << endl;
}
int main() {
Output
int q = 3;
increment(q); // does nothing a in increment 4
cout << "q in main " << q << endl;
}
q in main 3
Pass 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() {
Output
int q = 3;
increment(q); // works a in increment 4
cout << "q in main "
<< q << endl;
q in main 4
}
Pass by value vs by reference
main functi on scope

q=3

// pass-by-value
void increment(int &a) {
a = a + 1;
cout << "a in increment
" << a << endl;
}
int main() {
Output
int q = 3; // HERE
increment(q); // works a in increment 4
cout << "q in main "
<< q << endl;
q in main 4
}
Pass by value vs by reference
main function scope increment function scope

q=3 a

// pass-by-value
void increment(int &a) { // HERE
a = a + 1;
cout << "a in increment " << a
<< endl;
}
int main() {
Output
int q = 3;
increment(q); // works a in increment 4
cout << "q in main "
<< q << endl;
q in main 4
}
Pass by value vs by reference
main function scope increment function scope

q=4 a

// pass-by-value
void increment(int &a) {
a = a + 1; // HERE
cout << "a in increment
" << a << endl;
}
int main() {
Output
int q = 3;
increment(q); // works a in increment 4
cout << "q in main "
<< q << endl;
q in main 4
}
Implementing 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) { main functi on scope
int t = a;
a = b;
b =
q=3 r=5
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
}
Implementing Swap
void swap(int &a, int &b) { // HERE main function scope
int t = a;
a = b;
b =
t; q=3 r=5
}
int main() {
int q = 3;
int r = 5;
swap(q, r); swap function scope
cout << "q " << q << endl; // q 5
cout << "r " << r << endl; // r 3
} a b
Implementing Swap
void swap(int &a, int &b) { main function scope
int t = a; // HERE
a = b;
b =
t; q=3 r=5
}
int main() {
int q = 3;
int r = 5;
swap(q, r); swap function scope
cout << "q " << q << endl; // q 5
cout << "r " << r << endl; // r 3
} a b t=3
Implementing Swap
void swap(int &a, int &b) { main function scope
int t = a;
a = b; // HERE
b = t;
} q=5 r=5

int main() {
int q = 3;
int r = 5;
swap(q, r); swap function scope
cout << "q " << q << endl; // q 5
cout << "r " << r << endl; // r 3
} a b t=3
Implementing Swap
void swap(int &a, int &b) { main function scope
int t = a;
a = b;
b = t; // HERE
} q=5 r=3

int main() {
int q = 3;
int r = 5;
swap(q, r); swap function scope
cout << "q " << q << endl; // q 5
cout << "r " << r << endl; // r 3
} a b t=3
Returning 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);
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
• 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
myLib.dll
double squareRoot(double num);

// libraryUser.cpp – some other guy’s code


#include "myLib.h"

double fourthRoot(double num)


{ return
squareRoot(squareRoot(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 <cmath>

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 .

You might also like