an introduction to programming though c++cs101/lectures/lec8.pdfa problem • write a program that...
TRANSCRIPT
An Introduction to Programming though C++
Abhiram G. Ranade
Ch. 9: Functions
Can we define new commands?
• We already have many commands, e.g.– sqrt(x) evaluates to the square root of x.– forward(d) moves the turtle forward d pixels.
• Can we define new commands? e.g.– gcd(m,n) should evaluate to the GCD of m,n.– dash(d) should move the turtle forward, but draw
dashes as it moves rather than a continuous line.
• Function: official name for “command”
Outline
• Example of defining and using functions• How to define a function in general• How a function executes• “Contract” view of functions• Passing parameters by reference• Pointers• Functions and graphics objects
A problem• Write a program that prints the GCD of 36,
24, and of 99, 47.
• Using what you already know:– Make 2 copies of code to find GCD. – Use the first copy to find the GCD of 36, 24. – Use the second copy to find the GCD of 99, 47.
• Duplicating code is not good.– May make mistakes in copying. – What if we need the GCD at 10 places in the
program?– If we need to change later we need to
remember to change in 10 places.– Inelegant: Ideally, you should not have to state
anything more than once.
main_program{ int m=36, n=24; while(m % n != 0){
int r = m%n;m = n;n = r;
} cout << n << endl; m=99; n=47; while(m % n != 0){
int r = m%n;m = n;n = r;
} cout << n << endl;}
Using a function • Code has 2 parts: function definition + main programMain program: • “calls” or “invokes” function.gcd(a,b) : call or invocationgcd(99,47) : another call• Call includes values whose GCD is to be calculated.
– a, b in first call– 99, 47 in second
• Values supplied as part of a call: “arguments to the call”
Function definition:• function name • how it is to be called• what happens when function is executed.
int gcd(int m, int n){ while(m % n != 0){
int r = m%n;m = n;n = r;
} return n;}
main_program{ int a=36,b=24; cout << gcd(a,b) << endl; cout << gcd(99,47)<< endl;}
General form of function definitions
return-type name-of-function( parameter1-type parameter1-name, parameter2-type parameter2-name, …){ function-body}• return-type : the type of the value returned by the
function, e.g. int. • Some functions may not return anything, discussed
later.• name-of-function: e.g. gcd• parameter : variables that will be used to hold the
values of the arguments to the function. m,n in gcd.• function-body : code that will get executed.
int gcd(int m, int n){ while(m % n != 0){
int r = m%n;m = n;n = r;
} return n;}
main_program{ int a=36,b=24; cout << gcd(a,b) << endl; cout << gcd(99,47)<< endl;}
How a function executes
• main_program starts execution• Control reaches gcd(a,b)• main_program suspends.• Preparations made to run “subprogram” gcd:• Area allocated in memory where gcd will have
its variables. “activation frame”• Variables corresponding to parameters are
created in activation frame.• Values of arguments are copied from
activation frame of main_program to that of gcd. This is termed “passing arguments by value”.
• a=36, b=24 copied to m, n.
int gcd(int m, int n){ while(m % n != 0){
int r = m%n;m = n;n = r;
} return n;}
main_program{ int a=36,b=24; cout << gcd(a,b) << endl; cout << gcd(99,47)<< endl;}
Execution continued
• Execution of gcd starts.• n = 12 calculated.• Execution ends when “return”
statement is encountered.• Value following the word return, 12, is
copied back to the calling programWill be used in place of the expression gcd(…,…)• Activation frame of function is destroyed,
i.e. memory reserved for it is taken back.• main_program resumes, prints 12, ...
int gcd(int m, int n){ while(m % n != 0){
int r = m%n;m = n;n = r;
} return n;}
main_program{ int a=36,b=24; cout << gcd(a,b) << endl; cout << gcd(99,47)<< endl;}
Remarks
• Set of variables in calling program e.g. main_program is completely disjoint from the set in called function, e.g. gcd.
• Both may contain same name. – Calling program will refer to the variables in its activation frame.– Called program will refer to the variables in its activation frame.
• Arguments to calls/invocations can be expressions– Evaluated, then copied to parameters of called function.
• Function definition must appear before any call to it in the program file.
Remarks
• The body of a function can contain practically anything.– Can create new variables.– Can get input and produce output using cin, cout– Can call other functions, defined earlier.–Main program is also a function, discussed later.– Can use graphics canvas and access turtle created
using turtleSim().– Other graphics objects can also be accessed –
discussed later.
Exercise: Write a program to determine whether a number is even
bool even(int n){ if(n%2 == 0) return true; else return false;}
bool even(int n){ return (n%2 == 0);}
What we have discussed
• What is a function• How to define a function• How it executes• Next: More examples and how to think of
functions🎻
Exercise: Write function to compute LCM (Least common multiple)
Use the identity LCM(m,n) = m*n/GCD(m,n).
int lcm(int m, int n){ return m*n/gcd(m,n);}
• lcm calls gcd. So gcd definition must appear before lcm.
Program to find LCM using functions gcd, lcm
int gcd(int m, int n){ … return n}int lcm(int m, int n){ return m*n/gcd(m,n);}main_program{ cout << lcm(50,75);}• Functions and main program must appear in the given order.
Execution
int gcd(int m, int n){ … return n}int lcm(int m, int n){ return m*n/gcd(m,n);}main_program{ cout << lcm(50,75);}• main program starts executing• Call lcm(...) reached. Main program
suspends.• Activation frame created for lcm.
• 50, 75 copied to m,n. lcm starts execution.• call to gcd encountered. lcm suspends.• Activation frame created for gcd. • 50, 75 copied to m,n• Execution of gcd starts• gcd computes 25 as result.• Result copied to activation frame of lcm, • Activation frame of gcd destroyed.• lcm continues execution using result. • m*n/gcd(m,n)= 50*75/25 = 150 computed• returned to main_program• Activation frame of lcm destroyed.• main_program resumes and prints 150.
Function to draw dashes while moving
void dash(double d, int n){ repeat(n){
forward(d/2/n); penUp();
forward(d/2/n); penDown();
}return;
}
main_program{turtleSim();repeat(4){dash(100,5);
right(90);}getClick();
}• dash does not return a value, so
its return type is void.• The statement return used in
the body does not have a value after the word return.
Contract view of functions
• Function : piece of code which takes the responsibility of getting something done.
• Specification : what the function is supposed to do: “If the arguments satisfy certain properties, then a certain value will be returned, or a certain action will happen.”
• “certain properties” = “preconditions”• Example: gcd : If positive integers are given as arguments, then
their GCD will be returned.• If preconditions are not satisfied, nothing is promised.• Before you write a function, you should write its specification as a
comment
Contract view of functions (contd.)
• Function = contract between the programmer who wrote the function, and programmers who use it.
• Programmer who uses the function – trusts the function writer to make sure that the execution satisfies the
specification.– does not otherwise care how the function executes.
• Programmer who wrote the function does not care which program uses it.
• Analogous to giving cloth to tailor. – Tailor promises to give you a shirt if the cloth is good.–Wearer does not care how it was stitched.– Tailor does not care who wears the shirt,
Contract view of functions (contd.)
• Postcondition: What is promised about the state of the computer after the function finishes execution.
• Example: After dash finishes its execution we may want it to satisfy the postcondition that the pen is up. – not true for the code given earlier.– Exercise: Modify the code of dash to ensure that the pen is up at
the end.
• Post conditions must also be mentioned in the specification.
• Writing clear specifications is very important.
What we discussed
• If you are going to execute the same code several times, possibly with different values:– Define a function that executes the code– Call the function with appropriate values.
• Functions can have their own variables which are created in the activation area of the function.– Names can be same in the main program and in the function
• A function is like an independent program except that it gets some values (arguments) from the calling program, and returns results to the calling program.
• Next: Reference parameters🎻
Some shortcomings
Using what we just learned, it is not possible to write functions to do the following:• A function that exchanges the values of two
variables.• A function that produces several values as results:– Function to produce polar coordinates given Cartesian
coordinates.
Exchanging the values of two variables, attempt 1
void exchange(int m, int n){int temp = m;m = n; n = temp;return;
}main_program{
int a=1, b=2;exchange(a,b);cout << a <<‘ ‘<<
b << endl;}
• Does not work. 1, 2 will get printed.
• When exchange is called, 1, 2 are placed into m, n.
• Execution of exchange exchanges values of m,n.
• Change in m,n does not affect the values of a,b of main_program.
Reference parameters
void exchange(int &m, int &n){int temp = m;m = n; n = temp;return;
}main_program{
int a=1, b=2;exchange(a,b);cout << a <<‘ ‘<<
b << endl;}
• & before the name of the parameter:
• Says: “Do not allocate space for this parameter, but instead just use the variable from the calling program.”
• When function changes m,n it is really changing a,b.
• Such parameters are called reference parameters.
• 2 1 will be printed.
Remark
• If a certain parameter is a reference parameter, then the corresponding argument is said to be “passed by reference”.
• Now we can write a program that computes polar coordinates given cartesian coordinates–We use two reference parameters.– Called function stores the polar coordinates in the reference
parameters.– These changes can be seen my the main program.
• There are other ways of returning 2 values – study later.
Cartesian to polar
void CtoP(double x, double y, double &r, double &theta){
r = sqrt(x*x + y*y);theta = atan2(y, x); //arctan
return;}main_program{
double x=1, y=1, r, theta;CtoP(x,y,r,theta);cout << r <<‘ ‘<< theta << endl;
}
• r, theta in CtoP are reference parameters,
• changing them in CtoP changes the value of r, theta in the main program.
• Hence sqrt(2) and pi/4 (45 degrees) will be printed.
Exercises
Write a function which takes a length in inches and returns the length in yards, feet, and inches. Note that 12 inches make a foot, and 3 feet make a yard. As an example: 100 inches = 3 yards, 2 feet, 4 inches. Hint: your function will have 4 parameters, one in which you will pass the given length, and the other 3 in which the function will put the the number of yards, number of feet and number of inches.
What we discussed
• If we want to return more than one result we can do so by using a reference parameter.
• If we use a reference parameter R in a function, and pass as argument a variable A, then any change that the function makes in R will be seen by the calling program as a change in A.
• Next: Pointers, which perform a similar function.🎻
Pointers
• If the memory of a computer has N bytes, then the bytes are numbered 0..N-1.
• The number of a byte (different from what is stored in the byte) is said to be its address.
• A pointer is a variable that can store addresses. – Sometimes “pointer” might mean address.
• What we accomplished using reference variables can also be accomplished using pointers. – This will be seen soon.
• Pointers will also be useful elsewhere.
How to find the address of a variable
• The operator & can be used to get the address of a variable. – The same & is used to mark reference parameters; but the meaning will
be clear from the context.
int t;cout << &t << endl;• This prints the address of the variable t, i.e. the address of the
first byte that comprises the variable t. • Customarily, addresses get printed in hexadecimal radix, i.e. they
will consist of a sequence of hexadecimal digits prefixed by “0x”• Note: hexadecimal digits: 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F.
Variables that can store addresses
• How to create a variable for storing addresses of variables of type int :
int *v; // read as “int star v”• The * is not to be read as multiplication. – Think of it as (int*) v; where int* means the type: “address of int”.
int p;v = &p; // address of p stored in v• Since p is of type int, &p has type address of int. • Thus, it is OK to store &p in v, which is also of type address of int.cout << v <<‘ ‘<< &p << endl; // both print samev = p; // compile time error: type mismatch
Pointers in general
• In general, to create a variable w to store addresses of variables of type T, write:
T* w;• Assignment statements: types of lhs and rhs must be same– Except when both sides are numeric types; then conversion rules
used.– No conversion rule between pointers of one type and pointers of
other types.– No conversion rule between pointers of one type and values of
any type.
The dereferencing operator *
• If v contains the address of p, then we can get to p by writing *v.int *v;int p;v = &p;*v = 10; // as good as p = 10.• Think of * as the inverse of &. • &p : the address of the variable p• *v : the variable whose address is in v• int *v; – v is such that *v is an int– v is an address of an int
Pointers in functions
void CtoP(double x, double y, double *pr, double *ptheta){ *pr = sqrt(x*x + y*y); *ptheta = atan2(x,y); return;}main_program{ double r, theta; CtoP(1,1,&r,&theta); cout << r <<‘ ‘ << theta << endl;}
• main_program calls CtoP, supplying &r, &theta as third and fourth arguments.
• This is acceptable because corresponding parameters have type double*.
• The first step of the call copies the addresses of r,theta of the main_program into pr, ptheta of CtoP.
• *pr means the variable whose address is in pr, in other words, the variable r of main_program.
• Thus CtoP changes the variables of main_program.
• Thus r becomes √2 = 1.41 and theta becomes π/4 = 0.79 and are printed.
Remarks
• In variable definitions, * associates to the right. Example:int *v, p;• This means int *v; and int p; i.e. defines a variable v of type int*, and variable p of type int.
• For now, assume that the only operations you can perform on a variable of type T* are– dereference it, – store into it a value &v where v is of type T, – store it into another variable of type T*– pass it to a function as an argument, provided corresponding parameter
is of type T*
Exercise
• Point out the errors in this code.int *p, *q, w;p = w;q = 3;• What is the result of executing the following:int *p, *q, w, x;p = &w;w = 10;q = &x;*q = 20;cout << *p + x <<endl;
What we discussed
• A pointer is an address or a variable containing an address.• A pointer to a variable can be created in the main program
and dereferenced during a function call.• This way a function can be allowed to modify variables in
the main program, or other functions.• Pointers can do the same thing as references, but the
notation is clumsier.• But pointers can do other things too. (Later)🎻
Functions and graphics objects• You can pass graphics objects to functions.• The parameter must have the same type,
i.e. shape.• If you pass by value, a copy of the variable
is made for use in the called function.– The copy is destroyed when the function returns.
• If you pass by reference of pass a pointer, the function can operate on the original graphics object.
• If you imprint an object in a call, the image will survive after the call finishes.
• Incidentally, you can make a copy of an object even using assignment
Rectangle r(100,100,80,20); Rectangle s=r;
void Rev360(Rectangle &r){ repeat(36){ r.right(10); r.imprint(); wait(0.01); }}
main_program{ initCanvas(); Rectangle r(100,100,80,20); Rev360(r); getClick();}
Exercise
Write a function which takes a rectangle and coordinates x, y as input and decides whether the point (x,y) lies inside the rectangle.You will need to know the following useful operations that can be performed on any rectangle R.• R.getX() : returns the x coordinate of the rectangle center• R.getY() : returns the y coordinate of the rectangle center• R.getWidth() : returns the width of the rectangle• R.getHeight() : returns the height of the rectangle
Concluding remarks
• If you find that you are performing the same operation at several places in your program, consider making it into a function.
• Function = “packaged software component”.– The user of the function does not need to worry what happens inside the function.– The user only expects the specification of the function to be honoured.
• Arguments can be passed by value: – If corresponding parameter is modified in function, no direct effect in calling program.
• Arguments can be passed by reference: – If corresponding parameter is modified in function, variable in calling program
changes.
• Argument is a pointer to a variable in the calling function:– Code in called function can access variable by dereferencing pointer.
Exercises
• Write a function that draws an n sided regular polygon such that each side has length s, and returns the perimeter (n*s) as the result.
• Write a function that returns the cube root of a number using Newton’s method. Have an additional parameter to the function for specifying the number of iterations you want performed.
• Other exercises at the end of Chapter 9.🎻🎻