Sunday, October 30, 2011

Pointer Notation in C Programming

Consider the declaration,
int i = 3 ;
This declaration tells the C compiler to:
(a) Reserve space in memory to hold the integer value.
(b) Associate the name i with this memory location.
(c) Store the value 3 at this location.
We may represent i’s location in memory by the following memory map.

We see that the computer has selected memory location 65524 as the place to store the value 3. The location number 65524 is not a number to be relied upon, because some other time the computer may choose a different location for storing the value 3. The important point is, i’s address in memory is a number.We can print this address number through the following program:
 
main( )
{
int i = 3 ;
printf ( "\nAddress of i = %u", &i ) ;
printf ( "\nValue of i = %d", i ) ;
}

The output of the above program would be:
Address of i = 65524
Value of i = 3

Look at the first printf( ) statement carefully. ‘&’ used in this statement is C’s ‘address of’ operator. The expression &i returns the address of the variable i, which in this case happens to be 65524. Since 65524 represents an address, there is no question of a sign being associated with it. Hence it is printed out using %u, which is a format specifier for printing an unsigned integer. We have been using the ‘&’ operator all the time in the scanf( ) statement.
The other pointer operator available in C is ‘*’, called ‘value at address’ operator. It gives the value stored at a particular address. The ‘value at address’ operator is also called ‘indirection’ operator.
Observe carefully the output of the following program:

main( )
{
int i = 3 ;
printf ( "\nAddress of i = %u", &i ) ;
printf ( "\nValue of i = %d", i ) ;
printf ( "\nValue of i = %d", *( &i ) ) ;
}

The output of the above program would be:
Address of i = 65524
Value of i = 3
Value of i = 3
 
Note that printing the value of *( &i ) is same as printing the value of i.
The expression &i gives the address of the variable i. This address can be collected in a variable, by saying,
j = &i ;
But remember that j is not an ordinary variable like any other integer variable. It is a variable that contains the address of other variable (i in this case). Since j is a variable the compiler must provide it space in the memory. Once again, the following memory map would illustrate the contents of i and j.

 As you can see, i’s value is 3 and j’s value is i’s address.
But wait, we can’t use j in a program without declaring it. And since j is a variable that contains the address of i, it is declared as,
int *j ;
This declaration tells the compiler that j will be used to store the address of an integer value. In other words j points to an integer. How do we justify the usage of * in the declaration,
int *j ;
Let us go by the meaning of *. It stands for ‘value at address’. Thus, int *j would mean, the value at the address contained in j is an int.
Here is a program that demonstrates the relationships we have been discussing.
 
main( )
{
int i = 3 ;
int *j ;
j = &i ;
printf ( "\nAddress of i = %u", &i ) ;
printf ( "\nAddress of i = %u", j ) ;
printf ( "\nAddress of j = %u", &j ) ;
printf ( "\nValue of j = %u", j ) ;
printf ( "\nValue of i = %d", i ) ;
printf ( "\nValue of i = %d", *( &i ) ) ;
printf ( "\nValue of i = %d", *j ) ;
}

The output of the above program would be:
Address of i = 65524
Address of i = 65524
Address of j = 65522
Value of j = 65524
Value of i = 3
Value of i = 3
Value of i = 3

Work through the above program carefully, taking help of the memory locations of i and j shown earlier. This program summarizes everything that we have discussed so far. If you don’t understand the program’s output, or the meanings of &i, &j, *j and *( &i ), re-read the last few pages. Everything we say about C pointers from here onwards will depend on your understanding these expressions thoroughly.
Look at the following declarations,
 
int *alpha ;
char *ch ;
float *s ;

Here, alpha, ch and s are declared as pointer variables, i.e. variables capable of holding addresses. Remember that, addresses (location nos.) are always going to be whole numbers, therefore pointers always contain whole numbers. Now we can put these two facts together and say—pointers are variables that contain addresses, and since addresses are always whole numbers, pointers would always contain whole numbers.
The declaration float *s does not mean that s is going to contain a floating-point value. What it means is, s is going to contain the address of a floating-point value. Similarly, char *ch means that ch is going to contain the address of a char value. Or in other words, the value at address stored in ch is going to be a char.
The concept of pointers can be further extended. Pointer, we know is a variable that contains address of another variable. Now this variable itself might be another pointer. Thus, we now have a pointer that contains another pointer’s address. The following example should make this point clear.
 
main( )
{
int i = 3, *j, **k ;
j = &i ;
k = &j ;
printf ( "\nAddress of i = %u", &i ) ;
printf ( "\nAddress of i = %u", j ) ;
printf ( "\nAddress of i = %u", *k ) ;
printf ( "\nAddress of j = %u", &j ) ;
printf ( "\nAddress of j = %u", k ) ;
printf ( "\nAddress of k = %u", &k ) ;
printf ( "\nValue of j = %u", j ) ;
printf ( "\nValue of k = %u", k ) ;
printf ( "\nValue of i = %d", i ) ;
printf ( "\nValue of i = %d", * ( &i ) ) ;
printf ( "\nValue of i = %d", *j ) ;
printf ( "\nValue of i = %d", **k ) ;
}

The output of the above program would be:
 
Address of i = 65524
Address of i = 65524
Address of i = 65524
Address of j = 65522
Address of j = 65522
Address of k = 65520
Value of j = 65524
Value of k = 65522
Value of i = 3
Value of i = 3
Value of i = 3
Value of i = 3
Figure would help you in tracing out how the program prints the above output.
Remember that when you run this program the addresses that get printed might turn out to be something different than the ones shown in the figure. However, with these addresses too the relationship between i, j and k can be easily established.

Observe how the variables j and k have been declared,
int i, *j, **k ;
Here, i is an ordinary int, j is a pointer to an int (often called an integer pointer), whereas k is a pointer to an integer pointer. We can extend the above program still further by creating a pointer to a pointer to an integer pointer. In principle, you would agree that likewise there could exist a pointer to a pointer to a pointer to a pointer to a pointer. There is no limit on how far can we go on extending this definition. Possibly, till the point we can comprehend it. And that point of comprehension is usually a pointer to a pointer. Beyond this one rarely requires to extend the definition of a pointer. But just in case...

Conclusions of Functions & Pointers in C Programming

From the programs that we discussed here we can draw the following conclusions:

(a)
If we want that the value of an actual argument should not get changed in the function being called, pass the actual argument by value.
(b)If we want that the value of an actual argument should get changed in the function being called, pass the actual argument by reference.
(c)If a function is to be made to return more than one value at a time then return these values indirectly by using a call by reference.

Back to Function Calls : C Programming

Having had the first tryst with pointers let us now get back to what we had originally set out to learn—the two types of function calls—call by value and call by reference. Arguments can generally be passed to functions in one of the two ways:
(a) sending the values of the arguments
(b) sending the addresses of the arguments
In the first method the ‘value’ of each of the actual arguments in the calling function is copied into corresponding formal arguments of the called function. With this method the changes made to the formal arguments in the called function have no effect on the values of actual arguments in the calling function. The following program illustrates the ‘Call by Value’.
 
main( )
{
int a = 10, b = 20 ;
swapv ( a, b ) ;
printf ( "\na = %d b = %d", a, b ) ;
}
swapv ( int x, int y )
{
int t ;
t = x ;
x = y ;
y = t ;
printf ( "\nx = %d y = %d", x, y ) ;
}

The output of the above program would be:
x = 20 y = 10
a = 10 b = 20
Note that values of a and b remain unchanged even after exchanging the values of x and y.

