Programmer Defined Functions
Function Prototypes
Prototypes are function headers without bodies (similar to method declarations in Java interfaces). They let the compiler know a function exists so we can use it without the definition having yet appeared. They serve as code specifications as well, so the compiler knows what a legal call looks like and another programmer knows how that function should be defined.
- format is
return_type fun_name(arg_type_1, arg_type_2, etc);
example isint randInt(int, int)
(notice no variable names needed) - Put prototypes after
#include
s, beforemain
- (or put them in a seperate file; this is discussed below)
Function Definitions
The general format is
return_type fun_name(arg_type_1 var_1, arg_type_2 var_1, etc)
, for example int randInt(int a, int b).
Where can they go?
- The actual funcion can go anywhere if there is a prototype declared; otherwise it must appear before any call to it
- Function definitions must not be embedded within each other
Return type return_type
- Use
void
forreturn_type
if no return value (return statement optional) - Default return type is
int
if none specified which is usually a bad idea; explicitly declare itint
if its an int
Parameter list format:
- include type and local name of each variable, comma separated
-
int
is default type if none listed (again bad idea); parameter list(float x, y)
means first parameter is afloat
and second parameter is anint
- Function definitions are all global; they cannot be nested inside other function definitions
Function call format
- All arguments are passed by value (copied)
- Array contents are implicitly passed by reference when the entire array name (memory address) is given as a parameter; see the Carrays Notes for more details
Program Structure and Compilation
Generally we want to separate function declarations (prototypes) from their definitions into two related files.
- C header files (
*.h
) hold function prototypes (and type declarations) - C code files (
*.c
) contain global variables (to be avoided) and function definitions
Preprocessor directives
The#include
directive is used for both language libraries and programmer defined function header files. See also the next section on Compilation for other pre-processor options.
-
#include <clib.h>
-- in effect insert the specified C library fileclib.h
contents here -
#include "header.h"
-- in effect insert the programmer defined fileheader.h
contents here -
#define THING value
-THING
is a macro abreviation forvalue
Compilation
- Need to include all
.c
files to make the executable as ingccc my_funcs.c my_main.c
creates executablea.out
- Here is a standard hack to prevent multiple inclusion of header files
#ifndef MY_FUNCS_H
// MYFUNCS_H is a flag for the my_funcs.h header file#define MY_FUNCS_H
// define it if its undefined, and load it// function prototypes go here
#endif
// if the flag was previously defined, no headers loaded
Object files
- Separation into separate
*.c
and*.h
files supports separate compilation gcc -c my_funcs.c
(note the-c
option) produces object filemy_funcs.o
- Can then compile a main program that only has to
#include my_funcs.h
file,my_funcs.c
doesn't need to be recompiled:gcc -c my_main.c
creates object filemy_main.o
- Then to create a runnable program, feed all the
.o
files togcc
as ingcc my_main.o my_funcs.o
to create executablea.out
- If you leave out any
.o
file you will get a link error usually labelled as "undefined reference to functionName"
make and Makefiles
We use a tool calledmake
along with a special type of file called a Makefile
to keep track of all the parts of a program and define their dependences and rules for separate compilation and linking.
make
automatically figures out for you which files need to be recompiled and does only that- Saves you from bad behavior where you forgot to recompile a code file that changed
The Unix make
program does the making.
- For the simplest use of
make
, the dependencies and directives are in a fileMakefile
and you typemake
at the command line to read in that file and compile what is needed - To see what will get executed based on a
Makefile
in the current directory, typemake
to build an executable, then use the Unixtouch
shell command to "touch" a file, i.e. update the last written date and foolmake
into thinking the file was edited. Here is an example session. Notice how only the changed files, and anything dependent on it, are recompiled/relinked.
% make gcc -std=c99 -pedantic -Wall -Wextra -O -g -c -o my_main.o my_main.c gcc -std=c99 -pedantic -Wall -Wextra -O -g -c -o my_funcs.o my_funcs.c gcc my_main.o my_funcs.o -o program % make make: `my_main' is up to date. % touch my_main.c % make gcc -std=c99 -pedantic -Wall -Wextra -O -g -c -o my_main.o my_main.c gcc my_main.o my_funcs.o -o program %
Library Functions
Below are some commonly used function libraries in C. Also see Notes on I/O library (stdio.h), characters (ctype.h) and string (string.h).Assert
Assertions are particularly useful in functions to check the validity of parameter values. When an assertion fails, the program will stop running. If it passes (results in true), then the program keeps going.-
#include <assert.h>
-
assert(boolean expr);
Math
The math library has many useful functions. These generally havedouble
arguments and return double
values.
- Use
#include <math.h>
- Need to compile with
gcc -lm
option - Some of the most common are
sqrt(x)
,pow(x,y)
,exp(x)
,log(x)
,ceil(x)
,floor(x)
,sin(x)
.
Random numbers
The built-in library is very limited, but we can manipulate the results with some common arithmetic expressions to generate different types and ranges of values. Below are a few examples.-
rand()
- generates integer between 0 andRAND_MAX
(>= short int) -
#include <stdlib.h>
-
n = a + rand() % b;
to get random int between a and a+b-1, assuming allint
variables -
n = a + rand() % (b-a+1);
to get random int between a & b inclusive -
float x = (float) (rand() / RAND_MAX);
to get random float between 0 and 1
- If you don't seed it the numbers will be the same each program run
-
#include <time.h>
and use thetime()
function to seed to the current time of day (in milliseconds)</ul> - Seed with
srand
functionsrand(time(NULL))
; comment this out while debugging to make your results repeatable