Friday, August 24, 2018

Functions N Preprocessors


Functions: divide and conquer

C program consists of functions and variables. A function contains statements that specify the computing operations to be done, and variables store values used during the computation.

[KR88, page6]

 

A C program is made up of, among other components, variables and functions. A variable is a way to hold some data which may vary, hence the name.

 

A function is a segment of text in the source code of a program that tells the computer what to do. Programming consists, in large part, of writing functions.

 

The C language possesses features which make possible a ‘divide and conquer’ approach to large programming tasks. When programs are organised as modules they are necessarily well-planned, because each module contains only the instructions for a well-defined activity. Such programs are therefore more easily comprehensible by other readers than unstructured programs.

Another desirable quality of modular programs is that they may be modified without much difficulty. If changes are required, only a few modules may be affected, leaving the remainder of the program intact.

And last but not least, such programs are easier to debug, because errors can be localised to modules, and removed.

C functions are of three types: in-built library functions, user-defined functions and 3rd party library functions. The getchar(), printf(), scanf() are all in-built library functions supplied by compiler and declared in stdio.h header file. So compiler supplies number of library functions needed to carryout commonly used operations or tasks. However, C also allows programmers to define their own functions for carrying out various individual tasks.

The functions allow a large program to be broken down into a number of smaller, self-contained components, each of which has some unique, identifiable purpose. Why we needed to write program as a collection of functions?

1.    Many programs require a particular group of instructions to be accessed repeatedly from several different places within the program. The repeated instructions can be placed within a single function, which can then be accessed whenever it is needed.

2.    Avoids the need for redundant (repeated) programming of the same instructions.

3.    Programs with functions are compact.

4.    Debugging the code is much simpler because errors can be located and corrected.

5.    It increase the readability of the program and helps documentation.

6.    A function may be used by many other programs.

About Code blocks

The variables declared within code blocks or { and } braces are local to that code block and cannot be accessed outside that code block. Since function body is also declared between flower braces { and }, all variables declared inside the body are local to that function. Such local variables not retain their values if program control is out of that code block.

Although the left and right braces which mark a block may be placed anywhere on a line, for convenience of reading and debugging they are generally vertically aligned in the same column. For the same reason the braces of blocks which are nested inside other blocks are indented a few spaces to the right from the braces of the enclosing block.

Function Format

It is mandatory to declare the signature of the function to be create and used in any program file. The signature of function is of type:

returntype functionName(parameterList);

The general form of any C function or signature of c function is as follows:

return_data_type   function_name ( argument_list )

{

statement 1 ;

statement 2 ;

……

return ( expression);

}

 

Parts of Function

Each function has following parts: return data type, function name, its argument list, body of function and its return value. 

The return data type and return statement are inter-related and hence must match in their data type. Return statement simply returns control back to calling function, and it returns single value. If return data type is not mention while constructing function, compiler adds integer as default return type value.

 

Valid return statements:

 return;  return 1;  return (p);  return(a+b+c);

Invalid return statements:

 return n();      return(a,b,c);

A function may have zero/no, one or more return statements.

int GetBigger(int a, int b)

{

 if (a > b)

     return (a);

else

     return (b);

}

If more than one value is to be returned use pointers or arrays or structures.

Function name must be made of 

·         Sequences of characters chosen from the set a-z,A-Z,0-9,_.

·         first character must not be underscore (_), because such names are reserved for naming C library variables & functions.

·         Typical length is 8-10 characters, and maximum 63 characters.

·         Library function names must not be used as function names [not strictly].

·         C is case-sensitive language, so add(), Add(), ADD() are different functions.

The function arguments are passed between ( & ) brackets and are more than one then are separated by comma operator. The argument list must in following order: data type following identifier name.

 

The arguments passed to a function may be values or program variables, or they may be the memory addresses of program variables.

 

Note that while prototype/declaring and calling, passed variables are call arguments and at definition stage, they are call as parameters.

Function Usage: 3 Steps

The reusable code written as function and call whenever needed. Therefore, program can call the same function as-many times as it wishes in its code. However, before using any function it must be declare as function along with its signature. Then the function call done and lastly function definition is written.

 

#include <stdio.h>

 

int add(int i,int j);

 

 

Function declaration or prototype.

main()

{

 int x, y, z;

 x = add (5 + 8);

 y = add (2 + 3);

 z = add (9 + 7);

printf(“x=%d, y=%d, z=%d”, x,y,z);

}

 

 

 

Function call.

Function call.

Function call.

int add(int a, int b)

{

return a + b;

}

Function definition.

Note that in function prototype formal arguments are declare, which are dummy in nature. The actual processing parameters are passing while function call takes place.

Why this order is followed?

Because the compiler reads or parses the program from top-to bottom just like reading a letter in a paper.

The alternative method is defining function before calling it. However, this will not work if cross calling between many functions are included in program.

#include <stdio.h>

 

int add(int i, int j)

{

return i + j;

}

 

Function definition and no declaration or prototype needed.

main()