In the second method (call by reference) the addresses of actual arguments in the calling function are copied into formal arguments of the called function. This means that using these addresses we would have an access to the actual arguments and hence we would be able to manipulate them. The following program illustrates this fact.
 
main( )
{
int a = 10, b = 20 ;
swapr ( &a, &b ) ;
printf ( "\na = %d b = %d", a, b ) ;
}
swapr( int *x, int *y )
{
int t ;
t = *x ;
*x = *y ;
*y = t ;
}

The output of the above program would be:
a = 20 b = 10
Note that this program manages to exchange the values of a and b using their addresses stored in x and y.
Usually in C programming we make a call by value. This means that in general you cannot alter the actual arguments. But if desired, it can always be achieved through a call by reference.
Using a call by reference intelligently we can make a function return more than one value at a time, which is not possible ordinarily. This is shown in the program given below.
 
main( )
{
int radius ;
float area, perimeter ;
printf ( "\nEnter radius of a circle " ) ;
scanf ( "%d", &radius ) ;
areaperi ( radius, &area, &perimeter ) ;
printf ( "Area = %f", area ) ;
printf ( "\nPerimeter = %f", perimeter ) ;
}
areaperi ( int r, float *a, float *p )
{
*a = 3.14 * r * r ;
*p = 2 * 3.14 * r ;
}

And here is the output...
Enter radius of a circle 5
Area = 78.500000
Perimeter = 31.400000

Here, we are making a mixed call, in the sense, we are passing the value of radius but, addresses of area and perimeter. And since we are passing the addresses, any change that we make in values stored at addresses contained in the variables a and p, would make the change effective in main( ). That is why when the control returns from the function areaperi( ) we are able to output the values of area and perimeter.
Thus, we have been able to indirectly return two values from a called function, and hence, have overcome the limitation of the return statement, which can return only one value from a function at a time.

An Introduction to Pointers in C Programming

Which feature of C do beginners find most difficult to understand? The answer is easy: pointers. Other languages have pointers but few use them so frequently as C does. And why not? It is C’s clever use of pointers that makes it the excellent language it is.
The difficulty beginners have with pointers has much to do with C’s pointer terminology than the actual concept. For instance, when a C programmer says that a certain variable is a “pointer”, what does that mean? It is hard to see how a variable can point to something, or in a certain direction.
It is hard to get a grip on pointers just by listening to programmer’s jargon. In our discussion of C pointers, therefore, we will try to avoid this difficulty by explaining pointers in terms of programming concepts we already understand. The first thing we want to do is explain the rationale of C’s pointer notation

Call by Value and Call by Reference in C Programming

 By now we are well familiar with how to call functions. But, if you observe carefully, whenever we called a function and passed something to it we have always passed the ‘values’ of variables to the called function. Such function calls are called ‘calls by value’. By this what we mean is, on calling a function we are passing values of variables to it. The examples of call by value are shown below:
 
sum = calsum ( a, b, c ) ;
f = factr ( a ) ;
 
We have also learnt that variables are stored somewhere in memory. So instead of passing the value of a variable, can we not pass the location number (also called address) of the variable to a function? If we were able to do so it would become a ‘call by reference’. What purpose a ‘call by reference’ serves we would find out a little later. First we must equip ourselves with knowledge of how to make a ‘call by reference’. This feature of C functions needs at least an elementary knowledge of a concept called ‘pointers’. So let us first acquire the basics of pointers after which we would take up this topic once again.

Function Declaration and Prototypes in C Programming

Any C function by default returns an int value. More specifically, whenever a call is made to a function, the compiler assumes that this function would return a value of the type int. If we desire that a function should return a value other than an int, then it is necessary to explicitly mention so in the calling function as well as in the called function. Suppose we want to find out square of a number using a function. This is how this simple program would look like:
 
main( )
{
float a, b ;
printf ( "\nEnter any number " ) ;
scanf ( "%f", &a ) ;
b = square ( a ) ;
printf ( "\nSquare of %f is %f", a, b ) ;
}
square ( float x )
{
float y ;
y = x * x ;
return ( y ) ;
}

And here are three sample runs of this program...
Enter any number 3
Square of 3 is 9.000000
Enter any number 1.5
Square of 1.5 is 2.000000
Enter any number 2.5
Square of 2.5 is 6.000000
The first of these answers is correct. But square of 1.5 is definitely not 2. Neither is 6 a square of 2.5. This happened because any C function, by default, always returns an integer value. Therefore, even though the function square( ) calculates the square of 1.5 as 2.25, the problem crops up when this 2.25 is to be returned to main( ). square( ) is not capable of returning a float value. How do we overcome this? The following program segment illustrates how to make square( ) capable of returning a float value.
 
main( )
{
float square ( float ) ;
float a, b ;
printf ( "\nEnter any number " ) ;
scanf ( "%f", &a ) ;
b = square ( a ) ;
printf ( "\nSquare of %f is %f", a, b ) ;
}
float square ( float x )
{
float y ;
y = x * x ;
return ( y ) ;
}

And here is the output...
Enter any number 1.5
Square of 1.5 is 2.250000
Enter any number 2.5
Square of 2.5 is 6.250000
Now the expected answers i.e. 2.25 and 6.25 are obtained. Note that the function square( ) must be declared in main( ) as
float square ( float ) ;
This statement is often called the prototype declaration of the square( ) function. What it means is square( ) is a function that receives a float and returns a float. We have done the prototype declaration in main( ) because we have called it from main( ). There is a possibility that we may call square( ) from several other functions other than main( ). Does this mean that we would need prototype declaration of square( ) in all these functions. No, in such a case we would make only one declaration outside all the functions at the beginning of the program.
In practice you may seldom be required to return a value other than an int, but just in case you are required to, employ the above method. In some programming situations we want that a called function should not return any value. This is made possible by using the keyword void. This is illustrated in the following program.
 
main( )
{
void gospel( ) ;
gospel( ) ;
}
void gospel( )
{
printf ( "\nViruses are electronic bandits..." ) ;
printf ( "\nwho eat nuggets of information..." ) ;
printf ( "\nand chunks of bytes..." ) ;
printf ( "\nwhen you least expect..." ) ;
}
Here, the gospel( ) function has been defined to return void; means it would return nothing. Therefore, it would just flash the four messages about viruses and return the control back to the main( ) function.

Advanced Features of Functions in C Programming

With a sound basis of the preliminaries of C functions, let us now get into their intricacies. Following advanced topics would be considered here.

(a) Function Declaration and Prototypes
(b) Calling functions by value or by reference
(c) Recursion


Let us understand these features one by one.

One Dicey Issue of Loop Control Structure in C programing

Consider the following function calls:

#include <conio.h>
clrscr ( ) ;
gotoxy ( 10, 20 ) ;
ch = getch ( a ) ;

Here we are calling three standard library functions. Whenever we call the library functions we must write their prototype before making the call. This helps the compiler in checking whether the values being passed and returned are as per the prototype declaration. But since we don’t define the library functions (we merely call them) we may not know the prototypes of library functions. Hence when the library of functions is provided a set of ‘.h’ files is also provided. These files contain the prototypes of library functions. But why multiple files? Because the library functions are divided into different groups and one file is provided for each group. For example, prototypes of all input/output functions are provided in the file ‘stdio.h’, prototypes of all mathematical functions are provided in the file ‘math.h’, etc.
On compilation of the above code the compiler reports all errors due to the mismatch between parameters in function call and their corresponding prototypes declared in the file ‘conio.h’. You can even open this file and look at the prototypes. They would appear as shown below:

