7.2. Function Declarations
By declaring a function before using it, you inform the compiler of its type: in other words, a declaration describes a function's interface. A declaration must indicate at least the type of the function's return value, as the following example illustrates:
int rename( );
This line declares rename( ) as a function that returns a value with type int. Because function names are external identifiers by default, that declaration is equivalent to this one:
extern int rename( );
As it stands, this declaration does not include any information about the number and the types of the function's parameters. As a result, the compiler cannot test whether a given call to this function is correct. If you call the function with arguments that are different in number or type from the parameters in its definition, the result will be a critical runtime error. To prevent such errors, you should always declare a function's parameters as well. In other words, your declaration should be a function prototype. The prototype of the standard library function rename( ), for example, which changes the name of a file, is as follows:
int rename( const char *oldname, const char *newname );
This function takes two arguments with type pointer to const char. In other words, the function uses the pointers only to read char objects. The arguments may thus be string literals.
The identifiers of the parameters in a prototype declaration are optional. If you include the names, their scope ends with the prototype itself. Because they have no meaning to the compiler, they are practically no more than comments telling programmers what each parameter's purpose is. In the prototype declaration of rename( ), for example, the parameter names oldname and newname in indicate that the old filename goes first and the new filename second in your rename( ) function calls. To the compiler, the prototype declaration would have exactly the same meaning without the parameter names:
int rename( const char *, const char * );
The prototypes of the standard library functions are contained in the standard header files. If you want to call the rename( ) function in your program, you can declare it by including the file stdio.h in your source code. Usually you will place the prototypes of functions you define yourself in a header file as well, so that you can use them in any source file simply by adding the appropriate include directive.
7.2.1. Declaring Optional Parameters
C allows you to define functions so that you can call them with a variable number of arguments (for more information on writing such functions, see the section "Variable Numbers of Arguments," later in this chapter). The best-known example of such a function is printf( ), which has the following prototype:
int printf( const char *format, ... );
As this example shows, the list of parameters types ends with an ellipsis (...) after the last comma. The ellipsis represents optional arguments. The first argument in a printf function call must be a pointer to char. This argument may be followed by others. The prototype contains no information about what number or types of optional arguments the function expects.
7.2.2. Declaring Variable-Length Array Parameters
When you declare a function parameter as a variable-length array elsewhere than in the head of the function definition, you can use the asterisk character (*) to represent the array length specification. If you specify the array length using a nonconstant integer expression, the compiler will treat it the same as an asterisk. For example, all of the following declarations are permissible prototypes for the maximum( ) function defined in Example 7-5:
double maximum( int nrows, int ncols, double matrix[nrows][ncols] ); double maximum( int nrows, int ncols, double matrix[ ][ncols] ); double maximum( int nrows, int ncols, double matrix[*][*] ); double maximum( int nrows, int ncols, double matrix[ ][*] );