<br>The heart of effective problem solving is problem decomposition. Taking a problem and breaking it into small, manageable pieces is critical to writing large programs.
<br>In C, the function construct is used to implement this í Þtop-downí µ method of programming. A program consists of one or more files, with each file containing zero or more functions, one of them being a main() function.
<br>Functions are defined as individual objects that cannot be nested. Program execution begins with main(), which can call other functions, including library functions such as printf() and sqrt().
<br>Functions operate with program variables, and which of these variable at a particular place in a function is determined by scope rules. In this chapter we discuss function definition, function declaration, scope rules, storage classes, and recursion.
<br>The C code that describes what a function does is called the function definition. It must not be confused with the function declaration. A function definition has the following general form:
<br>type function_name( parameter list ) { declaration statements }
<br>
<br>Everything before the first brace comprises the header of the function definition, and everything between the braces comprises the body of the function definition. The parameter list is a comma-separated list of declarations. An example of a function definition is
<br>The parameter list consists of the declaration int n. This tells the compiler that the function takes a single argument of type int. An expression such as factorial(7) causes the function to be invoked, or called. The effect is to execute the code that comprises the function definition, with n having the value 7. Thus, functions act as useful abbreviating schemes. Here is another example of a function definition:
<br>The first void tells the compiler that this function returns no value; the second void tells the compiler that this function takes no arguments. The expression
<br>A function definition starts with the type of the function. If no value is returned, then the type is void. If the type is something other than void, then the value returned by the function will be converted, if necessary, to this type.
<br>The name of the function is followed by a parenthesized list of parameter declarations. The parameters act as placeholders for values that are passed when the function is invoked. Sometimes, to emphasize their role as placeholders, these parameters are called the formal parameters of the function. The function body is a block, or compound statement, and it too may contain declarations. Some examples of function definitions are
<br>void nothing(void) {} /* this function does nothing */
<br>
<br>double twice(double x)
<br>{
<br>return (2.0 * x);
<br>}
<br>
<br>
<br>int all_add(int a, int b)
<br>{
<br>int c;
<br>....
<br>
<br>
<br>return (a + b + c);
<br>}
<br>
<br>If a function definition does not specify the function type, then it is int by default. For example, the last function definition could be given by
<br>Any variables declared in the body of a function are said to be í Þlocalí µ to that function. Other variables may be declared external to the function. These are called í Þglobalí µ variables. An example is
<br>int a = 33; /* a is externel and initialized to 33 */
<br>int main(void)
<br>{
<br>int b = 77;
<br>
<br>printf(í Þa = %d\ní µ, a);
<br>printf(í Þb = %d\ní µ, b);
<br>return 0;
<br>}
<br>
<br>In traditional C, the function definition has a different syntax. The declarations of the variables in the parameter list occur after parameter list itself and just before the first brace. An example is
<br>The order in which the parameters are declared is immaterial. If there are no parameters, then a pair of empty parentheses is used. ANSI C compiler will accept this traditional syntax as well as the newer syntax. Thus, traditional code can still be compiled by an ANSI C compiler.
<br>There are several important reasons to write programs as collections of many small functions. It is simpler to correctly write a small function to do one job. Both the writing and debugging are made easier. It is also easier to maintain or modify such a program.
<br>One can readily change just the set of functions that need to be rewritten, expecting the rest of the code to work correctly. Also, small functions tend to be self-documenting and highly readable. A useful heuristic for writing good programs is to write each function so that its code fits on a single page.
<br>The expression being returned can be enclosed in parentheses, but this is not required. When a return statement is encountered, execution of the function is terminated and control is passed back to the calling environment.
<br>If the return statement contains an expression, then the value of the expression is passed back to the calling environment as well. Moreover, this value will be converted, if necessary, to the type of the function as specified in the function definition.
<br>There can be zero or more return statements in a function. If there is no retrun statement, then control is passed back to the calling environment when the closing brace of the body is encountered. This is called í Þfalling off the end.í µ The following function definition illustrates how two return statements might be used:
<br>Functions should be declared before they are used. ANSI C provides for a new function declaration syntax called the function prototype. A function prototype tells the compiler the number and type of arguments that are to be passed to the function and the type of the value that is to be returned by the function. An example is
<br>This tells the compiler that sqrt() is a function that takes a single argument of type double and returns a double. The general form of a function prototype is
<br>The parameter type list is typically a comma-separated list of types. Identifiers are optional; they do not affect the prototype. For example, the function prototype
<br>void f(char c, int i); is equivalent to void f(char, int);
<br>
<br>The identifiers such as c and i that occur in parameter type lists in function prototypes are not used by the compiler. Their purpose is to provide documentation to the programmer and other readers of the code. The keyword void is used if a function takes no arguments.
<br>Also, the keyword void is used if no value is returned by the function. If a function takes a variable number of arguments, then the ellipses(í ƒ) are used. See, for example, the function prototype for printf() in the standard header file stdio.h.
<br>Function prototypes allow the compiler to check the code more thoroughly. Also, values passed to functions are properly coerced, if possible. For example, if the function prototype for sqrt() has been specified, then the function call sqrt(4) will yield the correct value. Because the compiler knows that sqrt() takes a double, the int value 4 will be promoted to a double and the correct value will be returned. (See exercise 5, on page 236, for further discussion.)
<br>Even though ANSI C compilers will accept this style, function prototypes are preferred. With this declaration, the function call sqrt(4) will not yield the correct value.(See exercise 5, on page 236.)
<br>In C++, function prototypes are required, and the use of void in the parameter type list in both function prototypes and function definitions is optional. Thus, for example, in C++
<br>means that f() takes an unknown number of arguments. In traditional C, void is not a keyword. Thus, it cannot be used in a parameter list in a function declaration or function definition.
<br>In this section, we give an example of a program that is written using a number of functions. For simplicity, we will write all the functions one after another in one file. The purpose of the program is to print a table of powers.
<br>printf(í Þ\n::::: A TABLE OF POWERS :::::\n\ní µ);
<br>}
<br>
<br>void prn_tbl_of_powers(int n)
<br>{
<br>int i, j;
<br>
<br>for (i = 1; i<= n; ++i) {
<br>for (j =1; i <= n; ++j)
<br>if (j == 1)
<br>printf(í Þ%ldí µ, power(i, j));
<br>else
<br>printf(í Þ%9ldí µ, power(i, j));
<br>putchar(í Ú\ní Û);
<br>}
<br>}
<br>
<br>long power(int m. int n)
<br>{
<br>int i;
<br>long product = 1;
<br>
<br>for (i = 1; i <= n; ++i)
<br>product *= m;
<br>return product;
<br>}
<br>
<br>Here is the output of the program:
<br>
<br>::::: A TABLE OF POWERS :::::
<br>1 1 1 1 1 1 1
<br>2 4 8 16 32 64 128
<br>3 9 27 81 243 729 2187
<br>í ƒ..
<br>
<br>Note that the first column consists of integers raised to the first power, the second column consists of integers raised to the second power, and so forth. In our program we have put the function prototypes near the top of the file. This makes them visible throughout the rest of the file. We used the type long so that the program will produce the same output whether the machine has 2- or 4-byte words. Note that the function power() computes the quantity m(n), which is m raised to the nth power.
<br>Our program illustrates in a very simple way the idea of top-down design. The programmer thinks of the tasks to be performed and codes each task as a function. If a particular task is complicated, then that task, in turn, can be subdivided into other tasks, each coded as a function. An additional benefit of this is that the program as a whole becomes more readable and self-documenting.