Section Navigation

Functions

It is very common that certain tasks occurs multiple times within a code, such as sorting an array, converting strings to lower case characters, read and process a file from disk, to name a few. It would be highly inefficient, hard to maintain and difficult to read, when all the tasks have to be completely written out.

Instead C allows to combine a subsection of code to a single unit and then calls this section, from other places in the code. These are functions. One function, which is mandatory in all programs is main, the starting point of execution. All other functions are optional and can be defined in the same source text file, in other source text files, or already compiled as a library functions.

A functions is defined by its name, the data type of a returned value, a list of arguments and the actual code in the function body. A special data type is void, which indicates that no data is returned. Arguments are like variables, but their values are defined by the code, which calls the functions. As a simple example we defined a function, which returns twice the value of a supplied integer argument:

int twice(int a)
{
return 2*a;
}

The first word in a function definition is the data type of the returned value. The actual instruction to return a value and leave the function is given by the command return, followed by a right-hand side expression for the value. If the function is of type void, the semi-colon must directly follow the return-keyword.

The list of arguments is given in the round brackets, separated by commas. If no argument is required the bracket is empty. In our example the code calls the function with a value, which is stored in the content of variable a, so that the code in the function body can access its value.

The function can be called anywhere else in the program, even recursives calls are allowed (also beware of non-terminated recursion, which is one of the easiest method to crash a program). In our example the function is called in main.

main()
{
int a,b;

b=5;
a=twice(b);
}

Note that the variable a appears in both functions but they are not the same. Nor are b in main and a in twice the same. Arguments of basic data types are always transfered by value, meaning that the value of the calling argument (here b in main) is copied to a new variable (here a in twice) before it can be used in any expression.

A called function can alter the content of variables of the calling function, when the arguments are passed by reference, using pointers. This example is also an example for a void return type:

void absolute(int *a)
{
if (a < 0){
a=-a;
}
return;
}

main()
{
int b;

b=-5;
absolute(&b);
}

Because the function absolute is of type void, it can be called without an assignment operation. Although this examples works, it is a bad programming style, because it alters the content of variable directly and less transparent to the reader. Passing the argument by value and than redefining in main by an assignment operation would be better.

In the examples the functions were defined, before there were called. When the compiler process the source text it creates a table of all used function with its return type and the required arguments. Whenever a function is called the compiler looks in the table, where the specifications are fulfilled (the right number of arguments, the right type of arguments including the possibility of promotion, and the rcompability of return type and left-hand side data type). If there is incompabilities the compiler with stop report an error. If also stops, when the compiler cannot find an entry for the the function to be called.

If the definition of a function is behind a function, where it is called, or even in a different file, the compiler has to be informed that such a function exists. This is done by function declaration, where only the function name, the return type and the argument list are defined. It is similar to the function definition but without the function body and the curly brackets, but a semi-colon instead. It is a good programming practice to put all functions declaration in an include file, which have typically the extensions ".h". By declaring a function the compiler fills it into its table of all used functions. The actual function definition can be then anywhere. This is also required for already compiled functions. Here the compiler needs to be informed about the format of the function. This is done, again, with ".h" or include files. To include an ".h" file the compiler macro #include is used.

The benefit of distributing functions over multiple file is to reuse themm for other programs. Over time a personal library can be build and programing is significantly speed up by just including already written function to the code. Here is an example, using multiple files.

The "square.h" file for a function declaration to return the square of a double precision floating point number

double square(double a);

The actual function definition in file "square.c":

double square(double a)
{
return a*a;
}

and the main file "main.c":

#include "square.h"

main()
{
double a,b;

a=1.234;
b=square(a);
}

To compile the program, both files "main.c" and "square.c" has to be compiled and than linked together. See the main page for more information.

Many functions from the C libraries require also to include specific ".h" files to compile correctly. E.g. for malloc and free it is the file "stdlib.h" in the include-directory of the C installation. If and which include files are required can be found by typing man "function name" at the command prompt, when logged onto a Linux/Unix machine.

previous:next