As we have previously stated functions are essentially just groups of statements that are to be executed as a unit in a given order and that can be referenced by a unique name. The only way to execute these statements is by invoking them or calling them using the function’s name.
Traditional program design methodology typically involves a top-down or structured approach to developing software solutions. The main task is first divided into a number simpler sub-tasks. If these sub-tasks are still too complex they are subdivided further into simpler sub-tasks, and so on until the sub-tasks become simple enough to be programmed easily.
Functions are the highest level of the building blocks given to us in C and correspond to the sub-tasks or logical units referred to above. The identification of functions in program design is an important step and will in general be a continuous process subject to modification as more becomes known about the programming problem in progress.
We have already seen many C functions such as main( ) , printf(), etc. the common trait they share being the braces that indicate they are C functions.
Syntax : return_type function_name ( parameter_list ) { body of function ; }
The above is termed the function definition in C parlance.
Many functions will produce a result or return some information to the point at which it is called. These functions specify the type of this quantity via the return_type section of the function definition. If the return type is void it indicates the function returns nothing.
The function_name may be any valid C identifier and must be unique in a particular program.
If a function requires information from the point in the program from which it is called this may be passed to it by means of the parameter_list. The parameter list must identify the names and types of all of the parameters to the function individually. If the function takes no parameters the braces can be left empty or use the keyword void to indicate that situation more clearly.
When writing programs in C it is normal practice to write the main() function first and to position all user functions after it or indeed in another file. Thus if a user function is called directly in main() the compiler will not know anything about it at this point i.e. if it takes parameters etc. This means we need to give the compiler this information by providing a function prototype or declaration before the function is called.
Syntax : type_spec function_name( type_par1, type_par2, etc. );
This declaration simply informs the compiler what type the function returns and what type and how many parameters it takes. Names may or may not be given to the parameters at this time.
For Example :- A more complicated “Hello World” program.
#include <stdio.h> /* standard I/O function prototypes */ void hello( void ) ; /* prototype */ void main( void ) { hello () ; // function call } void hello ( ) // function definition { printf ( "Hello World \n" ) ; }
A function definition actually defines what the function does and is essentially a discrete block of code which cannot be accessed by any statement in any other function except by formally calling the function. Thus any variables declared and used in a function are private or local to that function and cannot be accessed by any other function.
For Example :-
#include <stdio.h> void hello( void ) ; void main( ) { hello () ; } void hello ( ) { int i ; /* local or automatic variable */ for ( i=0; i<10; i++ ) printf( "Hello World \n" ); }
The variable i in the hello() function is private to the hello function i.e. it can only be accessed by code in the hello() function.
Local variables are classed as automatic variables because each time a function is called the variable is automatically created and is destroyed when the function returns control to the calling function. By created we mean that memory is set aside to store the variable’s value and by destroyed we mean that the memory required is released. Thus a local variable cannot hold a value between consecutive calls to the function.
The keyword static can be used to force a local variable to retain its value between function calls.
For Example :-
#include <stdio.h> void hello( void ) ; void main () { int i ; for ( i = 0; i < 10; i++ ) hello ( ) ; } void hello( ) { static int i = 1 ; printf( "Hello World call number %d\n", i ++ ); }
The static int i is created and initialised to 1 when the function is first called and only then. The variable retains its last value during subsequent calls to the function and is only destroyed when the program terminates.
NOTE : The variables i in main() and i in hello() are completely different variables even though they have the same name because they are private to the function in which they are declared. The compiler distinguishes between them by giving them their own unique internal names.
The scope of an identifier is the area of the program in which the identifier can be accessed.
Identifiers declared inside a code block are said to have block scope. The block scope ends at the terminating } of the code block. Local variables for example are visible, i.e. can be accessed, from within the function, i.e. code block, in which they are declared. Any block can contain variable declarations be it the body of a loop statement, if statement, etc. or simply a block of code marked off by a curly brace pair. When these blocks are nested and an outer and inner block contain variables with the same name then the variable in the outer block is inaccessible until the inner block terminates.
Global variables are variables which are declared outside all functions and which are visible to all functions from that point on. These are said to have file scope.
All functions are at the same level in C i.e. cannot define a function within a function in C. Thus within the same source file all functions have file scope i.e. all functions are visible or can be called by each other ( assuming they have been prototyped properly before they are called ).
The return statement is used to return a value to the calling function if necessary.
return expression ;
If a function has a return type of type void the expression section can be omitted completely or indeed the whole return statement can be omitted and the closing curly brace of the function will cause execution to return appropriately to the calling function.
For Example :-
#include <stdio.h> int hello( void ) ; int main( ) { int count, ch = ‘\0’; while ( ch != ‘q’ ) { count = hello( ) ; ch = getchar() ; _flushall() ; } printf( "hello was called %d times\n", i ) ; return 0 ; } int hello( ) { static int i = 1 ; printf( "Hello World \n" ) ; // hello() keeps track of how many times it was called return ( i++ ) ; // and passes that information back to its caller }
NOTE : The return value of the function need not always be used when calling it. In the above example if we are not interested in know how often hello() has been called we simply ignore that information and invoke the function with
hello();
NOTE : When the main() function returns a value, it returns it to the operating system. Zero is commonly returned to indicate successful normal termination of a program to the operating system and other values could be used to indicate abnormal termination of the program. This value may be used in batch processing or in debugging the program.
The types of all function arguments should be declared in the function prototype as well as in the function definition.
NOTE : In C arguments are passed to functions using the call-by-value scheme. This means that the compiler copies the value of the argument passed by the calling function into the formal parameter list of the called function. Thus if we change the values of the formal parameters within the called function we will have no effect on the calling arguments. The formal parameters of a function are thus local variables of the function and are created upon entry and destroyed on exit.
For Example :- Program to add two numbers.
#include <stdio.h> int add( int, int ) ; /* prototype -- need to indicate types only */ void main ( ) { int x, y ; puts ( "Enter two integers ") ; scanf( "%d %d", &x, &y) ; printf( "%d + %d = %d\n" , x, y, add(x,y) ) ; } int add ( int a, int b ) { int result ; result = a + b ; return result ; // parentheses used for clarity here }
NOTE : In the formal parameter list of a function the parameters must be individually typed.
The add() function here has three local variables, the two formal parameters and the variable result. There is no connection between the calling arguments, x and y, and the formal parameters, a and b, other than that the formal parameters are initialised with the values in the calling arguments when the function is invoked. The situation is depicted below to emphasise the independence of the various variables.
NOTE : The information flow is in one direction only.
For Example :- Program that attempts to swap the values of two numbers.
#include <stdio.h> void swap( int, int ) ; void main( ) { int a, b ; printf( "Enter two numbers" ) ; scanf( " %d %d ", &a, &b ) ; printf( "a = %d ; b = %d \n", a, b ) ; swap( a, b ) ; printf( "a = %d ; b = %d \n", a, b ) ; } void swap( int , int )//This is original form of declarator int num1, num2 ; // which you may see in older texts and code { int temp ; temp = num2 ; num2 = num1 ; num1 = temp ; }
Since C uses call by value to pass parameters what we have actually done in this program is to swap the values of the formal parameters but we have not changed the values in main(). Also since we can only return one value via the return statement we must find some other means to alter the values in the calling function.
The solution is to use call by reference where the addresses of the calling arguments are passed to the function parameter list and the parameters are pointers which we will encounter later on. For example when we use the scanf() standard library function to read values from the keyboard we use the & operator to give the address of the variables into which we want the values placed.
All Rights Reserved. © 2024 BookOfNetwork