void clrscr( ) ;
void gotoxy ( int, int ) ;
int getch( ) ;

Now consider the following function calls:

#include <stdio.h>
int i = 10, j = 20 ;
printf ( "%d %d %d ", i, j ) ;
printf ( "%d", i, j ) ;

The above functions get successfully compiled even though there is a mismatch in the format specifiers and the variables in the list. This is because printf( ) accepts variable number of arguments (sometimes 2 arguments, sometimes 3 arguments, etc.), and even with the mismatch above the call still matches with the prototype of printf( ) present in ‘stdio.h’. At run-time when the first printf( ) is executed, since there is no variable matching with the last specifier %d, a garbage integer gets printed. Similarly, in the second printf( ) since the format specifier for j has not been mentioned its value does not get printed.

Calling Convention of C programing Loop Control Structure

Calling convention indicates the order in which arguments are passed to a function when a function call is encountered. There are two possibilities here:
 
(a) Arguments might be passed from left to right.
(b)Arguments might be passed from right to left.
C language follows the second order.
Consider the following function call:
fun (a, b, c, d ) ;

In this call it doesn’t matter whether the arguments are passed from left to right or from right to left. However, in some function call the order of passing arguments becomes an important consideration. For example:
int a = 1 ;
printf ( "%d %d %d", a, ++a, a++ ) ;
It appears that this printf( ) would output 1 2 3.
This however is not the case. Surprisingly, it outputs 3 3 1. This is because C’s calling convention is from right to left. That is, firstly

1 is passed through the expression a++ and then a is incremented to 2. Then result of ++a is passed. That is, a is incremented to 3 and then passed. Finally, latest value of a, i.e. 3, is passed. Thus in right to left order 1, 3, 3 get passed. Once printf( ) collects them it prints them in the order in which we have asked it to get them printed (and not the order in which they were passed). Thus 3 3 1 gets printed.

Scope Rule of Functions of C programing Loop Control Structure

Look at the following program
main( )
{
int i = 20 ;
display ( i ) ;
}
display ( int j )
{
int k = 35 ;
printf ( "\n%d", j ) ;
printf ( "\n%d", k ) ;
}
of i is known only to the function main( ) and not to any other function. Similarly, the variable k is local to the function display( ) and hence it is not available to main( ). That is why to make the value of i available to display( ) we have to explicitly pass it to display( ). Likewise, if we want k to be available to main( ) we will have to return it to main( ) using the return statement. In general we can say that the scope of a variable is local to the function in which it is defined.
In this program is it necessary to pass the value of the variable i to the function display( )? Will it not become automatically available to the function display( )? No. Because by default the scope of a variable is local to the function in which it is defined. The presence

Passing Values between Functions in C programing Loop Control Structure

The functions that we have used so far haven’t been very flexible. We call them and they do what they are designed to do. Like our mechanic who always services the motorbike in exactly the same way, we haven’t been able to influence the functions in the way they carry out their tasks. It would be nice to have a little more control over what functions do, in the same way it would be nice to be able to tell the mechanic, “Also change the engine oil, I am going for an outing”. In short, now we want to communicate between the ‘calling’ and the ‘called’ functions.
The mechanism used to convey information to the function is the ‘argument’. You have unknowingly used the arguments in the printf( ) and scanf( ) functions; the format string and the list of variables used inside the parentheses in these functions are arguments. The arguments are sometimes also called ‘parameters’.
Consider the following program. In this program, in main( ) we receive the values of a, b and c through the keyboard and then output the sum of a, b and c. However, the calculation of sum is done in a different function called calsum( ). If sum is to be calculated in calsum( ) and values of a, b and c are received in main( ), then we must pass on these values to calsum( ), and once calsum( ) calculates the sum we must return it from calsum( ) back to main( ).

/* Sending and receiving values between functions */
main( )
{
int a, b, c, sum ;
printf ( "\nEnter any three numbers " ) ;
scanf ( "%d %d %d", &a, &b, &c ) ;
sum = calsum ( a, b, c ) ;
printf ( "\nSum = %d", sum ) ;
}
calsum ( x, y, z )
int x, y, z ;
{
int d ;
d = x + y + z ;
return ( d ) ;
}

And here is the output...
Enter any three numbers 10 20 30
Sum = 60
There are a number of things to note about this program:

(a) In this program, from the function main( ) the values of a, b and c are passed on to the function calsum( ), by making a call to the function calsum( ) and mentioning a, b and c in the parentheses:
sum = calsum ( a, b, c ) ;
In the calsum( ) function these values get collected in three variables x, y and z:
calsum ( x, y, z )
int x, y, z ;

(b) The variables a, b and c are called ‘actual arguments’, whereas the variables x, y and z are called ‘formal arguments’. Any number of arguments can be passed to a function being called. However, the type, order and number of the actual and formal arguments must always be same
Instead of using different variable names x, y and z, we could have used the same variable names a, b and c. But the compiler would still treat them as different variables since they are in different functions.

(c) There are two methods of declaring the formal arguments. The one that we have used in our program is known as Kernighan and Ritchie (or just K & R) method.
calsum ( x, y, z )
int x, y, z ;
Another method is,
calsum ( int x, int y, int z )
This method is called ANSI method and is more commonly used these days.

(d) In the earlier programs the moment closing brace ( } ) of the called function was encountered the control returned to the calling function. No separate return statement was necessary to send back the control.
This approach is fine if the called function is not going to return any meaningful value to the calling function. In the above program, however, we want to return the sum of x, y and z. Therefore, it is necessary to use the return statement.
The return statement serves two purposes:
(1) On executing the return statement it immediately transfers the control back to the calling program.
(2) It returns the value present in the parentheses after return, to th3e calling program. In the above program the value of sum of three numbers is being returned

(e) There is no restriction on the number of return statements that may be present in a function. Also, the return statement need not always be present at the end of the called function. The following program illustrates these facts.
fun( )
{
char ch ;
printf ( "\nEnter any alphabet " ) ;
scanf ( "%c", &ch ) ;
if ( ch >= 65 && ch <= 90 )
return ( ch ) ;
else
return ( ch + 32 ) ;
}
In this function different return statements will be executed depending on whether ch is capital or not.

(f) Whenever the control returns from a function some value is definitely returned. If a meaningful value is returned then it should be accepted in the calling program by equating the called function to some variable. For example,
sum = calsum ( a, b, c ) ;

(g) All the following are valid return statements.
return ( a ) ;
return ( 23 ) ;
return ( 12.34 ) ;
return ;
In the last statement a garbage value is returned to the calling function since we are not returning any specific value. Note that in this case the parentheses after return are dropped.

(h) If we want that a called function should not return any value, in that case, we must mention so by using the keyword void as shown below.
void display( )
{
printf ( "\nHeads I win..." ) ;
printf ( "\nTails you lose" ) ;
}

(i) A function can return only one value at a time. Thus, the following statements are invalid.
return ( a, b ) ;
return ( x, 12 ) ;
There is a way to get around this limitation, which would be discussed later in this chapter when we learn pointers.

(j) If the value of a formal argument is changed in the called function, the corresponding change does not take place in the calling function. For example,
main( )
{
int a = 30 ;
fun ( a ) ;
printf ( "\n%d", a ) ;
}
fun ( int b )
{
b = 60 ;
printf ( "\n%d", b ) ;
}
The output of the above program would be:
60
30
Thus, even though the value of b is changed in fun( ), the value of a in main( ) remains unchanged. This means that when values are passed to a called function the values present in actual arguments are not physically moved to the formal arguments; just a photocopy of values in actual argument is made into formal arguments

