Chapter 7 : Functions

Chapter 7 : Functions

Contents

7.1. Motivation: the need for functions.

The basic property of functions is that they enable us to break a program down into a number of smaller units. There are several different reasons why programs should be broken down in this way. Different users attach different importance to these reasons; some of the considerations below may be considered irrelevant by some practitioners.

If a solution has been created for a particular sub-problem (an implementation of the solution involving means for storing the related data items, and the means of accessing them in an appropriate way) may be useful in more than one problem. An example is the sorting of a number of items into a particular order; sorting is a basic operation which is needed at many points in many computer problems.

Units which solve frequently occurring sub-problems can therefore be re-used in appropriate places in a variety of larger problems.

  • (i) They may be used in order to save effort in re-solving that particular problem, and in re-programming the solution.
  • (ii) They may be used in order to produce better quality systems, on the assumption that the solution being re-used was written and tested (by someone else) to a high quality standard when it was originally written.

    In this C course we teach just the programming techniques needed for producing useful re-usable code; we are not emphasising just WHY you may choose to break down your problem into these particular units. We need what are called "functions" and "structures" in C; on other courses you may learn techniques for using functions as the basis of a particular methodology for the design of programs.

    In this section of the course, we teach the techniques for implementing functions. For those who have used other programming languages, the concept of a "function" in C and C++ corresponds to a "procedure" or "function" elsewhere.

    7.2. Functions with no parameters

    7.2.1. A simple example

    First we look at a simple example.

    The parentheses following the function identifier in the function calls in the main program indicate that "dothis" and "dothat" are identifiers representing functions to be executed. The functions may, of course, be called as many times as you wish within the program.

    7.2.2. Declaration versus definition

    For each function the compiler needs two distinct items of information.

  • (i) A declaration, to define (to tell the compiler) what a call of the function will look like, and the identifier to be used.
  • (ii) A definition, to define exactly what is to be done (the actions to be executed) whenever the function is called.

    This should be compared with the declarations of variables, where again there are two distinct aspects to any declaration, one to inform the compiler about the type and identifier for compile-time, and one to arrange to claim space at run-time.

    In the above simple example, declaration and definition are combined.

    These two parts (declaration and definition) of a function can be separated in C as in the example

    The first declaration "void dothis();" is to warn the compiler what to expect as calls of the function, for example by introducing the identifier to be used. The compiler will not now be surprised to see the calls of the function when it encounters them in the main program. Although the compiler knows that dothis is the identifier of a function, not of a variable, it still requires parentheses after the identifier in function calls in the program.

    The later definition "void dothis() { ... }" with executable statements within curly braces will define between those curly braces the code to be executed whenever the function is called. It will involve executable C code.

    7.2.3. More examples of simple functions

    Variables which need to be accessed within both the function(s) and the main program must now be declared before both.

    Our rates of pay exercise earlier becomes

    To compute the area of a circle of given radius, a program might be

    To calculate the volume of a cylinder using the formulae

    we would use functions as in the definition and write

    7.2.4. Local variables

    The functions or main program can also have variables declared within them, at the start of the code. These are called local variables and can be referred to only from within that function or program. The Halberstam loop eaxmple earlier might be written

    The variable "counter" can be referred to only from within the halberstam function.

    7.2.5. Local identifiers

    If a local identifier is the same as a global one,

  • references to that identifier from within the function in which it is declared refer to the local variable;
  • references to that identifier from elsewhere refer to the gloablly declared variable.

    Generally, and identifier is first searched for as a local variable; if no local declaration of that identifier is found, a global declaration is used.

    Function identifiers themselves count a global identifiers. They cannot also be used as global variable identifiers. If they are used as a local variable identifier in a second function, then that function cannot be called from within that second function.

    7.2.6. Warning

    The use of global variables as shown above is generally not a good way to develope functions. See later!

    7.3. Functions with parameters

    The above examples were very simplistic. In more significant examples, we will wish to pass certain values into a function when it is invoked, and may wish to obtain results directly from the call. For example, if we are performing mathematics and require a "square root" function, we will wish

  • to pass to it the value of the number whose square root require, so that a call looks like

    or

  • and instead of putting the result into a global variable, we would like to write

    or

    and use the result directly.

    7.4. The function declaration

    The function declaration now needs to inform the compiler of

  • 1 Some functions will return a result, some will not. Functions to compute the square root of a number will return a numeric result for use in the program requesting the square root. The examples shown earlier, or a function to print output will not return a numeric value.
  • 2 The identifier of a function follows exactly the same rules as identifiers for variables. It must not clash with the special words of the language, or with global variable identifiers.
  • 3 We will probably need to pass values into functions when we call them. With the "square root" example above, each time we call it we must give the value of the number whose square root we require. The number which we pass to it is sometimes called a parameter and sometimes an argument. In C the number and types of the parameters are specified in the function definition, not its declaration. In C++, they are specified in the declaration.

    Examples of function declarations

    A function to compute the square root of a given value.

    A function to compute the larger of two integer values.

    A function to compute the volume of a cylinder.

    A function to print an error message involving an integer value.

    Examples of function calls

    The above functions would be called from elsewhere (perhaps from the main program, perhaps from another function) by statements such as the following.

    Square root would take a "double" parameter and return a double result.

    We would normally expect to use the returned result as a value.

    Maximum of two integers

    Volume of a cylinder

    Reporting an error

    The syntax of a function declaration

    A function declaration consists of

    Do not forget the semi-colon!

    The returned type may be any ordinary C type such as int , float and so on, or the type void if no value is being returned to the main program.

    In some older programming languages, the word "function" was used only when a result was to be delivered; the word "procedure" or "function" was used is there was no result to deliver. In C and C++ all such objects are called functions.

    7.4.1. The function definition

    The function definition needs to inform the compiler of the actions to be taken whenever the function is called. In the declaration we described only the type of the result. The compiler needs parameter type information to enable it to handle the parameters correctly wherever the function is called. In order to describe the actions to be taken when the function is called, we need to identify each of the parameters, so that we can refer to them and use them from within the code which forms the body of the function.

    The "max" function

    We want a function to deliver the larger of the values of the two values given as parameters.

    The "return" keyword acts both to specify the particular value to be returned by the call of the function, and to cause dynamic exit from the function.

    If the function returns type void we leave the function using the statement

    with no value specified; the function will leave anyway at the end of its code. If the function returns a non-void type, it must always use "return ..." to exit, it cannot just leave at the end of the code, and the return must be followed by a value which the compiler can force into the required type.

    Notice that we do not need an "else" statement in this example because of the dynamic exit caused by the "return i;" statement.

    The cylinder volume function

    We will declare and define two functions for this.

    The Halberstam function

    The declaration would be

    and the definition

    The "error" function

    We want a function to print an error message and then abandon the program.

    In this example, the "exit" causes the whole program to terminate; if we merely wished to report the error and continue the program, we would use a

    statement with no value given. If the function has its delivered type declared as void its code does not return values, and the function is left by using

    7.5. The exit function

    The exit function causes the completer program to terminate. Convention with the exit function is that

    The UNIX shell can use the value returned by a terminating program to determined whether it terminated successfully or not.

    However, with the Ceilidh system, all programs must use

    since any other exit assumes that some accidental error has occurred.

    7.6. More examples

    The sqrt function

    We need to calculate the square root of the given parameter value, and return it. Please forgive the crude method!

    The declaration would be

    A definition consists of

    7.7. Returned types

    The compiler needs to know the type of the value to be returned by the function so that it can be treated correctly in the call of the function. If no value is to be returned (cf "error" or "dothis" above) then the return type is given as "void".

    The particular value to be returned is specified by the line

    With a void function write simply

    The compiler will do type conversions where necessary. If the function declaration says that it returns a float and the function includes "return 1;" then the compiler knows to sort this out.

    7.8. Parameter types

    The parameter type sequence in the definition and the calls must agree. The compiler will make the necessary type conversions to the delivered result in a call of the function.

    The parameters in the function definition are called the formal parameters. The parameter values supplied in calls of the function are called actual parameters.

    7.9. Program structure

    The main program and function definitions can appear in any order in your program. It is normally clearest to read and understand if the main program appears before the function definitions. Reading the main program gives an overview of the sequence of operations.

    Function declarations MUST appear before the function is called. They are usually put together before the main program.

    7.10. Local variables

    We can declare local variables at the start of our function code if we require additional variables for computations within the function. The declarations appear after the opening curly brace, just as they do in the main program.

    If a local identifier clashes with a global constant, or with the name of another function, then that global constant or other function becomes inaccessible within this function. The local object will be referred to by the identifier.

    7.11. Parameters called by value

    When a function is called, the values of the (actual) parameters at the point where the function is called are calculated, and passed to the function definition for execution. Within the function, the parameters act like variables, initialised to the value of the corresponding actual parameter at the call, and their values can be changed by ordinary assignment.

    Thus if a function definition is

    the identifier "number" can be considered as a local variable to the function. Changing its value inside the function as shown in the above example has no effect on the outside world.

    If the call of the function is

    the value of the variable counter in the calling program will not be changed. We could also call the function by

    which would pass the value 23 to the formal parameter. This way of passing parameters is referred to as "passing by value".

    7.12. Jargon reminder

    The parameters as specified at the start of the function definition are referred to as "formal parameters".

    The parameters substituted in any particular call of the function are referred to as "actual parameters".

    7.13. A complete example

    The complete program with function declaration, main program and function definition will look roughly as follows. We use an example with the Halberstam function.

    7.14. Examples

    In general functions will perform operations on data, and not perform their own input output except

  • (i) if the main purpose of the function is for input/output; or
  • (ii) to print error messages.

    7.14.1. Circle radii and areas

    We show here two functions taking float parameters, and giving float results. The first takes a radius length, and delivers the area of a circle of that radius. The second takes an area, and delivers the radius of a circle with that area.

    Calls of these functions might be

    7.14.2. Summation

    This function sums the series

    for a given value of "x". We keep adding terms until we reach a term whose value is less than 0.001.

    Calls of this function might be

    7.14.3. The OK function

    We require a function to print out a given message as a question, and return TRUE if the user replies "y" and FALSE otherwise. The type of a message (a string of text contained within double quotes) is "char *" (the reasons for this will appear later), and the definition of the function might be:

    In a real situation, the function body might repeat the question until the given answer is "y" or "n". In the above example, we respond with TRUE if the answer is "y" and FALSE otherwise.

    Note that we do not need to say

    We can return the comparison result directly.

    Calls of this function might be:

    Observe the subtlety of the last example. The program first asks

    and, because the "&&" operator is lazy, only if the reply to the first question is "y" asks for confirmation

    If the reply to the first question is "n", the second question is not asked.

    7.15. Arrays as parameters

    7.16. Program modularity

    7.17. Mathematical functions

    A number of standard mathematical functions are available. For details try

    or

    Copyright Eric Foxley 1996


    Notes converted from troff to HTML by an Eric Foxley shell script, email errors to me!