|
Lecture 12: Modular Programming II:
functions with input and output
|
|
In the previous lecture (aula 11) we have seen
functions that are not accepting parameters and are not returning
values.
These are simple functions. Now we are going to look at functions that
are accepting parameters and functions that are producing return
values.
Parameters to pass to functions
We can pass parameters to functions. The functions can then work with
these
parameters. Inside the function, the parameters work like normal
variables.
In C the parameters the functions expects are put after the name of the
functions inside parenthesis. For a function that doesn't have output
(or
in other words, "returns type void"):
A function with input (but without output):
void
functionname(parameter_list)
{
<local
variable
declarations>
instructions;
}
|
|
|
The variables on the parameter list are declared in the same way as
the normal variables of a program or functions, namely we have to
specify
the type of each parameter. Inside the functions we can use the
parameter
as if it were a normal variable. We can calculate with it, use it in
conditions,
and even change its value. It doesn't have to be initialized, though,
because
the initialzation comes from the calling program.
As an example, the following program will calculate and show the
square
of a variable x: Note the way the parameter r is
declared
and used.
program code
#include <stdio.h>
void write_square(float r)
{
float y;
y = r*r;
printf("The square of %f is %f",
r,
y);
}
void main()
{
float x;
x = 4;
write_square(x);
write_square(3.0);
}
|
output
The square of 4.0 is 16.0
The square of 3.0 is 9.0 |
As seen in the program above, the functions with parameters can now
be called with a variable, as in write_square(x)
or with a constant.as in write_square(3.0).
Another example, that uses two parameters:
program code
#include <stdio.h>
void write_sum(int i1, i2)
/* write the sum of i1 and i2 */
{
int j;
j = i1+i2;
printf("The sum of %d and
%d
is %d',
i1, i2, j);
}
void main()
{
int x, y;
x = 4;
y = 5;
write_sum(x, y);
write_sum(3, 4);
}
|
output
The sum of 4 and 5 is 9
The sum of 3 and 4 is 7 |
Note that we have to pass to the function the type of information that
is expected. In this case, the function expects two integers, so we
should
pass two integers (x and y).
Finally, an example with a parameter list of mixed types. Variables
to be declared in the parameter list are separated by a comma ,
program code
#include <stdio.h>
void write_N_times(float r, int n);
/* Will write n times the real r
*/
{
int i;
for (i= 1; i<=n; i++)
printf("%10.3f\n",
r);
}
void main()
{
write_N_times(3.0, 4);
}
|
output
3.000
3.000
3.000
3.000 |
Functions with output
Functions can return an output value. The type of the returning
value has to be specified at the moment of declaring the function
before
the name of the function
type
FunctionName(parameter_list)
{
<variable_list>
instructions;
}
|
|
Functions with output and with input
parameters
|
Somewhere in the instructions we have to specify a returning
value.
We do this with the reserved word return
Obviously, the value has to be of the same type as the type of the
declaration
of the function.
Note that the return instruction immediately exits from the function
and the instructions after return will not be executed.
double square(double r)
/* will return the square
of of the parameter r */
{
r = r*r;
return (r);
}
At the place where the function will be called, we can assign this
value
to a variable (of the same type as the returning value of the
function!),
for example
y = square(3.0);
use it as part of an expression, for example
y = 4.0 * square(3.0) + 1.0;
or use it in another function, for example
printf("%f", square(3.0));
A full example:
program code
/* example with parameters */
#include <stdio.h>
double square(double r)
(* will return the square of of
the
parameter r *)
{
r = r*r;
return(r);
}
void main()
{
double x, y;
x = 4.0;
y = square(x);
printf("The square of %f is
%f\n",
x, y);
printf("The square of %f is
%f\n",
3.0, square(3.0));
}
|
output
The square of 4.0 is 16.0
The square of 3.0 is 9.0 |
What is happening in the instruction y =
square(x)
is the following:
-
The value of the expression inside parenthesis is calculated. In this
case
this is simple. It is the value of x,
namely 4.0;
-
This value (4.0) is passed to the function square().
Inside the function:
-
A temporary variable with name r
is created.
-
The value passed to the function is attributed to this variable r.
Effectively an instruction r=4.0
has happened.
-
r=r*r; The new value of r
is calculated. r now has the value 16.0.
-
return(r); The value of the
expression
inside parenthesis (16) is passed back to
the calling instruction (y=square(x););
where it will be used further.
-
In this case, the value returned (square(4.0) which is 16.0) will be
attributed
to y. The instruction y=square(x);
effectively becomes y=16.0;
-
The next line (printf...) shows
the
values of the variables x and y. (Note that the value of x
has remained unchanged and is still 4.0. later, in the lecture on
"passing
by value / passing by reference" will we see that it is not necessarily
like that.)
Note that in C we don't have to use the value that is coming
back from the function. We could, for example write in our function main()
square(3.0);
This construction is very confusing and should be avoided when
possible
in structured programs; a value returned by a function should, in
principle,
be used on the receiving side.
Why?
Now the big question is "why?". Why write functions if we can do the
same
thing with normal lines of instructions? Indeed, the first languages
(for
example BASIC) didn't have the possibility to write functions and still
we could write programs to solve any problem with it. There are however
three important reasons why to use modules.
-
With modules, because they are like black boxes, we can
distribute
our programming tasks over several people or groups of people without
having
to have much communication between the people. We can tell somebody
that
we need a function that diagonalizes a matrix and we do not have to say
how we want it done. We will only specify the type of parameters to
pass
to the function.
-
For the same reason, we can easily copy parts of other programs or
libraries
for our purpose (as long as we will only use parameters and local
variables,
as we will show later). In the ideal case we will just "link" those
functions
that we will need to our program, without knowing exactly how they
work.
(Of course
with knowing what they will do and how to call them).
An interesting side effect of this is that we can distribute our
functions
in a precompiled way, so that the source code remains safe with us.
-
With functions the program becomes shorter, more efficient and more
readible
by avoiding repetitions of code and by organizing it more logical.
Quick test:
To test your knowledge of what you have learned in this lesson, click here
for an on-line test.
Peter Stallinga. Universidade do Algarve, 8
November
2002