Why Use Functions ? in C programing Loop Control Structure

Why write separate functions at all? Why not squeeze the entire logic into one function, main( )? Two reasons:

(a)  Writing functions avoids rewriting the same code over and over. Suppose you have a section of code in your program that calculates area of a triangle. If later in the program you want to calculate the area of a different triangle, you won’t like it if you are required to write the same instructions all over again. Instead, you would prefer to jump to a ‘section of code’ that calculates area and then jump back to the place from where you left off. This section of code is nothing but a function.

(b)  Using functions it becomes easier to write programs and keep track of what they are doing. If the operation of a program can be divided into separate activities, and each activity placed in a different function, then each could be written and checked more or less independently. Separating the code into modular functions also makes the program easier to design and understand.

What is the moral of the story? Don’t try to cram the entire logic in one function. It is a very bad style of programming. Instead, break a program into small units and write functions for each of these isolated subdivisions. Don’t hesitate to write functions that are called only once. What is important is that these functions perform some logically isolated task.

What is a Function of : C programing The Loop Control Structure

A function is a self-contained block of statements that perform a coherent task of some kind. Every C program can be thought of as a collection of these functions. As we noted earlier, using a function is something like hiring a person to do a specific job for you. Sometimes the interaction with this person is very simple;
sometimes it’s complex.

Suppose you have a task that is always performed exactly in the same way—say a bimonthly servicing of your motorbike. When you want it to be done, you go to the service station and say, “It’stime, do it now”. You don’t need to give instructions, because the mechanic knows his job. You don’t need to be told when the job is done. You assume the bike would be serviced in the usual way, the mechanic does it and that’s that.
Let us now look at a simple C function that operates in much the same way as the mechanic. Actually, we will be looking at two things—a function that calls or activates the function and the function itself.
main( )
{
      message( ) ;
      printf ( "\nCry, and you stop the monotony!" ) ;
}
message( )
{
      printf ( "\nSmile, and the world smiles with you..." ) ;
}

And here’s the output...

Smile, and the world smiles with you...
Cry, and you stop the monotony!

Here, main( ) itself is a function and through it we are calling the function message( ). What do we mean when we say that main( ) ‘calls’ the function message( )? We mean that the control passes to the function message( ). The activity of main( ) is temporarily suspended; it falls asleep while the message( ) function wakes up and goes to work. When the message( ) function runs out of statements to execute, the control returns to main( ), which comes to life again and begins executing its code at the exact point where it left off. Thus, main( ) becomes the ‘calling’ function, whereas

main( )
{
      message( ) ;
      printf ( "\nCry, and you stop the monotony!" ) ;
}
message( )
{
      printf ( "\nSmile, and the world smiles with you..." ) ;
}

And here’s the output...

Smile, and the world smiles with you...
Cry, and you stop the monotony!

Here, main( ) itself is a function and through it we are calling the function message( ). What do we mean when we say that main( ) ‘calls’ the function message( )? We mean that the control passes to the function message( ). The activity of main( ) is temporarily suspended; it falls asleep while the message( ) function wakes up and goes to work. When the message( ) function runs out of statements to execute, the control returns to main( ), which comes to life again and begins executing its code at the exact point where it left off. Thus, main( ) becomes the ‘calling’ function, whereasmessage( ) becomes the ‘called’ function
.
If you have grasped the concept of ‘calling a function you are prepared for a call to more than one function. Consider the following example:

