9 - Functions - Programming Language
9 - Functions - Programming Language
1
Introduction
A function is a series of statements that have been
grouped together and given a name.
Each function is essentially a small program, with
its own declarations and statements.
Advantages of functions:
A program can be divided into small pieces that are
easier to understand and modify.
We can avoid duplicating code that’s used more than
once.
A function that was originally part of one program
can be reused in other programs. 2
Program: Computing Averages
A function named average that computes the
average of two double values:
double average(double a, double b)
{
return (a + b) / 2;
}
The word double at the beginning is the return
type of average.
The identifiers a and b (the function’s parameters)
represent the numbers that will be supplied when
average is called.
3
Program: Computing Averages
Every function has an executable part, called the
body, which is enclosed in braces.
The body of average consists of a single
return statement.
Executing this statement causes the function to
“return” to the place from which it was called; the
value of (a + b) / 2 will be the value returned by
the function.
4
Program: Computing Averages
A function call consists of a function name followed
by a list of arguments.
average(x, y) is a call of the average function.
Arguments are used to supply information to a
function.
The call average(x, y) causes the values of x and y to
be copied into the parameters a and b.
An argument doesn’t have to be a variable; any
expression of a compatible type will do.
average(5.1, 8.9) and average(x/2, y/3)
are also acceptable. 5
Program: Computing Averages
We’ll put the call of average in the place where
we need to use the return value.
A statement that prints the average of x and y:
printf("Average: %g\n", average(x, y));
The return value of average isn’t saved; the
program prints it and then discards it.
If we had needed the return value later in the
program, we could have captured it in a variable:
avg = average(x, y);
6
average.c
/* Computes pairwise averages of three numbers */
#include <stdio.h>
return 0;
}
7
Program: Computing Averages
The average.c program reads three numbers and
uses the average function to compute their
averages, one pair at a time:
Enter three numbers: 3.5 9.6 10.2
Average of 3.5 and 9.6: 6.55
Average of 9.6 and 10.2: 9.9
Average of 3.5 and 10.2: 6.85
8
Computing Averages: Function Position
9
Computing Averages without
Return Type
10
Computing Averages without
Return Type
11
Program: Printing a Countdown
To indicate that a function has no return value, we specify
that its return type is void:
void print_count(int n)
{
printf("T minus %d and counting\n", n);
}
void is a type with no values.
A call of print_count must appear in a statement by
itself:
print_count(i);
The countdown.c program calls print_count 10
times inside a loop.
12
countdown.c
/* Prints a countdown */
#include <stdio.h>
void print_count(int n)
{
printf("T minus %d and counting\n", n);
}
How about this time?
int main(void) print_count(int n)
{ {
int i; printf("T minus %d and
counting\n", n);
for (i = 10; i > 0; --i) }
print_count(i);
return 0;
}
13
Printing a Countdown without
Return Type
14
Program: Printing a Pun
(Revisited)
When a function has no parameters, the word void is placed
in parentheses after the function’s name:
void print_pun(void)
{
printf("To C, or not to C: that is the question.\n");
}
To call a function with no arguments, we write the function’s
name, followed by parentheses:
print_pun();
The parentheses must be present.
The pun2.c program tests the print_pun function.
15
pun2.c
/* Prints a bad pun */
#include <stdio.h>
void print_pun(void)
{
printf("To C, or not to C: that is the question.\n");
}
int main(void)
{
print_pun();
return 0;
}
16
Function with ( )
17
Function Definitions
General form of a function definition:
return-type function-name ( parameters )
{
declarations
statements
}
18
Function Definitions
The return type of a function is the type of value
that the function returns.
Rules governing the return type:
Functions may not return arrays.
Specifying that the return type is void indicates that
the function doesn’t return a value.
If the return type is omitted in C89, the function is
presumed to return a value of type int.
In C99, omitting the return type is illegal.
19
Function Definitions
As a matter of style, some programmers put the
return type above the function name:
double
average(double a, double b)
{
return (a + b) / 2;
}
Putting the return type on a separate line is
especially useful if the return type is lengthy, like
unsigned long int.
20
Function Definitions
After the function name comes a list of parameters.
Each parameter is preceded by a specification of its
type; parameters are separated by commas.
If the function has no parameters, the word void
should appear between the parentheses.
21
Function Definitions
The body of a function may include both
declarations and statements.
An alternative version of the average function:
double average(double a, double b)
{
double sum; /* declaration */
sum = a + b; /* statement */
return sum / 2; /* statement */
}
22
Function Definitions
Variables declared in the body of a function
can’t be examined or modified by other
functions.
In C89, variable declarations must come first,
before all statements in the body of a function.
In C99, variable declarations and statements
24
Function Calls
A function call consists of a function name followed
by a list of arguments, enclosed in parentheses:
average(x, y)
print_count(i)
print_pun()
If the parentheses are missing, the function won’t be
called:
print_pun; /*** WRONG ***/
This statement is legal but has no effect.
25
Function Calls
A call of a void function is always followed by a
semicolon to turn it into a statement:
print_count(i);
print_pun();
A call of a non-void function produces a value
that can be stored in a variable, tested, printed, or
used in some other way:
avg = average(x, y);
if (average(x, y) > 0)
printf("Average is positive\n");
printf("The average is %g\n", average(x, y));
26
Function Calls
The value returned by a non-void function can
always be discarded if it’s not needed:
average(x, y); /* discards return value */
This call is an example of an expression statement:
a statement that evaluates an expression but then
discards the result.
27
Function Calls
Ignoring the return value of average is an odd
thing to do, but for some functions it makes sense.
printf returns the number of characters that it
prints.
After the following call, num_chars will have the
value 9:
num_chars = printf("Hi, Mom!\n");
We’ll normally discard printf’s return value:
printf("Hi, Mom!\n");
/* discards return value */
28
Function Calls
To make it clear that we’re deliberately discarding
the return value of a function, C allows us to put
(void) before the call:
(void) printf("Hi, Mom!\n");
Using (void) makes it clear to others that you
deliberately discarded the return value, not just
forgot that there was one.
29
Program:
Testing Whether a Number Is Prime
The prime.c program tests whether a number is
prime:
Enter a number: 34
Not prime
The program uses a function named is_prime
that returns true if its parameter is a prime number
and false if it isn’t.
is_prime divides its parameter n by each of the
numbers between 2 and the square root of n; if the
remainder is ever 0, n isn’t prime.
30
prime.c
/* Tests whether a number is prime */
bool is_prime(int n)
{
int divisor;
if (n <= 1)
return false;
for (divisor = 2; divisor * divisor <= n; divisor++)
if (n % divisor == 0)
return false;
return true;
}
31
int main(void)
{
int n;
32
Practice
Perfect number, a positive integer that is equal to
the sum of its proper divisors. The smallest perfect
number is 6, which is the sum of 1, 2, and 3
The program uses a function named is_prefect
that returns true if its parameter is a perfect
number and false if it isn’t.
Please write perfect.c program to list all the
perfect numbers under 10000.
33
#include <stdio.h>
int is_perfect(int n) {
int j, total=0;
for (j = 1; j < n; j++) {
if ((n % j) == 0) total += j;
}
return n == total ? 1 : 0;
}
int main(void)
{
int i, j, total = 0;
for ( i = 1; i <= 10000; i++)
{
if (is_perfect(i)) printf("%d ", i);
}
return 0;
}
34
Function Declarations
C doesn’t require that the definition of a function
precede its calls.
Suppose that we rearrange the average.c
program by putting the definition of average after
the definition of main.
35
Function Declarations
#include <stdio.h>
int main(void)
{
double x, y, z;
printf("Enter three numbers: ");
scanf("%lf%lf%lf", &x, &y, &z);
printf("Average of %g and %g: %g\n", x, y, average(x, y));
printf("Average of %g and %g: %g\n", y, z, average(y, z));
printf("Average of %g and %g: %g\n", x, z, average(x, z));
return 0;
}
double average(double a, double b)
{
return (a + b) / 2;
}
36
Function Declarations
When the compiler encounters the first call of
average in main, it has no information about the
function.
Instead of producing an error message, the compiler
assumes that average returns an int value.
We say that the compiler has created an implicit
declaration of the function.
37
Function Declarations
The compiler is unable to check that we’re passing
average the right number of arguments and that
the arguments have the proper type.
Instead, it performs the default argument
promotions and hopes for the best.
When it encounters the definition of average later
in the program, the compiler notices that the
function’s return type is actually double, not int,
and so we get an error message.
38
Function Declarations
One way to avoid the problem of call-before-
definition is to arrange the program so that the
definition of each function precedes all its calls.
Unfortunately, such an arrangement doesn’t always
exist.
Even when it does, it may make the program harder
to understand by putting its function definitions in
an unnatural order.
39
Function Declarations
Fortunately, C offers a better solution: declare each
function before calling it.
A function declaration provides the compiler with a brief
glimpse at a function whose full definition will appear
later.
General form of a function declaration:
return-type function-name ( parameters ) ;
The declaration of a function must be consistent with the
function’s definition.
Here’s the average.c program with a declaration of
average added.
40
Function Declarations
#include <stdio.h>
double average(double a, double b); /* DECLARATION */
int main(void)
{
double x, y, z;
printf("Enter three numbers: ");
scanf("%lf%lf%lf", &x, &y, &z);
printf("Average of %g and %g: %g\n", x, y, average(x, y));
printf("Average of %g and %g: %g\n", y, z, average(y, z));
printf("Average of %g and %g: %g\n", x, z, average(x, z));
return 0;
}
double average(double a, double b) /* DEFINITION */
{
return (a + b) / 2;
}
41
Function Declarations
Function declarations of the kind we’re discussing
are known as function prototypes.
C also has an older style of function declaration in
which the parentheses are left empty.
A function prototype doesn’t have to specify the
names of the function’s parameters, as long as their
types are present:
double average(double, double);
It’s usually best not to omit parameter names.
42
Function Declarations
C99 has adopted the rule that either a declaration or
a definition of a function must be present prior to
any call of the function.
Calling a function for which the compiler has not
yet seen a declaration or definition is an error.
43
Arguments
In C, arguments are passed by value: when a
function is called, each argument is evaluated and
its value assigned to the corresponding parameter.
Since the parameter contains a copy of the
argument’s value, any changes made to the
parameter during the execution of the function don’t
affect the argument.
44
Arguments
The fact that arguments are passed by value has
both advantages and disadvantages.
Since a parameter can be modified without affecting
the corresponding argument, we can use parameters
as variables within the function, reducing the
number of genuine variables needed.
45
Arguments
Consider the following function, which raises a
number x to a power n:
int power(int x, int n)
{
int i, result = 1;
return result;
}
46
Arguments
Since n is a copy of the original exponent, the
function can safely modify it, removing the need for
i:
int power(int x, int n)
{
int result = 1;
return result;
}
47
Arguments
C’s requirement that arguments be passed by value
makes it difficult to write certain kinds of functions.
Suppose that we need a function that will decompose a
double value into an integer part and a fractional part.
Since a function can’t return two numbers, we might try
passing a pair of variables to the function and having it
modify them:
void decompose(double x, long int_part,
double frac_part)
{
int_part = (long) x;
frac_part = x - int_part;
}
48
Arguments
A call of the function:
decompose(3.14159, i, d);
Unfortunately, i and d won’t be affected by the
assignments to int_part and frac_part.
Chapter 11 shows how to make decompose work
correctly.
49
Argument Conversions
C allows function calls in which the types of the
arguments don’t match the types of the parameters.
The rules governing how the arguments are
converted depend on whether or not the compiler
has seen a prototype for the function (or the
function’s full definition) prior to the call.
50
Argument Conversions
The compiler has encountered a prototype prior to
the call.
The value of each argument is implicitly converted
to the type of the corresponding parameter as if by
assignment.
Example: If an int argument is passed to a
function that was expecting a double, the
argument is converted to double automatically.
51
Argument Conversions
The compiler has not encountered a prototype
prior to the call.
The compiler performs the default argument
promotions:
float arguments are converted to double.
The integral promotions are performed, causing char
and short arguments to be converted to int. (In
C99, the integer promotions are performed.)
52
Argument Conversions
Instead, the compiler performs the default argument promotions
on x, with no effect.
Since it’s expecting an argument of type int but has been given
a double value instead, the effect of calling square is
undefined.
The problem can be fixed by casting square’s argument to the
proper type:
printf("Square: %d\n", square((int) x));
A much better solution is to provide a prototype for square
before calling it.
In C99, calling square without first providing a declaration or
definition of the function is an error.
54
Array Arguments
Example:
int sum_array(int a[], int n)
{
int i, sum = 0;
56
Array Arguments
The prototype for sum_array has the following
appearance:
int sum_array(int a[], int n);
As usual, we can omit the parameter names if we
wish:
int sum_array(int [], int);
57
Array Arguments
When sum_array is called, the first argument will be the
name of an array, and the second will be its length:
#define LEN 100
int main(void)
{
int b[LEN], total;
…
total = sum_array(b, LEN);
…
}
Notice that we don’t put brackets after an array name when
passing it to a function:
total = sum_array(b[], LEN); /*** WRONG ***/
58
Array Arguments
A function has no way to check that we’ve passed it
the correct array length.
We can exploit this fact by telling the function that
the array is smaller than it really is.
Suppose that we’ve only stored 50 numbers in the b
array, even though it can hold 100.
We can sum just the first 50 elements by writing
total = sum_array(b, 50);
59
Array Arguments
Be careful not to tell a function that an array
argument is larger than it really is:
total = sum_array(b, 150); /*** WRONG ***/
sum_array will go past the end of the array,
causing undefined behavior.
60
Array Arguments
A function is allowed to change the elements of an
array parameter, and the change is reflected in the
corresponding argument.
A function that modifies an array by storing zero
into each of its elements:
void store_zeros(int a[], int n)
{
int i;
62
Array Arguments
If a parameter is a multidimensional array, only the length
of the first dimension may be omitted.
If we revise sum_array so that a is a two-dimensional
array, we must specify the number of columns in a:
#define LEN 10
int sum_two_dimensional_array(int a[][LEN], int n)
{
int i, j, sum = 0;
for (i = 0; i < n; i++)
for (j = 0; j < LEN; j++)
sum += a[i][j];
return sum;
}
63
Array Arguments
Not being able to pass multidimensional arrays with
an arbitrary number of columns can be a nuisance.
We can often work around this difficulty by using
arrays of pointers.
C99’s variable-length array parameters provide an
even better solution.
64
practice
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
80
Answer
81
The return Statement
A non-void function must use the return
statement to specify what value it will return.
The return statement has the form
return expression ;
The expression is often just a constant or variable:
return 0;
return status;
More complex expressions are possible:
return n >= 0 ? n : 0;
82
The return Statement
If the type of the expression in a return statement
doesn’t match the function’s return type, the
expression will be implicitly converted to the return
type.
Ifa function returns an int, but the return statement
contains a double expression, the value of the
expression is converted to int.
83
The return Statement
return statements may appear in functions whose
return type is void, provided that no expression is
given:
return; /* return in a void function */
Example:
void print_int(int i)
{
if (i < 0)
return;
printf("%d", i);
}
84
The return Statement
A return statement may appear at the end of a
void function:
void print_pun(void)
{
printf("To C, or not to C: that is the question.\n");
return; /* OK, but not needed */
}
87
Practice
88
Program Termination
The value returned by main is a status code that
can be tested when the program terminates.
main should return 0 if the program terminates
normally.
To indicate abnormal termination, main should
return a value other than 0.
It’s good practice to make sure that every C
program returns a status code.
89
The exit Function
Executing a return statement in main is one way
to terminate a program.
Another is calling the exit function, which
belongs to <stdlib.h>.
The argument passed to exit has the same
meaning as main’s return value: both indicate the
program’s status at termination.
To indicate normal termination, we’d pass 0:
exit(0); /* normal termination */
90
The exit Function
Since 0 is a bit cryptic, C allows us to pass
EXIT_SUCCESS instead (the effect is the same):
exit(EXIT_SUCCESS);
Passing EXIT_FAILURE indicates abnormal termination:
exit(EXIT_FAILURE);
EXIT_SUCCESS and EXIT_FAILURE are macros
defined in <stdlib.h>.
The values of EXIT_SUCCESS and EXIT_FAILURE
are implementation-defined; typical values are 0 and 1,
respectively.
91
The exit Function
The statement
return expression;
in main is equivalent to
exit(expression);
The difference between return and exit is that
exit causes program termination regardless of
which function calls it.
The return statement causes program termination
only when it appears in the main function.
92
Practice
93
Recursion
A function is recursive if it calls itself.
The following function computes n! recursively,
using the formula n! = n × (n – 1)!:
int fact(int n)
{
if (n <= 1)
return 1;
else
return n * fact(n - 1);
}
94
Recursion
To see how recursion works, let’s trace the
execution of the statement
i = fact(4);
95
Recursion
The following recursive function computes xn, using
the formula xn = x × xn–1.
int power(int x, int n)
{
if (n == 0)
return 1;
else
return x * power(x, n - 1);
}
96
Recursion
i = power(2, 3);
97
Recursion
We can condense the power function by putting a
conditional expression in the return statement:
int power(int x, int n)
{
return n == 0 ? 1 : x * power(x, n - 1);
}
Both fact and power are careful to test a
“termination condition” as soon as they’re called.
All recursive functions need some kind of
termination condition in order to prevent infinite
recursion.
98
Practice
In 1202, Italian mathematician Leonardo Pisano (also known as Fibonacci,
meaning "son of Bonacci") pondered the question: Given optimal
conditions, how many pairs of rabbits can be produced from a single pair of
rabbits in one year? This thought experiment dictates that the female rabbits
always give birth to pairs, and each pair consists of one male and one
female.
Think about it -- two newborn rabbits are placed in a fenced-in yard and left
to, well, breed like rabbits. Rabbits can't reproduce until they are at least
one month old, so for the first month, only one pair remains. At the end of
the second month, the female gives birth, leaving two pairs of rabbits.
When month three rolls around, the original pair of rabbits produce yet
another pair of newborns while their earlier offspring grow to adulthood.
This leaves three pairs of rabbit, two of which will give birth to two more
pairs the following month.
Write a program to determine the number of rabbits after n months.
https://science.howstuffworks.com/math-concepts/fibonacci-nature.htm99
Practice
Small Pair
Rabbits
Big Pair
Rabbits
Pairs
Pairs
Pairs
Pairs
Pairs
100
Answer
101
The Flow
102
Non-Recursive Version
Please try to input 45
to test the speed of
recursive and non-
recursive versions.
What is the different?
Hint: time!
103