Functions

This part should be quite simple compared to the last part. Functions are easy to use; they allow complicated programs to be parcelled up into small blocks, each of which is easier to write, read, and maintain. We have already encountered the function main and made use of printf from the standard library. Now let's look at writing and using our own functions.

c programming tutorial

Table of Contents:

The call to a function in C simply entails referencing its name with the appropriate arguments. The C compiler checks for compatibility between the arguments in the calling sequence and the definition of the function. When someone writes a function for someone to use that funciton will often be contained in a different C source file. Sometimes, however we may not have access to all the source code for all the functions. This is the case for most standard library functions like printf. However, we still know how to use printf, and the arguments it requires because those arguments are listed in the header file called stdio.h, which we have been including in our programs.

Library functions are generally not available to us in source form. Argument type checking is accomplished through the use of header files (like stdio.h) which contain all the necessary information. The most commonly used header files are

<stdio.h>  -> defining I/O routines
<string.h> -> defining string manipulation routines
<math.h>   -> defining mathematical routines
<stdlib.h> -> defining number conversion, storage allocation 
              	and similar tasks
<stdarg.h> -> defining libraries to handle routines with variable 
              	numbers of arguments
<time.h>   -> defining time-manipulation routines
To find out more about there header files and the functions they contain you can either by a book about C or visit our Other Resources. In addtion to those header files, we can of course make our own functions and header files. A function has the following layout:
return-type function-name ( argument-list-if-necessary )
{
    ...local-declarations...

    ...statements...

    return return-value;
}
If return-type is omitted, C defaults to int. The return-value must be of the declared type.

A function may simply perform a task without returning any value, in which case it has the following layout:

void function-name ( argument-list-if-necessary )
{
    ...local-declarations...

    ...statements...
}
Arguments are always passed by value in C function calls. This means that local ``copies'' of the values of the arguments are passed to the routines. Any change made to the arguments internally in the function are made only to the local copies of the arguments. In order to change (or define) an argument in the argument list, this argument must be passed as an address, thereby forcing C to change the ``real'' argument in the calling routine.

As an example, consider exchanging two numbers between variables. First let's illustrate what happen if the variables are passed by value:

#include <stdio.h>

void exchange(int a, int b);

void main()
{			/* WRONG CODE */
    int a, b;

    a = 5;
    b = 7;
    printf("From main: a = %d, b = %d\n", a, b);

    exchange(a, b);
    printf("Back in main: ");
    printf("a = %d, b = %d\n", a, b);
}

void exchange(int a, int b)
{
    int temp;

    temp = a;
    a = b;
    b = temp;
    printf(" From function exchange: ");
    printf("a = %d, b = %d\n", a, b);
}
Run this code and observe that a and b are NOT exchanged! Only the copies of the arguments are exchanged. The RIGHT way to do this is of course to use pointers. Also note that in the above code how the function exchange was prototyped. It was declared with a semicolon, and ZERO statements before the main function. This is called forward declaration. This allows the C Compiler to compile main, without not yet knowing the code for exchange. All it needs to know is what exchange arguments look like. This way we can put the exchange function after our main function. We could have easily put exchange before main and gotten rid of the declaration. The next code segment will fix exchange to use pointers, and move exchange above main to eliminate the need for the forward declaration.
#include <stdio.h>

void exchange ( int *a, int *b )
{
    int temp;

    temp = *a;
    *a = *b;
    *b = temp;
    printf(" From function exchange: ");
    printf("a = %d, b = %d\n", *a, *b);
}

void main()
{			/* RIGHT CODE */
    int a, b;

    a = 5;
    b = 7;
    printf("From main: a = %d, b = %d\n", a, b);

    exchange(&a, &b);
    printf("Back in main: ");
    printf("a = %d, b = %d\n", a, b);
}
The rule of thumb here is that
  • You use regular variables if the function does not change the values of those arguments
  • You MUST use pointers if the function changes the values of those arguments
Lastly, I noticed that none of the examples with functions have returned values. So this quick example will illustrate returning values with functions. Functions may not seem that useful yet, but as your program grows you will no longer want to have all your code in main. So you will want to split it up into functions. Below we have a function that adds the two arguments it receives and returns their value. Not to complex, but does its job well. Take a look:
#include <stdio.h>

int addints(int a, int b)
{
	return a+b;
}

void main()
{
	int a;
	int b;
	int sum;
	a = 6;
	b = 7;
	sum = addints(a, b);
	printf("The sum of a and b is : %d\n", sum);
}

Function

Now that we have covered Functions, we can move onto I/O Capabilities.