main( )
{
      printf ( "\nI am in main" ) ;
      italy( ) ;
      brazil( ) ;
      argentina( ) ;


becomes the ‘called’ function.
If you have grasped the concept of ‘calling’ a function you are prepared for a call to more than one function. Consider the following example:

main( )
{
      printf ( "\nI am in main" ) ;
      italy( ) ;
      brazil( ) ;
      argentina( ) ; 
}
italy( ) 
{
      printf ( "\nI am in italy" ) ;

}
brazil( ) 
{
      printf ( "\nI am in brazil" ) ; 
}
argentina( ) 
{
      printf ( "\nI am in argentina" ) ;
}

The output of the above program when executed would be as
under:

I am in main
I am in italy 
I am in brazil 
I am in argentina 

From this program a number of conclusions can be drawn:

−  Any C program contains at least one function.

−  If a program contains only one function, it must be main( ).

−  If a C program contains more than one function, then one (and only one) of these functions must be
main( ), because program execution always begins with main( ).

−  There is no limit on the number of functions that might be present in a C program.

−  Each function in a program is called in the sequence specified by the function calls in main( )

−  After each function has done its thing, control returns to main( ).When main( ) runs out of function calls, the program ends.

As we have noted earlier the program execution always begins with main( ). Except for this fact all C functions enjoy a state of perfect equality. No precedence, no priorities, nobody is nobody’s
boss. One function can call another function it has already called but has in the meantime left temporarily in order to call a third function which will sometime later call the function that has calledit, if you understand what I mean. No? Well, let’s illustrate with an example.

main( )
{
      printf ( "\nI am in main" ) ;
      italy( ) ;
      printf ( "\nI am finally back in main" ) ;
}
italy( ) 
{
      printf ( "\nI am in italy" ) ;
      brazil( ) ;
      printf ( "\nI am back in italy" ) ;
}
brazil( ) 
{
      printf ( "\nI am in brazil" ) ; 
      argentina( ) ;
}
argentina( ) 
{
      printf ( "\nI am in argentina" ) ;
}

And the output would look like..
I am in main
I am in italy 
I am in brazil 
I am in argentina 
I am back in italy 
I am finally back in main

Here, main( ) calls other functions, which in turn call still other functions. Trace carefully the way control passes from one function to another. Since the compiler always begins the program
execution with main( ), every function in a program must be called directly or indirectly by main( ). In other words, the main( ) function drives other functions. Let us now summarize what we have learnt so far.

(a)  C program is a collection of one or more functions.

(b)  A function gets called when the function name is followed by a semicolon. For example,

 main( )
{
     argentina( ) ;
}

(c)  A function is defined when function name is followed by a pair of braces in which one or more statements may be present. For example,

 argentina( )

 statement 1 ;
 statement 2 ;
 statement 3 ;

(d)  Any function can be called from any other function. Even main( ) can be called from other functions. For example,

 main( )
{
     message( ) ;
}
message( )
{
     printf ( "\nCan't imagine life without C" ) ;
     main( ) ; 

}

(e)  A function can be called any number of times. For example,

 main( ) 
{
     message( ) ;
     message( ) ;
}
message( )
{
     printf ( "\nJewel Thief!!" ) ;
}

(f)  The order in which the functions are defined in a program and the order in which they get called need not necessarily be same. For example,

 main( )
{
     message1( ) ;
     message2( ) ;
}
message2( )
{
     printf ( "\nBut the butter was bitter" ) ;
}
message1( )
{
     printf ( "\nMary bought some butter" ) ;
}

 Here, even though message1( ) is getting called before message2( ), still, message1( ) has been defined after message2( ). However, it is advisable to define the functions in the same order in which they are called. This makes the program easier to understand.

(g)  A function can call itself. Such a process is called ‘recursion’. We would discuss this aspect of C functions later in this chapter. 

(h)  A function can be called from other function, but a function cannot be defined in another function. Thus, the following program code would be wrong, since argentina( ) is being defined inside another function, main( ).

main( )
{
     printf ( "\nI am in main" ) ;
 argentina( )
 {
           printf ( "\nI am in argentina" ) ;
 }
}

(i)  There are basically two types of functions:

 Library functions Ex. printf( ), scanf( ) etc. User-defined functions Ex. argentina( ), brazil( ) etc.

 As the name suggests, library functions are nothing but commonly required functions grouped together and stored in what is called a Library. This library of functions is present on the disk and is written for us by people who write compilers for us. Almost always a compiler comes with a library of standard functions. The procedure of calling both types of functions is exactly same.

C programing The Loop Control Structure Summary:

(a)  When we need to choose one among number of alternatives, a switch statement is used.
(b)  The  switch  keyword is followed by an integer or an expression that evaluates to an integer.  
(c)  The  case  keyword is followed by an integer or a character constant. 
(d)  The control falls through all the cases unless the break statement is given.
(e)  The usage of the goto keyword should be avoided as it usually violets the normal flow of execution.

The goto Keyword : C programing Loop Control Structure

Avoid goto keyword! They make a C programmer’s life miserable. There is seldom a legitimate reason for using goto, and its use isone of the reasons that programs become unreliable, unreadable, and hard to debug. And yet many programmers find goto seductive. 

In a difficult programming situation it seems so easy to use a goto to take the control where you want. However, almost always, there is a more elegant way of writing the same program using if, for,
while and switch. These constructs are far more logical and easy to understand.

The big problem with gotos is that when we do use them we can never be sure how we got to a certain point in our code. They obscure the flow of control. So as far as possible skip them. You can always get the job done without them. Trust me, with good programming skills goto can always be avoided. This is the first and last time that we are going to use goto in this book. However, for sake of completeness of the book, the following program shows how to use goto.

main( )
{
      int  goals ;

      printf ( "Enter the number of goals scored against India" ) ;
      scanf ( "%d", &goals ) ;

      if ( goals <= 5 )
  goto sos ;
 else
 {
            printf ( "About time soccer players learnt C\n" ) ;
            printf ( "and said goodbye! adieu! to soccer" ) ;
            exit(  ) ;  /* terminates program execution */
 }

 sos :
            printf ( "To err is human!" ) ;
}

And here are two sample runs of the program...

Enter the number of goals scored against India 3
To err is human!
Enter the number of goals scored against India 7
About time soccer players learnt C
and said goodbye! adieu! to soccer

A few remarks about the program would make the things clearer.

−  If the condition is satisfied the goto statement transfers control to the label ‘sos’, causing printf( ) following sos to beexecuted. 

−  The label can be on a separate line or on the same line as the statement following it, as in,

 sos : printf ( "To err is human!" ) ;

−  Any number of gotos can take the control to the same label.

−  The  exit( ) function is a standard library function which terminates the execution of the program. It is necessary to use this function since we don't want the statement

 printf ( "To err is human!" ) 

 to get executed after execution of the else block.

−  The only programming situation in favour of using goto is when we want to take the control out of the loop that is contained in several other loops. The following program illustrates this. 

main( )
{
     int  i, j, k ; 

     for ( i = 1 ; i <= 3 ; i++ )
 {
           for ( j = 1 ; j <= 3 ; j++ )
  {
                 for ( k = 1 ; k <= 3 ; k++ )
   {
                       if ( i == 3 && j == 3 && k == 3 )
     goto out ;
    else
                             printf ( "%d %d %d\n", i, j, k ) ;
   }
  }
 }
 out :
           printf ( "Out of the loop at last!" ) ;
}

Go through the program carefully and find out how it works. Also write down the same program without using goto.

switch Versus if-else Ladder : C programing Loop Control Structure

There are some things that you simply cannot do with a switch. These are:

(a)  A float expression cannot be tested using a switch
(b)  Cases can never have variable expressions (for example it is wrong to say case a +3 : )
(c)  Multiple cases cannot use same expressions. Thus the following switch is illegal

switch  ( a )
{
     case 3 :
  ...
     case 1 + 2 :
  ...
}

(a), (b) and (c) above may lead you to believe that these are obvious disadvantages with a switch, especially since there weren’t any such limitations with if-else. Then why use a switch at all? For speed—switch works faster than an equivalent if-else ladder. How come? This is because the compiler generates a jump table for a switch during compilation. As a result, during execution it simply refers the jump table to decide which case should be executed, rather than actually checking which case is satisfied. As against this, if-elses are slower because they are evaluated at execution time. A switch with 10 cases would work faster than an equivalent if-else ladder. Also, a switch with 2 cases would work slower than if-else  ladder. Why? If the 10th  case is satisfied then jump table would be referred and statements for the 10th case would be executed. As againstthis, in an if-else ladder 10 conditions would be evaluated at execution time, which makes it slow. 

Note that a lookup in the jump table is faster than evaluation of a condition, especially if the condition is complex.

If on the other hand the conditions in the if-else were simple and less in number then if-else would work out faster than the lookup mechanism of a switch. Hence a switch with two cases would work slower than an equivalent if-else. Thus, you as a programmer should take a decision which of the two should be used when.

The Tips and Traps C programing Loop Control Structure

A few useful tips about the usage of switch and a few pitfalls to be avoided:

(a)  The earlier program that used switch may give you the wrong impression that you can use only cases arranged in ascending order, 1, 2, 3 and default. You can in fact put the cases in any order you please. Here is an example of scrambled case order:

 main( )
{
     int  i = 22 ;

     switch ( i ) 
 {
           case 121 :
                 printf ( "I am in case 121 \n" ) ;
   break ;
           case 7 :
                 printf ( "I am in case 7 \n" ) ;
   break ;
           case 22 :
                 printf ( "I am in case 22 \n" ) ;
   break ;
  default :
                 printf ( "I am in default \n" ) ;
 }
}

 The output of this program would be:

 I am in case 22 

(b)  You are also allowed to use char values in case and switch as shown in the following program:

 main( )
{
     char  c = 'x' ;

     switch ( c ) 
 {
           case 'v' :
                 printf ( "I am in case v \n" ) ;
   break ;
           case 'a' :
                 printf ( "I am in case a \n" ) ;
   break ;
           case 'x' :
                 printf ( "I am in case x \n" ) ;
   break ;
  default :
                 printf ( "I am in default \n" ) ;
 }
}

 The output of this program would be:

 I am in case x 

In fact here when we use ‘v’, ‘a’, ‘x’ they are actually replaced by the ASCII values (118, 97, 120) of these character constants.

(c)  At times we may want to execute a common set of statements for multiple  cases. How this can be done is shown in the following example.

 main( )
{
     char  ch ;

     printf ( "Enter any of the alphabet a, b, or c " ) ;
     scanf ( "%c", &ch ) ;
switch ( ch ) 
 {
           case 'a' :
           case 'A' :
                 printf ( "a as in ashar" ) ;
   break ;
           case 'b' :
           case 'B' :
                 printf ( "b as in brain" ) ;
   break ;
           case 'c' :
           case 'C' :
                 printf ( "c as in cookie" ) ;
   break ;
  default :
                 printf ( "wish you knew what are alphabets" ) ;
 } 
}

 Here, we are making use of the fact that once a case is satisfied the control simply falls through the case till it
doesn’t encounter a break statement. That is why if an alphabet a is entered the case ‘a’ is satisfied and since there are no statements to be executed in this case the control automatically reaches the next case i.e. case ‘A’ and executes all the statements in this case.

(d)  Even if there are multiple statements to be executed in each case there is no need to enclose them within a pair of braces (unlike if, and else). 

(e)  Every statement in a switch must belong to some case or the other. If a statement doesn’t belong to any case the compiler won’t report an error. However, the statement would never get executed. For example, in the following program the printf( ) never goes to work.
main( )
{
     int  i, j ;

     printf ( "Enter value of i" ) ;
     scanf ( "%d”, &i ) ;

     switch ( i )
 {
           printf ( "Hello" ) ;
           case 1 :
                 j = 10 ;
   break ;
           case 2 :
                 j = 20 ;
   break ;
 }
}

(f)  If we have no default case, then the program simply falls through the entire switch and continues with the next instruction (if any,) that follows the closing brace of switch.

(g)  Is switch a replacement for if? Yes and no. Yes, because it offers a better way of writing programs as compared to if, and no because in certain situations we are left with no choice but to use if. The disadvantage of switch is that one cannot have a case in a switch which looks like:

        case i <= 20 :

 All that we can have after the case is an int constant or a char constant or an expression that evaluates to one of these
constants. Even a float is not allowed.  The advantage of switch over if is that it leads to a more structured program and the level of indentation is manageable, more so if there are multiple statements within each case of a switch.

(h)  We can check the value of any expression in a switch. Thus
the following switch statements are legal.

       switch ( i + j * k )
       switch ( 23 + 45 % 4 * k )
       switch ( a < 4 && b > 7 )

 Expressions can also be used in cases provided they are constant expressions. Thus case 3 + 7 is correct, however, case a + b is incorrect. 

(i)  The break statement when used in a switch takes the control outside the switch. However, use of continue will not take the control to the beginning of switch as one is likely to believe.

(j)  In principle, a switch may occur within another, but in practice it is rarely done. Such statements would be called nested switch statements.

(k)  The  switch statement is very useful while writing menu driven programs. This aspect of switch is discussed in the exercise at the end of this chapter

Decisions Using switch : C Programming Case Control Structure

The control statement that allows us to make a decision from the number of choices is called a switch, or more correctly a switch-case-default, since these three keywords go together to make up the control statement. They most often appear as follows:

switch ( integer expression )
{
  case constant 1 :
  do this ;
  case constant 2 :
  do this ;
  case constant 3 :
  do this ;
 default :
  do this ; 
}

The integer expression following the keyword switch is any C expression that will yield an integer value. It integer. The keyword case is followed by an integer or a character constant. Each constant in each case must be different from all the others. The “do this” lines in the above form of switch represent any valid C statement.

What happens when we run a program containing a switch? First, the integer expression following the keyword switch is evaluated. The value it gives is then matched, one by one, against the constant values that follow the case statements. When a match is found, the program executes the statements following that case,
and all subsequent case and default statements as well. If no match is found with any of the case statements, only the statements following the default are executed. A few examples will show how this control structure works. Consider the following program:

main( )
{
      int   i = 2 ;

      switch ( i ) 
 {
  case 1 :
                  printf ( "I am in case 1 \n" ) ;
  case 2 :
                  printf ( "I am in case 2 \n" ) ;
  case 3 :
                  printf ( "I am in case 3 \n" ) ;
  default :
                  printf ( "I am in default \n" ) ;
 }
}

The output of this program would be:

I am in case 2
I am in case 3 
I am in default 

The output is definitely not what we expected! We didn’t expectthe second and third line in the above output. The program prints case 2 and 3 and the default case. Well, yes. We said the switch executes the case where a match is found and all the subsequent cases and the default as well.  If you want that only case 2 should get executed, it is upto you to get out of the switch then and there by using a break statement. The following example shows how this is done. Note that there is no need for a break statement after the default, since the control comes out of the switch anyway.

main( )
{
      int   i = 2 ;

      switch ( i ) 
 {
  case 1 :
                  printf ( "I am in case 1 \n" ) ;
   break ;
  case 2 :
                  printf ( "I am in case 2 \n" ) ;
   break ;
  case 3 :
                  printf ( "I am in case 3 \n" ) ;
   break ;
  default :
                  printf ( "I am in default \n" ) ;
 }
}

The output of this program would be:
I am in case 2
The operation of switch is shown below in the form of a flowchart for a better understanding. 
 

Summary : C programing The Loop Control Structure

(a)  The three type of loops available in C are for, while, and do-while.
(b)  A break statement takes the execution control out of the loop.
(c)  A  continue  statement skips the execution of the statements after it and takes the control to the beginning of the loop.
(d)  A do-while loop is used to ensure that the statements within the loop are executed at least once.
(e)  The ++ operator increments the operand by 1, whereas, the -- operator decrements it by 1.
(f)  The operators +=, -=, *=, /=, %= are compound assignment operators. They modify the value of the operand to the left of them.

The do-while Loop : C programing The Loop Control Structure

The do-while loop looks like this:

do
{
 this ;
      and this ;
      and this ;
      and this ;
} while ( this condition is true ) ;

There is a minor difference between the working of while and do-while  loops. This difference is the place where the condition is tested. The while tests the condition before executing any of the statements within the while loop. As against this, the do-while tests the condition after having executed the statements within the
loop. Figure 3.5 would clarify the execution of do-while loop still further



This means that do-while  would execute its statements at least once, even if the condition fails for the first 
time. The while, on the other hand will not execute its statements if the condition fails for the first time. This difference is brought about more clearly by the following program.

main( )
{
  while ( 4 < 1 )
    printf ( "Hello there \n") ;
}
 
Here, since the condition fails the first time itself, the printf( ) will
not get executed at all. Let's now write the same program using a
do-while loop.

main( )
{
 do
 {
            printf ( "Hello there \n") ;
      } while ( 4 < 1 ) ;
}

In this program the printf( ) would be executed once, since first the body of the loop is executed and then the condition is tested. 

There are some occasions when we want to execute a loop at least once no matter what. This is illustrated in the following example: 

break and continue are used with do-while just as they would be in a while or a for loop. A break takes you out of the do-while bypassing the conditional test. A continue  sends you straight to the test at the end of the loop. 

The continue Statement : C programing The Loop Control Structure

In some programming situations we want to take the control to the beginning of the loop, bypassing the statements inside the loop, which have not yet been executed. The keyword continue allows us to do this. When continue  is encountered inside any loop, control automatically passes to the beginning of the loop.
A continue is usually associated with an if. As an example, let's consider the following program.

main( )
{
      int   i, j ;

      for ( i = 1 ; i <= 2 ; i++ )
 {
            for ( j = 1 ; j <= 2 ; j++ )
  {
                  if ( i == j )
    continue ;

                  printf ( "\n%d %d\n", i, j ) ;
  }
 }
}

The output of the above program would be...

1 2 
2 1 

Note that when the value of i equals that of j, the continue statement takes the control to the for loop (inner) bypassing rest of
the statements pending execution in the for loop (inner).

The break Statement: C programing The Loop Control Structure

We often come across situations where we want to jump out of a loop instantly, without waiting to get back to the conditional test. The keyword break  allows us to do this. When break  is encountered inside any loop, control automatically passes to the first statement after the loop. A break is usually associated with an
if. As an example, let’s consider the following example.

Example:  Write a program to determine whether a number is prime or not. A prime number is one, which is divisible only by 1 or itself.

All we have to do to test whether a number is prime or not, is to divide it successively by all numbers from 2 to one less than itself. If remainder of any of these divisions is zero, the number is not a prime. If no division yields a zero then the number is a prime number. Following program implements this logic

main( )
{
      int   num, i ;

      printf ( "Enter a number " ) ;
      scanf ( "%d", &num ) ;

      i = 2 ;
      while ( i <= num - 1 )
 {
            if ( num % i == 0 )
  {
                  printf ( "Not a prime number" ) ;
   break ;
  }
  i++ ;
 }
if ( i == num )
            printf ( "Prime number" ) ;
}

In this program the moment num % i turns out to be zero, (i.e. num is exactly divisible by i) the message “Not a prime number” is printed and the control breaks out of the while loop. Why does the program require the if  statement after the while  loop at all? Well, there are two ways the control could have reached outside
the while loop:

(a)  It jumped out because the number proved to be not a prime.
(b)  The loop came to an end because the value of i became equal to num.

When the loop terminates in the second case, it means that there was no number between 2 to num - 1 that could exactly divide num. That is, num is indeed a prime. If this is true, the program should print out the message “Prime number”. The keyword break, breaks the control only from the while  in which it is placed. Consider the following program, which illustrates this fact.

main( )
{
      int  i = 1 , j = 1 ;

      while ( i++ <= 100 )
 {
            while ( j++ <= 200 )
  {
                  if ( j == 150 )
    break ;
   else
                        printf ( "%d %d\n", i, j ) ;
  }
 }
}

In this program when j equals 150, break takes the control outside the inner while only, since it is placed inside the inner while.

The Odd Loop : C programming The Loop Control Structure

 The loops that we have used so far executed the statements within them a finite number of times. However, in real life programming one comes across a situation when it is not known beforehand how many times the statements in the loop are to be executed. This situation can be programmed as shown below: 

/* Execution of a loop an unknown number of times */
main( )
{
      char  another ;
      int  num ;
 do
 {
            printf ( "Enter a number " ) ;
            scanf ( "%d", &num ) ;
            printf ( "square of %d is %d", num, num * num ) ;
            printf ( "\nWant to enter another number y/n " ) ;
            scanf ( " %c", &another ) ;
      } while ( another == 'y' ) ;
}

And here is the sample output...

Enter a number 5
square of 5 is 25
Want to enter another number y/n y
Enter a number 7
square of 7 is 49
Want to enter another number y/n n

In this program the do-while loop would keep getting executed till the user continues to answer y. The moment he answers n, the loop terminates, since the condition ( another == 'y' ) fails. Note that this loop ensures that statements within it are executed at least once even if n is supplied first time itself.Though it is simpler to program such a requirement using a do-while loop, the same functionality if required, can also be accomplished using for and while loops as shown below:

/* odd loop using a for loop */
main( )
{
      char  another = 'y' ;
      int  num ;
      for ( ; another == 'y' ; )
 {
            printf ( "Enter a number " ) ;
            scanf ( "%d", &num ) ;
            printf ( "square of %d is %d", num, num * num ) ;
            printf ( "\nWant to enter another number y/n " ) ;
            scanf ( " %c", &another ) ;
 }
}

/* odd loop using a while loop */
main( )
{
      char  another = 'y' ;
      int  num ;

      while ( another == 'y' )
 {
            printf ( "Enter a number " ) ;
            scanf ( "%d", &num ) ;
            printf ( "square of %d is %d", num, num * num ) ;
            printf ( "\nWant to enter another number y/n " ) ;
            scanf ( " %c", &another ) ;
 }
}
 

Multiple Initialisations in the for Loop : C programing The Loop Control Structure

The initialisation expression of the for loop can contain more than one statement separated by a comma. For example,

for ( i = 1, j = 2 ; j <= 10 ; j++ )

Multiple statements can also be used in the incrementation expression of for loop; i.e., you can increment (or decrement) two or more variables at the same time. However, only one expression is allowed in the test expression. This expression may contain several conditions linked together using logical operators.
Use of multiple statements in the initialisation expression also demonstrates why semicolons are used to separate the three expressions in the for loop. If commas had been used, they could not also have been used to separate multiple statements in the initialisation expression, without confusing the compiler.

Nesting of Loops

The way if statements can be nested, similarly whiles and fors can also be nested. To understand how nested loops work, look at the program given below:

/* Demonstration of nested loops */
main( )
{
      int   r, c, sum ;
      for ( r = 1 ; r <= 3 ; r++ )  /* outer loop */
 {
            for ( c = 1 ; c <= 2 ; c++ )  /* inner loop */
  {
                  sum = r + c ;
                  printf ( "r = %d c = %d sum = %d\n", r, c, sum ) ;
  }
 }
}

When you run this program you will get the following output:

r = 1 c = 1 sum = 2
r = 1 c = 2 sum = 3
r = 2 c = 1 sum = 3
r = 2 c = 2 sum = 4
r = 3 c = 1 sum = 4
r = 3 c = 2 sum = 5

Here, for each value of r the inner loop is cycled through twice, with the variable c taking values from 1 to 2. The inner loop
terminates when the value of c exceeds 2, and the outer loop terminates when the value of r exceeds 3. 
As you can see, the body of the outer for loop is indented, and the body of the inner for  loop is further indented. These multiple
indentations make the program easier to understand.  Instead of using two statements, one to calculate sum and another to print it out, we can compact this into one single statement by saying:

printf ( "r = %d c = %d sum = %d\n", r, c, r + c ) ;

The way for  loops have been nested here, similarly, two while loops can also be nested. Not only this, a for loop can occur within a while loop, or a while within a for. 

The for Loop

Perhaps one reason why few programmers use while is that they are too busy using the for, which is probably the most popular looping instruction. The for allows us to specify three things about a loop in a single line: 

(a)  Setting a loop counter to an initial value.
(b)  Testing the loop counter to determine whether its value has reached the number of repetitions desired.
(c)  Increasing the value of loop counter each time the program segment within the loop has been executed.
The general form of for statement is as under:

for ( initialise  counter ; test  counter ; increment  counter )
{
  do this ;
      and this ; 
  and this ;
}

Let us write down the simple interest program using for. Compare this program with the one, which we wrote using while. The flowchart is also given below for a better understanding.



/* Calculation of simple interest for 3 sets of p, n and r */ 
main ( )
{
  int   p, n, count ;
  float   r, si ;
 
  for ( count = 1 ; count <= 3 ; count = count + 1 )
 {
    printf ( "Enter values of p, n, and r " ) ;
    scanf ( "%d %d %f", &p, &n, &r ) ;

    si = p * n * r / 100 ;
    printf ( "Simple Interest = Rs.%f\n", si ) ;
 }


If this program is compared with the one written using while, it can be seen that the three steps—initialization, testing and incrementation—required for the loop construct have now been incorporated in the for statement.
Let us now examine how the for statement gets executed:

  When the for statement is executed for the first time, the value of count is set to an initial value 1.

  Now the condition count <= 3 is tested. Since count is 1 the condition is satisfied and the body of the loop is executed for the first time.

−  Upon reaching the closing brace of for, control is sent back to the for statement, where the value of count gets incremented by 1.

−  Again the test is performed to check whether the new value of count exceeds 3.

−  If the value of count  is still within the range 1 to 3, the statements within the braces of for are executed again.

−  The body of the for loop continues to get executed till count doesn’t exceed the final value 3. 

−  When count reaches the value 4 the control exits from the loop and is transferred to the statement (if any) immediately after the body of for.

The following figure would help in further clarifying the concept of execution of the for loop.



It is important to note that the initialization, testing and incrementation part of a for loop can be replaced by any valid expression. Thus the following for loops are perfectly ok.

for ( i = 10 ; i ; i -- )
  printf ( "%d", i ) ;
for ( i < 4 ; j = 5 ; j = 0 )
  printf ( "%d", i ) ;
for ( i = 1; i <=10 ; printf ( "%d",i++ )
 ;
for ( scanf ( "%d", &i ) ; i <= 10 ; i++ )
  printf ( "%d", i ) ;

Let us now write down the program to print numbers from 1 to 10 in different ways. This time we would use a for loop instead of a while loop.

(a)  main( )
{
     int   i ;
     for ( i = 1 ; i <= 10 ; i = i + 1 )
           printf ( "%d\n", i ) ;
}

 Note that the initialisation, testing and incrementation of loop counter is done in the for statementitself.Instead of i = i + 1, the statements i++ or i += 1 can also be used.  Since there is only one statement in the body of the for loop, the pair of braces have been dropped. As with the while, the default scope of for is the immediately next statement after for.

(b)  main( )
{
     int   i ;
     for ( i = 1 ; i <= 10 ; )
 {
           printf ( "%d\n", i ) ;
           i = i + 1 ;
 }
}

 Here, the incrementation is done within the body of the for loop and not in the for statement. Note that inspite of this the semicolon after the condition is necessary. 

(c)  main( )
{
     int   i = 1 ;
     for ( ; i <= 10 ; i = i + 1 )
           printf ( "%d\n", i ) ;
}
Here the initialisation is done in the declaration statement itself, but still the semicolon before the condition is necessary.

(d)  main( )
{
     int   i = 1 ;
     for ( ; i <= 10 ; )
 {
           printf ( "%d\n", i ) ;
           i = i + 1 ;
 }
}
Here, neither the initialisation, nor the incrementation is done in the for statement, but still the two semicolons are necessary.

(e)  main( )
{
     int   i ;
     for ( i = 0 ; i++ < 10 ; )
           printf ( "%d\n", i ) ;
}

 Here, the comparison as well as the incrementation is done through the same statement, i++ < 10. Since the ++ operator comes after i firstly comparison is done, followed by incrementation. Note that it is necessary to initialize i to 0. 

(f)  main( )
{
     int   i ;
     for ( i = 0 ; ++i <= 10 ; )
           printf ( "%d\n", i ) ;
}

Here, both, the comparison and the incrementation is done through the same statement, ++i <= 10. Since ++ precedes i firstly incrementation is done, followed by comparison.
Note that it is necessary to initialize i to 0.

More Operators

There are variety of operators which are frequently used with while. To illustrate their usage let us consider a problem wherein numbers from 1 to 10 are to be printed on the screen. The program for performing this task can be written using while  in the following different ways:

(a)  main( )
{
     int   i = 1 ;
     while ( i <= 10 )
 {
           printf ( "%d\n", i ) ;
           i = i + 1 ;
 }
}
(b)  main( )
{
  int   i = 1 ;
     while ( i <= 10 )
 {
           printf ( "%d\n", i ) ;
  i++ ;
 }
}

 Note that the increment operator ++ increments the value of i by 1, every time the statement i++ gets executed. Similarly, to reduce the value of a variable by 1 a decrement operator -- is also available. 
However, never use n+++ to increment the value of n by 2, since C doesn’t recognize the operator +++.

(c)  main( )
{
     int   i = 1 ;
     while ( i <= 10 )
 {
           printf ( "%d\n", i ) ;
           i += 1 ;
 }
}

 Note that +=  is a compound assignment operator. It increments the value of i by 1. Similarly, j = j + 10 can also be written as j += 10. Other compound assignment operators are -=, *=, / = and %=.

(d)  main( )
{
     int  i = 0 ;
     while ( i++ < 10 )
printf ( "%d\n", i ) ;
}

 In the statement while ( i++ < 10 ), firstly the comparison of value of i with 10 is performed, and then the incrementation of i takes place. Since the incrementation of i happens after its usage, here the ++ operator is called a post-incrementation operator. When the control reaches printf ( ),  i has already been incremented, hence i must be initialized to 0. 

(e)  main( )
{
     int  i = 0 ;
     while ( ++i <= 10 )
        printf ( "%d\n", i ) ;
}

 In th statement    e  while ( ++i <= 10 ), firstly incrementation of i takes place, then the comparison of value of i with 10 is performed. Since the incrementation of i happens before its usage, here the ++ operator is called a pre- incrementation operator

Tips and Traps

The general form of while is as shown below:

initialise loop counter ;
while ( test loop counter using a condition )
{
  do this ;
  and this ;
  increment loop counter ;
}

Note the following points about while...

−  The statements within the while loop would keep on getting executed till the condition being tested remains true. When the condition becomes false, the control passes to the first statement that follows the body of the while loop.

In place of the condition there can be any other valid expression. So long as the expression evaluates to a non-zero value the statements within the loop would get executed.

−  The condition being tested may use relational or logical operators as shown in the following examples:

 while ( i <= 10 )
while ( i >= 10 && j <= 15 ) 
while ( j > 10 && ( b < 15 || c < 20 ) )

−  The statements within the loop may be a single line or a block of statements. In the first case the parentheses are optional. For example,

 while ( i <= 10 )
     i = i + 1 ;
is same as

 while ( i <= 10 )
{
     i = i + 1 ;
}

−  As a rule the while must test a condition that will eventually become false, otherwise the loop would be executed forever, indefinitely.

 main( )

     int   i = 1 ;
     while ( i <= 10 )
        printf ( "%d\n", i ) ; 
}
This is an indefinite loop, since i remains equal to 1 forever. The correct form would be as under:

 main( )
{
     int   i = 1 ;
     while ( i <= 10 )
 {
           printf ( "%d\n", i ) ;
           i = i + 1 ;
 }
}

−  Instead of incrementing a loop counter, we can even decrement it and still manage to get the body of the loop executed
repeatedly. This is shown below:

 main( )
{
     int   i = 5 ;
     while ( i >= 1 )
 {
           printf ( "\nMake the computer literate!" ) ;
           i = i - 1 ;
 }
}

−  It is not necessary that a loop counter must only be an int. It can even be a float.

 main( )
{
     float   a = 10.0 ;
     while ( a <= 10.5 )
 {
           printf ( "\nRaindrops on roses..." ) ;
           printf ( "...and whiskers on kittens" ) ;
           a = a + 0.1 ;
 }
}

−  Even floating point loop counters can be decremented. Once again the increment and decrement could be by any value, not necessarily

What do you think would be the output of the following
program?

 main( )
{
     int   i = 1 ;
     while ( i <= 32767 )
 {
           printf ( "%d\n", i ) ;
           i = i + 1 ;
 }
}

 No, it doesn’t print numbers from 1 to 32767. It’s an indefinite loop. To begin with, it prints out numbers from 1 to 32767. After that value of i is incremented by 1, therefore it tries to become 32768, which falls outside the valid integer range, so it goes to other side and becomes -32768 which would certainly satisfy the condition in the while. This process goes on indefinitely.
−  What will be the output of the following program?

 main( )
{
     int   i = 1 ;
     while ( i <= 10 ) ;
 {
           printf ( "%d\n", i ) ;
           i = i + 1 ;
 }
}
This is another indefinite loop, and it doesn’t give any output at all. The reason is, we have carelessly given a ; after the while. This would make the loop work like this...

 while ( i <= 10 )
 ;
{
     printf ( "%d\n", i ) ;
     i = i + 1 ;
}

 Since the value of i is not getting incremented the control would keep rotating within the loop, eternally. Note that enclosing printf( ) and i = i +1 within a pair of braces is not an error. In fact we can put a pair of braces around any individual statement or set of statements without affecting the execution of the program.