{

 int x, y, z;

 x = add (5 + 8);

 y = add (2 + 3);

 z = add (9 + 7);

printf(“x=%d, y=%d, z=%d”, x,y,z);

}

 

 

Function call.

Function call.

Function call.

 

Types of Functions

A function may belong to one of the following categories.

1.    Functions with No Arguments and No Return values.

2.    Functions with Arguments and No Return values.

3.    Functions with Arguments and Return values.

main()

char User_response()   

long Cal_Irate(int bsal, int irate)

void main(void)

returns nothing (default:int), no arguments

returns char,                        no arguments

returns long, accepts two int values as arguments

 

returns nothing,       arguments nothing

Recursive functions

Many algorithm and mathematical definitions are naturally described recursively, that is, function that calls itself directly or indirectly repeatedly. The most general example is finding factorial of nonnegative integer number [i.e., product of all integers between 1 and the given number].

n!  = 1      if n = 0

n * (n-1)  if n > 0

examples:

0! = 1

2! = 2 * 1 = 2

5! = 5 * 4! = 5 * 4 * 3! =5 * 4 * 3 * 2! =5 * 4 * 3 * 2 * 1 = 120

The functions, which constructed to call themselves, are call recursive functions. However, they need proper termination logic in its code else, program will hang forever.

Pre-processor

As name implies, this tool takes source code prior compiling, put some actions and then hand over it to compiler for further processing [refer Chapter 02 for details]. The following actions carried out on source code by pre-processor:

·         Replacement of defined identifiers by pieces of text.

·         Conditional selection of parts of the source file.

·         Inclusion of other files.

·         Renumbering of source files and the renaming of the source files itself.

To decide what action to perform, it looks for lines beginning with pre-processor directive in column one in source code. The general rule for defining a  pre-processor are as follows:

·         All pre-processor directives begin with the hash (#) sign.

·         They must start in the first column, and no space between # and directive word.

·         They are not terminated by semi-colon.

·         Per line only one directive is allowed.

·         They may appear anywhere in the code file.

Directive

Used as

#define

define a macro

#undef

undefine a macro

#include

include text from file

#line

Provide line number for compiler message.

#if

#else

#elif

#endif

compile-time conditional tests are carried out using these macros

Macros

Programmer can create type-less constants using #define directive. It tells the compiler to replace the constant name with whatever follows it. Directive like this are called macros [A defined name], and the process of substituting its replacement text is called macro substitution.

#include <stdio.h>

#define ASKINPUT printf(“Enter a Number:“)

..

 

main()

{

int age , size ;

ASKINPUT     ;

scanf ( “%d “, &age );

 

ASKINPUT    ;

scanf ( “%d “, &size );

……

}

For details and examples on constants in C language, refer Ch06_DataTyes_N_Identifiers.

There are two types of Macro definitions:

1.    Simple Macro Definition

2.    Macro Definition with arguments

Simple Macro Definition

As in the above figure, each occurrence of the identifier ASKINPUT as a token is replaced with printf(“Enter a Number:”) statement. A macro is simply substitution string that placed in the program.

#define TRUE

1

#define PI

3.14159

#define TWOPI

(PI+PI)

#define YES

0

#define DEFAULT_MOBILENO

+919901234567

#define TITLE

“BASIC ELECTRONICS”

#define MAX_USERS

100

 

 

some wrong MACRO definitions

 

#define PI = 3.14159

don’t want = sign.

 

#define TWOPI     (2*PI);

don’t want ; sign

 

#define TWOPI    PI+PI

Parentheses needed!

 

circum = TWOPI * radius;

circum = PI+PI * radius;

 [error in reading!]

 

       

 

Macro Definition with arguments

A macro with arguments acts as template and allows programmer to use it with different parameter values.

#define macro_name (name1,name2,…nameN)    replacement_text

#define SQUARE(x)

( (x) * (x) )

#define PRODUCT(x,y)

( (x) * (y) )

#define MAXIMUM(n1,n2)

( (n1)> (n2) ? (n1) : (n2) )

printf(“Square of 3 is =%d”, SQUARE(3));

printf(“Square of 5 is =%d”, SQUARE(5));

 

Other Pre-processing Techniques

Since, macro definition is type less variables, which means their data type is not checked and simply substitute whatever mentioned in the replacement text with token. Using this feature programmer can create his own language with his own syntax, for example writing program using Pascal language syntax. Refer example program for source code.

Conditional Compilation

It is necessary to make code ready for both debugging and final porting. It is done by imposing a condition on compiler using macro definitions.

#define  DEBUGMODE

……

main()

{

….

#if defined(DEBUGMODE)

                printf(“Calculated average is %d”, avg);

#else

     ; //do nothing

#endif

}

//#define  DEBUGMODE

……

main()

{

….

#if defined(DEBUGMODE)

                printf(“Calculated average is %d”, avg);

#else

     ; //do nothing

#endif

}

when code is in debug mode

when code is finalized, debug mode is commented-out and compiled


Previous Page Main Contents Next Page

No comments:

Post a Comment