05A All about Functions Part 1

The discussion this past week has been wonderful, with fun digressions, good
homeworks, a great long tangent on binary, and a nice coding style howto by
Jacinta Richardson. If you haven't had time to follow along, maybe take a few
minutes to skim the discussion because there is a lot of good stuff.

Today we are going to learn about functions. Functions are fundamental to all
programming, so we need to know all about them. Printf and scanf are
functions. They are also called routines. Programming languages are cram-full
of built-in functions, and of course when we write our own programs we write
our own functions. main is a function, a special required function in every C
program. Remember our initial discussions about the different ways to declare
main:

main ()
int main ()
void main (void)
int main (void)

'main ()' is the wrong way to declare main. Don't use it. I know, I used it in
our first lesson. Under the C89 standard, 'main ()' is acceptable. But not
under C99, which says we must use 'int main (void)' or 'int main ( int argc,
char *argv[] )'.
Please refer to C
Programming Resource Center
to read the C99 standard and get other useful
information. Section 5.1.2.2.1 Program startup says:

"The function called at startup is named main. The implementation declares no
prototype for this function. It shall be defined with a return type of int and
with no parameters:

int main (void)

or with two parameters (referred to here as argc and argv, though any names
may be used, as they are local to the function in which they are declared):

int main (int argc, char *argv[]) "

A common misconception is that the empty parentheses mean zero arguments. But
it really means an unknown number of arguments, which is quite different. So
what arguments are we talking about? This means command-line options for our
programs. This is jumping ahead a little, but we might as well get this sorted
now. Because someday we will write programs that take command-line arguments,
so instead of plain old commands like

$ books

we'll have fancier programs with command options:

$ books --cooloption1 --cooloption2

So the short story is I'm going to follow the C99 standard. And to think that
when I started this I expected I wouldn't have to pay attention to the
different standards :)

void main(void) is against all C standards. You'll see it in howto books. They
are wrong. Don't use it.

======= Function Prototypes and Definitions ========

Now let's talk about function prototypes and definitions. Function prototypes
describe your functions; they tell the compiler basic information about your
function such as its return type, name, parameters, and data types. Function
definitions are your actual functions. This simple example shows what this all
looks like:

=======================================

// timex, a simple multiplication
// program demonstrating function
// prototypes and definitions

#include

int timex ( int, int );

int main(void)
{
int a = 0;
int b = 0;

printf( "Please type in two numbers no larger than 100, separated by a space
or line break, to multiply together: " );
scanf( "%d", &a );
scanf( "%d", &b );
printf( "The product of your two numbers is %d\n", timex( a, b ) );
return 0;
}

int timex (int a, int b)
{
return a * b;
}

==========================================

Compile this program with the --Wall option, which turns on all warnings so
the compiler will tell you about all errors, even non-fatal errors. As this
example shows, I send my executables to my ~/bin directory:

$ gcc -Wall -o ~/bin/timex timex.c

Now run the new program:

$ timex
Please type in two numbers no larger than 100, separated by a space or line
break, to multiply together: 55
44
The product of your two numbers is 2420

'int timex ( int, int );' is the function prototype. If you comment this out
it will compile with a warning:

$ gcc -Wall -o ~/bin/timex2 timex2.c
timex2.c: In function ‘main’:
timex2.c:17:3: warning: implicit declaration of function ‘timex’ [-Wimplicit-
function-declaration]

man gcc lists all the warnings flags that Wall supports. You can probably guess
what Wimplicit-function-declaration means, and man gcc tells you:

"Give a warning whenever a function is used before being declared."

You can include variable names in your function prototype:

int timex ( int a, int b );

But leaving them out lets you rename your variables as you need to. This is
the function definition:

int timex (int a, int b)
{
return a * b;
}

An advantage of always using a function prototype is your compiler will find
errors such as wrong data types or wrong number of variables. Try changing the
function prototype to the wrong number of variables:

int timex ( int, int, int );

This should generate a flurry of error messages:

$ gcc -Wall -o ~/bin/timex2 timex2.c
timex2.c: In function ‘main’:
timex2.c:17:3: error: too few arguments to function ‘timex’
timex2.c:7:5: note: declared here
timex2.c: At top level:
timex2.c:21:5: error: conflicting types for ‘timex’
timex2.c:7:5: note: previous declaration of ‘timex’ was here

Or try the wrong data type:

char timex ( int, int );

$ gcc -Wall -o ~/bin/timex2 timex2.c
timex2.c:21:5: error: conflicting types for ‘timex’
timex2.c:7:6: note: previous declaration of ‘timex’ was here

That's all for now-- stay tuned for part 2 of this week's lesson!

Homework: Download a copy of the C99 standard for yourself, and read a little
bit of it every day. If you find something interesting, please share it on this
list.
C Programming Resource
Center

Perhaps some our ace gurus could discuss the best places to put your function
prototypes. This is not a big deal in our tiny example programs, but in large
complex programs what are some best practices?