Upload
rodney-glenn
View
215
Download
0
Embed Size (px)
Citation preview
1
Functions
2
Objectives
You will be able to Write a function definition. Write a program that makes use of
functions. Design a small program by dividing it
into multiple functions. Make use of pre-existing functions in
libraries.
3
Functions
A function is a named block of code that can be executed by putting its name into a statement.
A very simple example:
void say_hello(){ printf ("Hello, world\n");}
int main (){ say_hello(); return 0;}
Function Header
Function Body
Function “Call”
Whenever the function name is reached in the stream of execution, the function body is executed.
Function Definition
Function Name
4
Functions
Our primary tool for coping with complexity.
Divide a big program into smaller pieces Each piece performs a well defined action Pieces can be further divided as needed Final result is nothing but small,
understandable pieces.
“Program Design”
5
Functions
Some things to notice.
void say_hello(){ printf ("Hello, world\n");}
No semicolon at end of function header.
For readability, align the curly brackets with the function header and indent the code within the function body by 3 spaces
(The usual rules for alignment of curly brackets.)
The function body is delimited by curly brackets.
No semicolon at end of function definition.
6
Functions
This is NOT textual substitution like #define
The compiler produces executable code from the function definition.
The compiler generates code for the function call that transfers control to the function body.
The function body includes executable code to return control back to the next statement after the function call.
7
A Note about Examples
Examples used in this lecture will all be very simple. Show the mechanisms Avoid obscuring the concepts with
details
In order to be useful, functions in real life are more complex. But not a lot more complex. Typically should fit on one page.
8
Function Parameters
A function definition can include one or more variables, called parameters, to be supplied by the call.
double average (double n1, double n2 ){ return (n1 + n2) / 2.0;}
The function call must provide values for function’s parameters.
A value passed to the function by the call is referred to as an argument.
Each argument becomes the initial value of a parameter when the function is called.
Inside the function body, parameters act like normal variables.
Parameters
9
Function Arguments
void print_int (int x) {
printf ("The integer is %d\n", x); }
int main (){ ... print_int (33);}
Function Definition
Function Call
x = 33; /* Effect of call */Parameter
Argument
10
Returned Value
A function can perform a computation and return the result.
The result is the “value” of the function name. Can be used in assignment statement. Can be used in an expression.
11
Returning a Result
int square (int x){ return x*x;}
int main (){ int num; int num_squared; printf ("Enter number to be squared: "); scanf ("%d", & num);
num_squared = square(num);
printf ("The square of %d is %d\n", num, num_squared); return 0;}
Function Definition
num_squared is set to the value returned by function
This says that the function returns a value of type int.
The value of num becomes the value of x for the function
The value of x*x becomes the value of square(num)
Returning a Result
13
Using Returned Values in an Expression
int main (){ int a = 0; int b = 0; int c_squared = 0; printf ("Enter a: "); scanf ("%d", &a); printf ("Enter b: "); scanf ("%d", &b);
c_squared = square(a) + square(b);
return 0;}
A function call can be used in any expression just like a variable.
14
Returning a Result
If a function is declared with a type other than void, it must return a value of that type.
return x*x;
If a function is declared as void, it must not return a result. Can return using the statement:
return;
Can simply run to completion.
15
Function Prototypes
A function definition begins with a function header
int average (int a, int b)
Function name
Parameters and their types.
Type of returned value
The compiler needs this information in order to compile the function call.
This information is referred to as the function prototype
a.k.a. function signature
16
Function Prototypes
If the function definition appears in the source file before the function call, the compiler automatically knows the function prototype.
Otherwise, we have to provide it in the form of a function declaration somewhere prior to the function call.
int average (int a, int b);
A function declaration must be followed by a semicolon.
In the function definition, this information is NOT followed by a semicolon. (It is followed by the function body.)
17
Function Prototypes
Programming Style Issue: Function declarations, if needed,
should appear near the beginning of the source file, following any #define lines.
18
Function Declaration Example
#include <stdio.h>
int square (int x);
int main (){ int value = 0; int value_squared = 0; printf ("Enter value to be squared: "); scanf ("%d", &value); value_squared = square(value); printf ("The square of %d is %d\n", value, value_squared); return 0;}
int square (int x){ return x*x;}
Function declaration
Function call
Function definition
19
Function Prototypes
If we tell the compiler the function prototype in a function declaration prior to any calls, the function definition can appear anywhere. Even in a different file that is compiled
separately.
End of Section
20
Libraries
Functions can be collected and compiled separately to form a library. Standard Libraries
Defined by the C Language standards Included with every C compiler Example: The Standard IO Library Details in Chapter 23.
Local Libraries Locally written functions intended for reuse
Proprietary Libraries Software products
21
Standard Libraries
The standard libraries are essentially like extensions to the C language.
Standard I/O Library printf(), getchar(), scanf(), others Chapter 22
The C Mathematics Library sin(), cos(), exp(), log() Complete list starting on page 593
22
Libraries
Functions in libraries are compiled separately.
Separately compiled object code is added to the executable file by the linker.
Function prototypes for the library functions are collected in a header file for the library. Added to user’s source file with #include.
23
Example
#include <stdio.h>
int square (int x);
int main (){ int value = 0; int value_squared = 0; printf ("Enter value to be squared: "); ...}
Function prototypes for all functions in the Standard I/O Library are inserted here by the preprocessor.
The compiler knows the function prototype for printf() because or the #include.
The call to function printf() causes the linker to add the precompiled code for function printf() to the executable file.
24
Example: hypotenuse.c
A program to compute the length of the hypotenuse of a right triangle, given the lengths of the other two sides, a and b. a and b must be in the range 0 < x < 1000000
Will use a function to get user inputs for the two sides. Verify that input is valid. Ask user to provide a different value if not.
Example: hypotenuse.c
/* Compute length of hypotenuse of a right triangle */
#include <stdio.h>#include <math.h>
/* Get user input for length of a side. */double get_length(){ double length = 0; while (1) { scanf ("%lg", &length); if ((length > 0) && (length <= 1000000)) { return length; } printf ("Value must be greater than 0 “); printf (“and no more than 1000000\n"); printf ("Please enter a valid value\n"); }}
A local variable.
Example: hypotenuse.cint main (){ double a = 0; double b = 0; double c = 0; /* Hypotenuse */
printf ("This program computes the length of the hypotenuse\n"); printf ("of a right triangle, given the lengths of the other\n"); printf ("two sides, a and b\n"); printf ("a and b must be between zero and 1000000\n");
printf ("Enter a: "); a = get_length(); printf ("Enter b: "); b = get_length();
printf (“Sides are %10.4f and %10.4f\n", a, b);
c = sqrt(a*a + b*b);
printf ("Length of hypotenuse is %10.4f\n", c); return 0;}
Get value of “a” from user.Get value of “b” from user.
Local variables of function main()
Function in the math library
27
Example: hypotenuse.c
When we compile, we have to tell gcc to link with the math library.
Otherwise we get an “Undefined reference” error:
28
Example: hypotenuse.c
To tell the linker to link with the math library, include –lm in the command.
29
Recursion
Section 9.6
30
Objectives
You will be able to write functions that call themselves in
order to solve problems by dividing them into smaller but similar subproblems.
31
Recursive Function
A function that calls itself
Why?
Many algorithms can be expressed more clearly and concisely in recursive form.
"Divide and Conquer" Solve a smaller problem. Use result to solve original problem.
32
The Run-Time Stack
Hidden data structure in every C program. Maintained automatically. Not directly accessible to the program.
Each call to a function allocates some space on the run-time stack. Called a stack frame Function’s parameters are allocated here. Function’s local variables are allocated here,
Except variables declared as static. Return address is stored here.
33
The Run-Time Stack
Each successive function call allocates a new stack frame. Caller’s local variables are still on the
stack in a lower stack frame. Not visible to the newly called function. Will still be there when the called
function returns.
This makes it possible for a function to call itself.
34
Recursive Calls
If a function calls itself, there is a separate stack frame corresponding to each invocation. arguments local variables return address
A function can call itself multiple times without overwriting its local variables. But not an unlimited number of times. Eventually will run out of stack space!
35
A Very Simple Example
void countdown(int n){ printf ("n = %d\n", n); n--; if (n >= 0) { countdown(n); }}
int main ( ){ countdown(5); return 0;}
Call self
36
Compile and Run
37
A Very Minor Change
void countdown(int n){ //printf ("n = %d\n", n); n--; if (n >= 0) { countdown(n); } printf ("n = %d\n", n);}
int main ( ){ countdown(5); return 0;}
Now what is the output?
38
Compile and Run
Why did this happen?
39
Program countdown2.c
void countdown(int n){ //printf ("n = %d\n", n); n--; if (n >= 0) { countdown(n); } printf ("n = %d\n", n);}
int main ( ){ countdown(5); return 0;}
Last invocation prints first
First invocation prints last
Recursion can be tricky!
When it returns, next to last invocation prints....
40
Inappropriate Use of Recursion
A classic (and bad!) example of recursion is the factorial function.
41
Factorial Program
#include <stdio.h>
#include <assert.h>
int factorial(int n)
{
assert (n >= 0);
if (n <= 1)
{
return 1;
}
return n*factorial(n-1);
}
42
Factorial Program
int main()
{
int n = -1;
printf ("This program uses a recursive function\n");
printf ("to compute N factorial\n\n");
printf ("Enter N as a nonnegative integer: ");
while (n < 0)
{
scanf("%d", &n);
if (n < 0)
{
printf ("Invalid entry. Please try again\n");
while (getchar() != 'n'); // Clear keyboard input buffer
}
}
printf ("%d factorial is %d\n", n, factorial(n));
return 0;
}
43
Factorial Program in Action
44
Inappropriate Use of Recursion
Why is this an inappropriate use of recursion?
The problem is not inherently recursive. Can be solved just as easily with a loop.
Prefer loops over recursion when it is feasible to do so. Avoid the performance cost and
conceptual subtleties of recursion.
45
An Inherently Recursive Calculation
The Fibonacci series is defined as 1, 1, 2, 3, 5, ... where after the first two members, each member is the sum of the two preceding members.
46
Fibonacci main()int main()
{
int num, fibo;
printf ("This program computes Fibonacci numbers\n\n");
while (1)
{
printf ("Enter a (fairly small) integer: ");
if (scanf("%d", &num) == 1)
{
fibo = Fibonacci(num);
printf ("\nFibonacci(%d) = %d\n\n", num, fibo);
}
else
{
printf ("Input error\n");
printf ("Please try again\n\n");
while (getchar() != '\n'); // Clear input buffer
}
}
}
47
Recursive Implementation
int Fibonacci (int n)
{
if (n <= 2)
{
return 1;
}
return Fibonacci(n-1) + Fibonacci(n-2);
}
Try it!
48
Fibonacci Program in Action
Stopped with Ctrl-c
49
Measure Run Time
#include <time.h>
...
int main()
{
int num, fibo;
time_t start_time, end_time;
printf ("This program computes Fibonacci numbers\n\n");
while (1)
{
printf ("Enter a (fairly small) integer: ");
if (scanf("%d", &num) == 1)
{
time(&start_time);
fibo = Fibonacci(num);
time(&end_time);
printf ("\nFibonacci(%d) = %d\n", num, fibo);
printf ("%5.1f seconds\n\n", difftime(end_time, start_time));
}
}
50
Measure Run Time
Ctrl-c
51
Loop Implementation
int Fibonacci (int n)
{
int pred1 = 1;
int pred2 = 1;
int i, next;
if (n <= 2)
{
return 1;
}
for (i = 3; i <= n; i++)
{
next = pred1 + pred2; /* next is Fibonacci(i) */
pred2 = pred1;
pred1 = next;
}
return next;
}
52
Compare Implementations
How does the run time for the loop implementation compare to that for the recursive implementation?
End of Example
Properly Formed Recursive Processes
Every recursive process consists of two parts:1 One or more smallest base cases that are processed without recursion; 2 A general method that reduces an arbitrary non-base case to one or more
smaller cases The general method must be such that
repeated application of the method will eventually reach base cases
Towers of Hanoi
Brass platform with 3 diamond needles. On the first needle, 64 golden disks each slightly
smaller than the one underneath it.
Task: move all 64 disks to third needle, by moving one disk at a time from one needle to another so that a larger disk is never placed on top of a smaller one.
Story: at the creation of the world, Buddhist priests were told to accomplish the task and that when it was done, the world would end.
Solution to the Towers of Hanoi problem
Restate problem: move n disks from needle i to needle j using needle k as the auxiliary needle, where {i,j,k} = {1,2,3}
Recursive solution1 Move the top n-1 disks from i to k using j as auxiliary2 Move single disk from i to j3 Move n-1 disks from k to j using i as auxiliary
Code for recursive Towers of Hanoi
void Move(int count, int start, int finish, int temp){ if (count == 0)
return;if (count == 1) printf(“%d -> %d\n”, start, finish);
else { Move(count-1, start, temp, finish);
printf(“%d -> %d\n”, start, finish);Move(count-1, temp, finish, start);
}}
3,1,3,2
2,1,2,3 2,2,3,1
1,1,3,2 1,3,2,1 1,2,1,3 1,1,3,21->2
1->3
1->3 3->2 2->1
2->3
1->3
Recursion Tree for Move(3,1,3,2)
Instructions:
1->3 1->2 3->2 1->3 2->1 2->3 1->3
1->3
1->2
3->2
1->3
2->1
2->3
1->3
Analysis
By analyzing the recursion tree for Move you will find that the number of moves is
1 + 2 + ... + 2n1 = 2n1 For 64 disks, if the monks can move
one disk each second, it will take approximately 5*1011 years
This is 25 times the current estimated age of the universe!
72
Summary
Recursion is one of the key tricks of the programming trade.
“Divide and Conquer”
Many algorithms can be expressed more clearly and concisely using recursion. Typically at significant cost in terms of
execution time and memory usage.