3. Control – C Programming Essentials

Chapter 3. Control

The purpose of this chapter is to explain the flow of control that the C programming language supports. Statements in a sequential program are normally executed one after the other [Refer to Sequence Construct, Fig. 1.3 (a)]. This is also called sequential flow of control. However, it might be often desirable to alter this sequential flow to provide for a choice of action or a repetition of action [Refer to Selection Constructs, Fig. 1.3 (b), and Repetition Constructs, Fig. 1.3 (c)]. We can make a selection among alternative actions using the if, the if-else, and the switch statements. The while, for, and do-while statements help us to perform iterative actions. In addition, break and continue can be used in conjunction with switch, while, for and do-while to ease logic overhead. The infamous goto keyword will be discussed, but not encouraged since it is considered to be an impairment to structured programming. In this chapter, we shall be discussing the above control statements in turn.

The if Statement

The if construct is used to execute a segment of code conditionally. The segment of code is specified in the following sections by the notation <Actions_block_i> referring to the ith block. Action blocks may consist of a single statement or multiple statements. A multiple-statement action block must be enclosed within braces, while for single-statement Actions_block, the braces are optional. Like any other C statement, the statements in the Actions_block are terminated by a semicolon.

First Form (if Statement)

The general form of an if construct is:

if (expression)
       <Actions_block>

Thus, the if construct consists of the keyword if, followed by an expression in parenthesis, it is followed by a block of actions to be performed if the expression is true.

In a strange case, we might choose to keep the actions block empty, where we terminate the if statement by a semicolon, or a pair of opening and closing braces, without any statement enclosed.

To execute an if statement, we first determine whether the expression is true or false. If the expression is true, the statement/(s) in the Actions_block is/are executed and the execution proceeds to the statement immediately following the Actions_block. However, if the expression is evaluated as false (a zero value), the statement/(s) in the Actions_block is/are skipped and execution jumps to the statement immediately following the Actions_block. A set of examples is presented below to illustrate the use of the if construct.

Example . 

Program Ch03n01.c

/*Program to illustrate if statement*/
#include <stdio.h>

int main()
{
  int x,y;

  x=3;
  y=5;
  if(x<y)
    y=x++;
  printf("\n x = %d, y = %d.\n",x,y);
  return 0;
}
End Program
EXECUTION

  x = 4, y = 3.

Explanation: The value of y becomes 3 since the old value of x is assigned to y, and the value of x becomes 4 since the value of x is incremented by 1.

Example . 

Program Ch03n02.c

#include <stdio.h>

int main()
{
  int x=1,y=4,p;

  p=((x<=1)&&(y==3));
  if(p)
    x++;
  printf("\nx=%d, y=%d, p=%d.\n",x,y,p);
  return 0;
}
End Program
EXECUTION

  x=1, y=4, p=0.

Explanation: The value of p becomes zero since the expression results in false. The incerment in the if statement is ignored as the value of p is zero, which is false. The value of x remains as 1.

Example . 

Program Ch03n03.c

 #include <stdio.h>

 int main()
 {
    int x='A';        /*ASCII value of 'A' is 65*/
    int y=2,k;

    k=x>>y;
     if(k)
              ++x;
    printf("\nx=%d, y=%d, k=%d.\n",x,y,k);
    return 0;
 }
End Program
EXECUTION

  x=66, y=2, k=16.

Explanation: The value of k is 16 since x is shifted right twice (divided by 4). The variable k contains the integer part after division. The value of x becomes 66 since k is 16 (non-zero value), and hence true.

Example . 

Program Ch03n04.c

#include <stdio.h>

int main()
{
  int Income=6000,Allowance=1000;

  if(Income<6000)
  {
    Allowance=3000;
    printf("\nAllowance Increased.");
  }
  printf("\nIncome=%d\nAllowance=%d.\n",Income,Allowance);
  return 0;
}
End Program
EXECUTION

Income=6000
Allowance=1000.

Explanation: Allowance contains 1000 since the condition is false.

Example . 

Program Ch03n05.c

/*Program to print the largest of two numbers*/
#include <stdio.h>

int main()
{
   int x,y;

   printf("Enter two numbers: \n");
   scanf("%d%d",&x,&y);
   if(x>=y)
      printf("\n%d is the greater number.\n",x);
   if(x<y)
      printf("\n%d is the greater number.\n",y);
   return 0;
}
End Program
EXECUTION (Boldface represents user input)

Enter two numbers:
10 20

20 is the greater number.

Example . 

Program Ch03n06.c

/*Program to print the largest of three numbers*/
#include <stdio.h>

int main()
{
   int a,b,c;

   printf("Enter three numbers: \n");
   scanf("%d%d%d",&a,&b,&c);
   if(a>=b && a>=c)
        printf("\n%d is the largest number.\n",a);
   if(b>=a && b>=c)
        printf("\n%d is the largest number.\n",b);
   if(c>=a && c>=b)
        printf("\n%d is the largest number.\n",c);
  return 0;
}
End Program
EXECUTION (Boldface represents user input)

Enter three numbers:
10 25 15

25 is the largest number.

Example . 

Program Ch03n07.c

/*Program to let the user guess a number between 1 and 10
and print a message if the user has guessed correctly,
the number which is stored in the program as a magic number*/
#include <stdio.h>
int main()
{
   int Magic=6,Guess;

   printf("Guess a number between 1 and 10: \n");
   scanf("%d",&Guess);
   if(Guess==Magic)
        printf("\nYour guess is correct.\n");
   if(Guess!=Magic)
        printf("\nYou have made a wrong guess.\n");
   return 0;
}
End Program
EXECUTION (Boldface represents user input)

Guess a number between 1 and 10:
6

Your guess is correct.

Let us now consider an examination where a student has to appear for three papers. The problem is to write a C program to find out the student’s grades according to the following rules:

  1. If any of the marks is less than or equal to 40, grade is ‘F’.

  2. If each mark is less or equal to 60 and the total is greater than 120, then the grade is ‘O’.

  3. If each mark is less or equal to 80 and the total marks are not less than 180, then the grade is ‘S’.

  4. If total marks is larger than 240, then the grade is ‘E’.

Example . 

Program Ch03n08.c

 /*Program for Grade computation*/

 #include <stdio.h>
 int main()
 {

   int m1,m2,m3,Total;
   char Grade;

   printf("Enter three marks:\n");
   scanf("%d%d%d",&m1,&m2,&m3);
   Total=m1+m2+m3;

   if(m1<=40 || m2<=40 || m3<=40)
   {
        Grade='F';
   }

   if(m1<=60 && m2<=60 && m3<=60 && Total>120)
   {
        Grade='O';
   }
   if(m1<=80 && m2<=80 && m3<=80 && Total>180)
   {
        Grade='S';
   }
   if(Total > 240)
   {
        Grade='E';
   }
   printf("\nm1=%d,m2=%d,m3=%d.\n",m1,m2,m3);
   printf("\nTotal=%d,Grade is %c.\n",Total,Grade);
   return 0;
}
End Program
EXECUTION (Boldface represents user input)

Enter three marks:
85 81 90

m1=85,m2=81,m3=90.
Total=256,Grade=E.

We now move on to computing the absolute value of an integer. Mathematically, the absolute value of a number is the same as the number, with exclusion of the sign if the number is negative. The solution can be worked out as follows:

Example . 

Program Ch03n09.c

/*Program to print the absolute value of a number*/
#include <stdio.h>

int main()
{
   int x;

   printf("Enter the number:\n");
   scanf("%d",&x);
   if(x<0)
         x=-x;
   printf("\nThe absolute value of the number is %d.\n",x);
   return 0;
}
End Program
EXECUTION (Boldface represents user input)

Enter the number:
-3

The absolute value of the number is 3.

Second Form (ifelse Statement)

Another form of the if statement is given below:

if (expression)
   <Actions_block_1>
else
   <Actions_block_2>

When this form of the if statement is executed, the compiler first determines whether the expression is true or false. If the expression is true, we execute <Actions_block_1> and proceed to the statement immediately following <Actions_block_2>. Thus, <Actions_block_2> will not be executed. However, if the expression is false, the compiler executes the statement/(s) in <Actions_block_2> and then proceeds to the statement immediately following it. In this case, we do not execute <Actions_block_1>. We illustrate this by the following examples.

Example . 

Program Ch03n10.c

/*Program to illustrate if-else statement*/
#include <stdio.h>

int main()
{
  int BasicPay=2000,Allowances=4000;
  int Tax,NetPay,GrossPay;
  if(BasicPay>2000)
  {
    Tax=500;
    printf("\nTaxed Rs 500.");
  }
  else{
    Tax=250;
    printf("\nTaxed Rs 250.");
  }
  GrossPay=BasicPay+Allowances;
  NetPay=GrossPay-Tax;
  printf("\nGross Pay=Rs %d.\nNet Pay=Rs %d.\n",GrossPay,NetPay);
  return 0;
}
End Program
EXECUTION

Taxed Rs 250.
Gross Pay=Rs 6000.
Net Pay=Rs 5750.

Example . 

Program Ch03n11.c

 /*Program to print the largest of two numbers using if-else construct*/
 #include <stdio.h>

 int main()
 {
    int x,y;

    printf("Enter two numbers: \n");
    scanf("%d%d",&x,&y);
    if(x>=y)
    printf("\n%d is the greater number.\n",x);
    else
    printf("\n%d is the greater number.\n",y);
    return 0;
 }
 End Program
EXECUTION (Boldface represents user input)

Enter two numbers:
10 20
20 is the greater number.

Suppose we want to find out whether a particular number is odd or even. An easy way to solve this problem is by checking if the number is divisible by 2. The modulus-division operator can be used in this regard as follows:

Example . 

Program Ch03n12.c

 /*Program to find out if a number is odd or even*/
 #include <stdio.h>

 int main()
 {
    int x;

    printf("Enter the number:\n");
    scanf("%d",&x);
    if(x%2)
       printf("\nThe number is odd.\n");
    else
       printf("\nThe number is even.\n");
    return 0;
 }
End Program
 EXECUTION (Boldface represents user input)

Enter the number:
7
The number is odd.

Another way of solving the above problem is by use of the bitwise AND operator. If a number is AND-masked by 1, the result will be zero if and only if the least significant bit in the number is zero. The binary representation of a number divisible by 2 must always have a zero in its least significant bit. This technique is used in the following version of the earlier program.

Example . 

Program Ch03n13.c

 /*Program to find out of a number is odd or even using bitwise AND*/
 #include <stdio.h>

 int main()
 {
    int x;

    printf("Enter the number:\n");
    scanf("%d",&x);
    if(x&1)
           printf("\nThe number is odd.\n");
    else
           printf("\nThe number is even.\n");
    return 0;
 }
End Program
EXECUTION (Boldface represents user input)

Enter the number:
6
The number is even.

The following example program tests whether a given number read in from the user is positive, negative, or zero, and prints a message accordingly.

Example . 

Program Ch03n14.c

 /*Program to test a number for positive, negative or zero value*/
 #include <stdio.h>

 int main()
 {
    int x;

    printf("Enter the number to test: \n");
    scanf("%d",&x);
    if(x)
    {
        printf("\nThe input is a non-zero value.\n");
        if(x<0)
            printf("The number is negative.\n");
        else
            printf("The number is positive.\n");
    }
    else
         printf("\nThe number is zero.\n");
    return 0;
}
End Program
EXECUTION (Boldface represents user input)

Enter the number to test:
-12
The input is a non-zero value.
The number is negative.

Explanation: The condition if(x) tests whether the value of x is non-zero. If it has a non-zero value, the expression evaluates to true and the program carries out the action in the outer if block. One of the actions includes another if-else construct. This construct is tackled in the same fashion as the outer one. Here, the condition is whether x is negative. If so, the program prints that the value is negative; otherwise, it prints that the value is positive. However, if the outer if had evaluated to false, then the value of x is zero, the outer else is entered, and a message is printed indicating that the value of x is zero.

Example . 

Program Ch03n15.c

 /*Program to find out the heavier coin from a set of four coins, the
 remaining three having identical weights.*/
 #include <stdio.h>

 int main()
 {
    int a,b,c,d,K,M;

    printf("Enter the weights for four coins (A,B,C,D):\n");
    scanf("%d%d%d%d",&a,&b,&c,&d);
    K=a+b;
    M=c+d;
    printf("\nThe heavier coin is ");
    if(K>M)
        (a>b)?printf("A.\n"):printf("B.\n");
    else
        (c>d)?printf("C.\n"):printf("D.\n");
    return 0;
 }
 End Program
EXECUTION (Boldface represents user input)

Enter the weights for four coins (A,B,C,D):
15 15 22 15
The heavier coin is C.

Extended Form (Nested if Statements)

Since an if structure is a statement and if blocks can contain statements, nested if blocks immediately follow as a possibility. A nested if is a statement that is the object of either an if or an else. For example, if the following skeleton construct is considered, it will contain two blocks – the inner if-else contained within the else block of the outer if-else statement.

if(expression1)
      <Actions_block_1>
else{
      if(expression2)
            <Actions_block_2>
      else
            <Actions_block_3>
}

At the start, the outer if statement executes. If expression1 evaluates to true, control transfers to <Actions_block_1>, executes the statements in it, and then skips the outer else and proceeds to the statement immediately following the outer else. However, if expression1 evaluates to false, the outer else block is entered and the inner if statement executes. Here, <Actions_block_2> or <Actions_block_3> executes according to whether expression2 evaluates to true or false.

In the above structure, there is no confusion about the inner if statement. However, consider the following structure:

if(expression1)
if(expression2)
<Actions_block_1>
else
<Actions_block_2>

Since if statements are not explicitly nested using braces, there is an ambiguity as regarding the associativity of the else block. There is confusion as to which if then else is associated with. In other words, the structure can be interpreted in two different ways.

if(expression1){
   if(expression2){
      <Actions_block_1>
   }
   else{
      <Actions_block_2>
   }
}
          (A)
if(expression1){
   if(expression2){
      <Actions_block_1>
   }
}
else{
   <Actions_block_2>
}
          (B)

The C language interprets nested if structures and matches else’s in the absence of explicit braces by a simple rule. It links the else to the closest preceding if that is not already associated with an else statement. In the above example, the rule matches the mismatched else with the second if statement, i.e., the closest preceding if that is not already matched with an else. Thus, (A) will be the correct interpretation for the preceding example, and not (B). If, however, we want to associate the else to the first if statement, we must use explicit braces as in (B) to force a different evaluation scheme.

We now illustrate nested if-else constructs with the following examples.

Example . 

Program Ch03n16.c

 /*Program to illustrate nested if-else*/
#include <stdio.h>

int main()
{
   int x=5;

   if(x<2)
   {
         x--;
   }
   else{
        if(x<4)
           x++;
    else{
           if(x<6)
                  x+=2;
           else
                  x+=5;
    }
  }
  printf("\nx=%d.\n",x);
  return 0;
}
End Program
EXECUTION

X=7.

Explanation: Since x is 5, x<2 evaluates to false, and the outermost else block is entered. Here, the inner if statement evaluates x<4 to false, and likewise control enters the associated else. The innermost if finds the condition x<6 to be true and executes the statement x+=2, and x evaluates to 7. The innermost else is skipped since the associated if was executed and control transfers outside the entire ifhierarchy to the printf function, where the value of x is printed as 7.

The above example is an example of the if-else-if ladder structure and can be rewritten as:

Example . 

Program Ch03n17.c

 /*Program to illustrate if-else-if ladder*/
 #include <stdio.h>

 int main()
 {

    int x=5;

    if(x<2)
      x--;
    else
      if(x<4)
         x++;
    else
      if(x<6)
         x+=2;
    else
      x+=5;
    printf("\nx=%d.\n",x);
    return 0;
 }
 End Program
EXECUTION

X=7.

Explanation: In the absence of explicit braces, the “associate else’s with the closest preceding unmatched if” rule is applied, and the if hierarchy interprets the same as in Program Ch03n16.c. The usage of such an implicit structure is simply to avoid deeply indented hierarchies. If the hierarchies are nested too deep, the code becomes unreadable. In addition, such deep nestings are not supported for all C compilers. In such a case, the switch statement is recommended as an alternative.

The above structure can be generalized by the following general construct for the if–else ladder:

if(expression1)
      <Actions_block_1>
else
if(expression2)
      <Actions_block_2>
else
if(expression3)
      <Actions_block_3>
      ...
      ...
else
      <Actions_block_n>

To execute this construct, we find the first expression, if any, that evaluates to true. If expression j is the first true expression, we execute the actions associated with it, i.e., <Actions_block_j> for any j in [1, n]. All other action blocks are skipped and the program exits the construct. However, if no expression is true, we execute <Actions_block_n> and proceed to the statement following the ladder. The following example uses the if–else ladder hierarchy:

Example . 

Program Ch03n18.c

 #include <stdio.h>

 int main()
 {

    int x=7;

    if(x--<2)
           x=x;
    else if(x--<4)
           x=2*x;
    else if(x--<6)
           x=3*x;
    else
           x=4*x;
    printf("\nx=%d.\n",x);
    return 0;
 }
 End Program
EXECUTION

X=12.

The switch Statement

The C language provides an easy-to-read control mechanism in the form of the switch construct. The switch construct can be regarded as a special instance of the if-else-if ladder. The general form of the switch statement is:

switch(integer_expression1){
      case constant_1:
            <Actions_block_1>
      case constant_2:
            <Actions_block_2>
            ...
            ...
      case constant_n:
            <Actions_block_n>
}

The switch statement consists of the keyword switch, followed by an expression in parentheses and a number of cases enclosed in braces. Here, case is a keyword, and each case corresponds to equality checkpoints within the switch construct.

To execute a switch statement, the compiler first evaluates the integer expression. Then, the evaluated value of the integer expression is compared with constant_1, constant_2, ..., constant_n, where constant_j’s are integer constants. The value determines which statements are to be executed.

As an aside, the expression might evaluate to a character and, likewise, the constants following the case keywords might be character constants. This is so, because characters are converted to integers in C.

Continuing from where we left off, if the value of the expression equals constant_i, execution begins with <Actions_block_i> and continues executing <Actions_block_i+1> through <Actions_block_n>. If, however, the value does not equal any of the constants, execution begins with the statement immediately following the terminating brace of the switch statement. The usage of surrounding braces is optional for the actions blocks for switch statements even in the presence of multi-statement action blocks.

The switch construct can be considered to be an if-else-if ladder structure with only equality checks in the expressions, with the extra feature that once an equality condition is satisfied, all conditions following it are not checked and the blocks in them executed.

There is another form of the switch statement using a special clause, default, which corresponds to the else. Similar to the else, the block following default is executed if the value of the evaluated expression does not equal any of the constants represented by the cases preceding default. The general form of the switch construct using the default keyword is:

switch(integer_expression1){
      case constant_1:
            <Actions_block_1>
      case constant_2:
            <Actions_block_2>
            ...
      case constant_n:
            <Actions_block_n>
      default:
            <Actions_block_default>
}

While using default clauses in switch statements, it is important to note that the default clause need not be the last clause in a switch.

Recalling that a block is a group of statements, a block may have other blocks nested in it. C allows indefinite nesting of blocks (restricted only by the compiler). This is also true for the switch statement. If one switch statement is nested within another, the configuration is a nested switch statement hierarchy as in the case of nested if-else statements.

The use of the switch statement in control is shown in the following examples:

Example . 

Program Ch03n19.c

 /*Program to illustrate switch statement*/
 #include <stdio.h>

 int main()
 {
    int x=3;

    switch(x)
    {
       case 1:
           printf("*");
       case 2:
           printf("**");
       case 3:
           printf("***");
       case 4:
           printf("****");
    }
    printf("\n");
    return 0;
 }
 End Program
EXECUTION

*******

Explanation: Since the expression in switch evaluates to 3, case 3 is entered and the printf function prints 3 asterisks. Note that, case 4 executes after case 3, and 4 asterisks are printed by the printf function in the clause. Hence, a total of 7 asterisks are printed and the output follows.

The above program can be easily modified to print the following pattern of asterisks, and the program is left to the reader as an exercise.

*
**
***
****

Example . 

Program Ch03n20.c

 /*Program to print a pattern of numbers*/
 #include <stdio.h>

 int main()
 {
    int x=1;

    switch(x)
    {
       case 1:
           printf("1\n");
       case 2:
           printf("12\n");
       case 3:
           printf("123\n");
       case 4:
           printf("1234\n");
    }
    return 0;
 }
 End Program
EXECUTION

1
12
123
1234

We will now consider the problem of checking whether an integer within a given range is even or not. The switch statement can be used to write a restricted version of a solution. The problem is to read an integer from the keyboard and print the message indicative of whether the number is even. The reader can try running the following program with valid inputs and check the results.

Example . 

Program Ch03n21.c

/*Program to check whether an integer is even*/
#include <stdio.h>

int main()
{
  int x;

  printf("Enter a number between 1 and 10:\n");
  scanf("%d",&x);
  switch(x)
  {
     case 2:
     case 4:
     case 6:
     case 8:
         printf("\nThe number is even.\n");
  }
  return 0;
}
End Program
EXECUTION (Boldface represents user input)

Enter a number between 1 and 10:
2

The number is even.

Explanation: The switch statement used contains three case clauses without any statement in the corresponding blocks. Whenever x equals either of 2, 4, 6, or 8, execution continues to the printf function call in the last clause. For other values of x, no equality clause satisfies and the switch is exited without entering any case blocks.

More examples with the switch will be presented later in this chapter when we discuss the break keyword. For now, we move on to the repetition constructs for, while and do-while.

The for Statement

It is often desirable to repeat certain sections of code in a program. One way of achieving this would be to repeat the appropriate program instructions in the code itself. However, this approach leads to cumbersome programs and is not always feasible. Consider a situation where a program has to print the first thousand even numbers. It is certainly not feasible to write five thousand identical fragments of code to handle the task. We now move on to the for keyword as a mechanism to write repetition constructs.

The general form of the for statement is:

for(expression1;expression2;expression3)
         <Actions_block>

The for statement consists of the keyword for followed by three expressions, terminated by semicolons, in parenthesis. An Actions_block follows. The Actions_block must be enclosed in braces if it consists of multiple statements. The first expression, expression1, is used to initialize the loop; expression2 is tested for each repetition; and expression3 is used to update the loop. The usage of expressions is optional and they can be removed without error. However, the semicolon separators cannot be removed. Let us move on to tracing the execution of the for loop.

The first time the for statement executes, expression1 is evaluated. If the expression is missing, then no initialization occurs. The second expression is treated as a condition for the loop to be executed and is, thus, evaluated. If it is non-zero (true), then the Actions_block executes. A missing expression2 is assumed to evaluate to true. After the block has been executed, control passes to the beginning of the for construct. Now, expression3 is evaluated, if present, and then expression2 is evaluated. A similar sequence of events occurs and this process continues until expression2 is false. It is important to note that expression1 is evaluated only once, at the beginning of the loop, and is skipped for subsequent passes.

An important thing to note about for loops is that as the condition test is performed at the top of the loop (i.e., at the beginning of each iteration of the loop), the code inside the loop may not be executed at all if the condition is false to begin with. If the Actions_block is empty, for must either have an empty set of braces or a semicolon following the statement.

To illustrate the use of for as a repetition construct, let us move on to an example program to compute the sum of integers from 1 to 10.

Example . 

Program Ch03n22.c

/*Program to compute the sum of integers from 1 to 10*/

#include <stdio.h>

int main()
  {
  int i,Sum=0;

  for(i=1;i<=10;i++)
  {
    Sum+=i;
  }
  printf("The sum of integers from 1 to 10 is %d.\n",Sum);
  return 0;
}
End Program
EXECUTION

The sum of integers from 1 to 10 is 55.

Explanation: At first, we set the variable Sum to zero. At the start of the for loop, i is initialized to 1. The condition i<=10 is true, and hence, the statement Sum+=i executes. The value of Sum is now 1. Control then returns to the beginning of the for loop and the expression i++ is evaluated. The variable i now becomes 2. The condition tests to true and the loop body executes once more, setting the variable Sum to 3. This process continues for subsequent iterations of the loop body until the condition i<=10 evaluates to false. The value of Sum is then 55 as printed by the printf function.

We shall now move on to writing another program. Let us say we wish to find all magic numbers less than a number read in from the input. An integer is said to be magic if the result is 1 when the digits of the number are added, the digits of the resulting sum are added, and so on, until we arrive at a single digit sum. For example, 307 is a magic number, since 3+0+7=10; 1+0=1, i.e., the resulting sum is 1. Instead of writing the entire summation logic as code, in the following program we take advantage of the fact that the difference between two successive magic numbers is always 9.

Example . 

Program Ch03n23.c

/*Program to generate all magic numbers until an upper bound*/
#include <stdio.h>

int main()
{
  int j,n;

  printf("Enter the upper bound for magic number generation:\n");
  scanf("%d",&n);
  printf("\n");
  for(j=1;j<=n;j+=9)
           printf("%d,",j);
  printf("\n");
  return 0;
}
End Program
EXECUTION (Boldface represents user input)

 Enter the upper bound for magic number generation:
 118
 1,10,19,28,37,46,55,64,73,82,91,100,109,118,

The for statement can be nested to indefinite depths. This can be used for a variety of purposes. In the previous section on the switch statement, pattern-printing programs were demonstrated. The for statement is a powerful tool for writing such programs in a compact and general fashion. The following programs are presented as an example of the usage of nested for loops:

Let us write a program to generate the following pattern

1
12
123
1234
...

Where the number of rows to generate is read in as input.

Example . 

Program Ch03n24.c

/*Program to generate number of rows of a pattern*/
#include <stdio.h>

int main()
{

  int i,j,n;

  printf("Enter the number of rows for pattern generation:\n");
  scanf("%d",&n);
  printf("\n");
  for(i=1;i<=n;i++)
  {
      for(j=1;j<=i;j++)
          printf("%d",j);
      printf("\n");
  }
  return 0;
}
End Program
EXECUTION (Boldface represents user input)

 Enter the number of rows for pattern generation:
 5

 1
 12
 123
 1234
 12345

Explanation: The outer for loop executes n times with i=1,2,...,n for successive iterations. The inner for loop prints i numbers from 1 to i for each iteration of the outer loop. The outer loop then prints a new line and moves on to the next iteration.

We now move on to a slightly more difficult example of pattern generation using nested for loops. The following pattern is to be generated.

            1
        2   3   2
    3   4   5   4   3
4   5   6   7   6   5   4

Example . 

Program Ch03n25.c

 #include <stdio.h>

 int main()
 {
    int i,j,k,l;

    for(i=1;i<=4;i++)
    {
        for(j=1;j<=10-i;j++)
            printf("    ");
        k=i-1;
        for(j=1;j<=i;j++)
            printf("%4d",++k);
        for(j=1;j<i;j++)
            printf("%4d",--k);
        printf("\n");
    }
    return 0;
 }
 End Program
EXECUTION

                                    1
                                2   3   2
                            3   4   5   4   3
                        4   5   6   7   6   5   4

Explanation: The outer for loop executes n times with i=1,2,...,n for successive iterations. In our case n = 4. The inner for loop prints i numbers from 1 to i for each iteration of the outer loop. The outer loop then prints a new line and moves on to the next iteration.

The Comma Operator

The C language uses the comma in two ways. The first uses the comma as a separator, such as in the variable declaration statements. Another use is as an operator in expressions. We shall frequently use the comma operator in for loops, but its use is not restricted only to that construct. A list of expressions separated by commas guarantees that the expressions will be evaluated left to right. The expression using comma operators returns the evaluation of the rightmost expression in the comma-separated list. The following example demonstrates use of the comma operator in a program to find the sum of the first ten natural numbers.

Example . 

Program Ch03n26.c

 /*Program to compute sum of first 10 natural numbers*/
 #include <stdio.h>

 int main()
    {
    int i,Sum;

    for(Sum=0,i=1;i<=10;Sum+=i,i++);

    printf("Sum of the first 10 natural numbers is %d.\n",Sum);
    return 0;
 }
 End Program
EXECUTION

Sum of the first 10 natural numbers is 55.

Explanation: At the first iteration of the for loop, the variables Sum and i are initialized to 0 and 1, respectively. Subsequent iterations then add the next natural number in i to Sum, increments i, and repeats this process until the value of i exceeds ten. Thus, the sum of 10 natural numbers is stored in Sum and printed after the end of the loop.

It is important to note that the comma operator can also be used for a list of expressions in place of the second expression. When placed in the condition part of the for statement, the comma returns the evaluation of the rightmost expression and this value controls the loop execution. The following example uses the comma operator in the condition part of the for statement.

Example . 

Program Ch03n27.c

 /*Program to generate a list of values*/
 #include <stdio.h>

 int main()
 {
    int i,j;

    printf("\n");
    for(i=0,j=20;i<=10,j>0;i++,j--)
           printf("i=%d, j=%d\n",i,j);
    return 0;
 }
 End Program
EXECUTION

i=0, j=20
i=1, j=19
i=2, j=18
i=3, j=17
...
...
i=19, j=1

Explanation: Since there are two expressions i<=10 and j>0 in the condition part of the for statement, the value of the rightmost expression, i.e., j>0, is returned and the loop continues even after the first condition i<=10 is evaluated to be false.

The while Statement

The general form of the while repetition construct is as follows:

while(expression)
         <Actions_block>

The while statement consists of the keyword while, followed by an expression in parenthesis. An Actions_block follows. The Actions_block may contain zero or more statements. The rules for constructing the Actions_block are the same as those in case of the for statement. Let us trace the execution pattern of a while loop.

In a while statement, the expression in parenthesis is tested. If it evaluates to true, the statement/(s) in the Actions_block is/are executed. For the next iteration, the expression is re-evaluated and if true, the body is evaluated again. The loop exits only when the condition is false and execution continues from the statement immediately following the loop. It is possible for a while loop not to execute at all. This will happen if the expression evaluates to false at the top of the loop. The loop does not execute if the condition is false at the beginning. Thus, a while loop executes zero or more times.

To illustrate the use of while as a repetition construct, let us move on to an example program to compute the sum of integers from 1 to 10.

Example . 

Program Ch03n28.c
 /*Program using a while loop to compute the sum of integers from 1 to 10*/
 #include <stdio.h>

 int main()
 {
    int i=1,Sum=0;

    while(i<=10)
    {
           Sum+=i;
           i++;
    }
    printf("The sum of integers from 1 to 10 is %d.\n",Sum);
    return 0;
}
End Program
EXECUTION

The sum of integers from 1 to 10 is 55.

Explanation: At first, we set the variable Sum to zero and i to 1. In the while statement, the expression i<=10 is evaluated. Since the current value of i is 1, the expression is true, causing the statements enclosed within braces to be executed. Here, the value of Sum is set to the sum of the old value of Sum and the value of i. The variable i is incremented and the loop body has been executed once. Now, since i is 2, the conditional expression in the while evaluates to true again and the loop body executes. This process continues until i has the value 11. Now, the expression i<=10 evaluates to false and the body of the loop is skipped. The next statement executed is the one following the while statement block, i.e., the printf statement. Here, the value of Sum is printed as 55.

We shall now move on to writing another program. Let us say we wish to print some powers of 2.

Example . 

Program Ch03n29.c

 /*Program to print powers of 2*/
 #include <stdio.h>

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

    while(++i<=10)
           printf("%d,",Power*=2);
    printf("\n");
    return 0;
 }
 End Program
EXECUTION

2,4,8,16,32,64,128,256,512,

Explanation: As long as the value of the expression ++i is less than or equal to 10, the body of the while loop is executed. The expression Power*=2 is evaluated. This multiplies 2 with the old value of Power and assigns it to Power. So, the first time the loop executes, Power is set to 2*1=2, and the printf function prints the value of Power as 2. This continues for 8 more times, and each time Power is multiplied by 2 and printed. This causes the powers of 2 to be printed as shown in the execution section.

The next example program computes the sum of the cubes from 1 to 10.

Example . 

Program Ch03n30.c

 /*Program to compute sum of the cubes of 1 to 10 (13+23+33+43+...+103)*/
 #include <stdio.h>

 int main()
 {
    int i,Sum=0;

    i=1;
    while(i<=10)
    {
           Sum+=i*i*i;
           i++;
    }
    printf("\nThe sum of the cubes is %d.\n",Sum);
    return 0;
 }
 End Program
EXECUTION

The sum of the cubes is 3025.

We now give a program to print a pattern of asterisks to illustrate the while loop further.

Example . 

Program Ch03n31.c

 /*Program to print a pattern of asterisks*/
 #include <stdio.h>

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

    while(i<=n)
    {
       j=1;
       while(j<=n-i)
       {
          printf(" ");
          j++;
       }
       j=1;
       while(j<=2*i-1)
       {
          printf("*");
          j++;
       }
       i++;
       printf("\n");
    }
    printf("\n");
    return 0;
 }
 End Program
EXECUTION

   *
  ***
 *****
*******

The do-while Statement

The do-while construct can be considered as a variant of the while construct. Instead of having an expression test at the top of the loop, as in the while, the do-while makes its test at the bottom of the loop. The loop will, thus, always execute at least once because do-while tests for continuation at the bottom. The general form of the do-while repetition construct is as follows:

do
   <Actions_block>
while(expression);

The construct consists of the keyword do, followed by the Actions_block. The Actions_block is as defined for the while looping construct, i.e., it may consist of one or more statements. The Actions_block is followed by the keyword while, and an expression in parentheses. A semicolon must terminate the statement.

First, the statements in the Actions_block are executed. Then, the expression in parentheses is evaluated. If the value of the expression is non-zero (true), control passes to the beginning of the Actions_block and the Actions_block executes again. This process continues until the expression evaluates to zero (false) at some iteration of the loop, and control transfers out of the do-while construct to the statement immediately following the construct.

The do-while construct is used in the following illustrative examples:

Let us consider writing a program to read in a value ranging between 1 and 10, from the user. On incorrect inputs (beyond the specified range), the program retries the read. This process continues until the user has entered a correct value

Example . 

Program Ch03n32.c

 /*Program to demonstrate the do-while repetition construct*/
 #include <stdio.h>

 int main()
 {
    int Val;

    do{
       printf("\nEnter a number between 1 and 10(both inclusive): ");
       scanf("%d",&Val);
       if((Val<1) || (Val>10))
          printf("The number is not between 1 and 10...");
    }  while((Val<1) || (Val>10));
    printf("The number you entered is %d.\n",Val);
    return 0;
}
End Program
EXECUTION (Boldface represents user input)

Enter a number between 1 and 10(both inclusive): 12
The number is not between 1 and 10...
Enter a number between 1 and 10(both inclusive): -1
The number is not between 1 and 10...
Enter a number between 1 and 10(both inclusive): 6
The number you entered is 6.

Explanation: The program prompts for a value between 1 and 10. The loop will continue to prompt for a number, until its value falls within the required bounds. Once the user has entered a value between 1 and 10, control transfers out of the do-while and to the printf function call, where the value entered is displayed.

Consider the problem to compute the factorial of a number n. For a non-negative integer, the factorial of n, written as n!, is defined by:

0!=1
n!=n*(n-1)*(n-2)* ... *3*2*1    for n>0

Or equivalently,

n!=n*((n-1)!)                   for n>0

Thus, for example, 5! = 5 * 4 * 3 * 2 * 1 = 120. We present an iterative solution to the factorial problem in the next program.

Since there is an upper limit on the size of an int on the host machine, we can only obtain factorials for small values of n. Larger values of n result in an overflow and produce incorrect results. If, however, we wish to compute factorials for larger numbers, use of higher-precision data types like long int or long double is recommended.

Example . 

Program Ch03n33.c

 /*Program to compute the factorial of a number*/
 #include <stdio.h>

 int main()
 {
    int n,Factorial=1,i=1;

    printf("\nEnter the number for computing factorial: ");
    scanf("%d",&n);
    do{
       Factorial*=i;
       i++;
    } while(i<=n);
    printf("The factorial of %d is %d.\n",n,Factorial);
    return 0;
 }
 End Program
EXECUTION (Boldface represents user input)

Enter the number for computing factorial: 5
The factorial of 5 is 120.

Returning to triangles, we present as our next example, a program to print a right-angled triangle of asterisks.

Example . 

Program Ch03n34.c

 /*Program to print another pattern of asterisks*/
 #include <stdio.h>

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

    printf("\nEnter the number of rows: ");
    scanf("%d",&n);
    do{
       j=1;
       do{
          printf("*");
          j++;
       } while(j<=i);
       i++;
       printf("\n");
    } while(i<=n);
    return 0;
 }
 End Program
EXECUTION (Boldface represents user input)

Enter the number of rows: 4
*
**
***
****

The break and continue Statements

The break and continue statements are used to interrupt ordinary iterative flow of controls in loops. The break statement terminates the innermost loop or switch in which the statement is found. At that point, program control transfers to the next statement in the immediately surrounding block, which may be another loop. The break statement can be used only inside a loop or in a switch statement.

Consider the following program as an illustration of the break statement.

Example . 

Program Ch03n35.c

 /*Program to illustrate the break statement in a for loop*/
 #include <stdio.h>

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

    for(i=1;i<=5;i++)
    {
        if(i==4)
            break;
        else
            j++;
    }
    printf("The value of j is %d.\n",j);
    return 0;
 }
 End Program
EXECUTION

The value of j is 6.

Explanation: The variable j is initialized to 3. At the first iteration of the for loop, i is set to 1. The expression i<=5 evaluates to true and the loop body executes. The first statement in the block tests if i is 4. Since i is 1, the expression i==4 evaluates to false and the increment statement in the else part executes. This process continues until i is 4, at which the increment has been performed thrice and j has the value 6. When i==4 is true, the break statement executes and control transfers out of the current loop to outside of the loop, i.e., to the printf function call outside the for loop. The break statement can be used with similar results for while and do-while repetition constructs. The next program illustrates use of the break in a switch statement. It counts the occurrences of the letters a, b, m, and M, with the letters m and M counted together. The input is read in letter by letter, and terminated by a full stop.

Example . 

Program Ch03n36.c

 /*Program to illustrate the break statement in a switch statement*/
 #include <stdio.h>

 int main()
    {
    int c,a_count=0,b_count=0,mM_count=0,other_count=0;

    do{
        printf("Enter the character('.' to terminate): ");
        fflush(stdin);
        c=getchar();
        switch(c)
        {
            case 'a':
                 ++a_count;
                break;
            case 'b':
                 ++b_count;
                break;
            case 'm':
            case 'M':
                 ++mM_count;
                break;
            default:
                 ++other_count;
        }
    } while(c!='.');
    printf("\nThe count of a's is %d.\n",a_count);
    printf("The count of b's is %d.\n",b_count);
    printf("The count of m-M's is %d.\n",mM_count);
    printf("The count of others is %d.\n",other_count);
    return 0;
 }
 End Program
EXECUTION (Boldface represents user input)

Enter the character('.' to terminate): p
Enter the character('.' to terminate): m
Enter the character('.' to terminate): m
Enter the character('.' to terminate): a
Enter the character('.' to terminate): M
Enter the character('.' to terminate): b
Enter the character('.' to terminate): a
Enter the character('.' to terminate): b
Enter the character('.' to terminate): m
Enter the character('.' to terminate): a
Enter the character('.' to terminate): y
Enter the character('.' to terminate): .

The count of a's is 3.
The count of b's is 2.
The count of m-M's is 4.
The count of others is 3.

Explanation: At the beginning of the loop, a character is read in from the terminal. It is preceeded by a call to the fflush function, which takes a single argument – the stream to flush free of unnecessary characters. The prototype for the fflush function is defined within stdio.h. The input stream, i.e., the keyboard, is referred to by stdin and, thus, stdin is passed as an argument to fflush to indicate that we want the input stream to be flushed. In the absence of a call to fflush preceding each call to getchar to read in a character, subsequent getchar calls may return a previously scanned character.

After reading in the character, the switch construct is entered. Here, the variable read in is checked for ‘a’, ‘b’, ‘m’, ‘M’, or others. If the character matches any of ‘a’, ‘b’, ‘m’, or ‘M’, the appropriate counter variable is incremented and the break statement is executed. The break statement transfers control outside the switch statement to the do-while expression evaluation. Here, the last character entered is checked for a dot (·). If it is not a dot (·), the loop continues to read in another character, and this process continues until a dot is entered and the do-while loop exits. The program then prints the values of the counter variables to give the counts of the occurrences of the specified characters in the input.

The continue statement is similar to break in that both allow exits from a loop. The continue exits from the innermost loop. The continue statement transfers control to the top of the loop in which the statement was found.

Let us move on to an example program to clarify things further.

Example . 

Program Ch03n37.c

 /*Program to illustrate the continue statement*/
 #include <stdio.h>

 int main()
 {
    int i;

    for(i=1;i<=3;i++)
    {
        if(i!=2)
            continue;
        break;
    }
    printf("The value of i is %d.\n",i);
    return 0;
 }
 End Program
EXECUTION

The value of i is 2.

Explanation: At the first iteration of the for loop, the variable i is set to 1. The expression i<=3 evaluates to true and the loop body executes. The first statement in the for block tests if i is 2. Since i is 1, the expression i!=2 evaluates to true and control transfers to the start of the loop because of the continue in the if statement. Now, i is incremented and i<=3 is again true, since i is now 2. When i!=2 is tested, the if statement block does not execute and the break statement executes. This transfers control out of the current loop to outside of the loop, i.e., to the printf function call outside the for loop.

The continue statement can be used with similar results for while and do-while loops.

Note: A variable declared using the register data type is useful for declaring loop counter variables. Since the register variables might be stored in the CPU registers, there is a possibility of an increase in performance for small loops that run for a lot of iterations.

The Infamous goto

The syntax of goto is

goto <identifier> ;

The goto statement is used to transfer control to the location of a local label specified by <identifier>. Labels are always terminated by a colon and appear at the beginning of a statement.

An example will help to clarify things.

      int a=10;
      ...
next: printf("%d",a);
      a++;
      ...
      if(a<20)goto next;
      ...

Here, the label is ‘next’ and the skeleton program prints the integers from 10 to 19. We shall not be discussing goto anymore. Usage of goto leads to unstructured programs. The traceability of programs and, thus, their readability as well as maintainability are reduced considerably when goto is used to write programs. Usage of this keyword might seem tempting at first, but it is easy to overcome this temptation by increasing your expertise in writing repetition control constructs. A loop can easily replace a goto, and should always be used as an option instead of the unstructured goto. The primary lesson from this subsection is: “DO NOT USE this technique.”

Summary

Control constructs are provided in C to facilitate writing of programs. Conditional constructs and repetition constructs are available. The conditional constructs include the if, if-else, nested if-else and switch statements. They perform the tasks of carrying out a particular set of operations (block) if a condition is satisfied at some point in a program.

Repetition constructs provide facilities for conditional repetition of a block of code. The statements in the block are executed repeatedly as long as a condition is satisfied. The for, while and do-while are the three types of repetition constructs available in C. There is an unstructured way to escape a loop midway by the break statement, or reset the loop execution to the start of the loop by ignoring all the statements that follow the continue statement. Usage of these techniques is not advised for writing well-structured programs since a lot of break and continue statements in repetition constructs can harm the beauty of the control provided by the looping mechanism. A similar philosophy applies to the goto construct. However, unlike the fact that the goto construct should be avoided altogether, it is not always possible to write elegant code without using the break or the continue statement. Absolute avoidance of these statements may lead to complicated loops – and the result may be more complex than a block with no break or continue statements.

New Terminology Checklist

Control

If

Nested ifs

Loop

Switch

Break

Do while

While

Break

Continue

Goto

Default

Masking

Exercises

1.

Write a program to read in the three angles of a triangle and print if the triangle is a valid one or not. If it represents a valid triangle, then print the type of the triangle, i.e., one of Isosceles, Scalene, or Equilateral. Also, print if the triangle is a right-angled one.

2.

Sunny numbers are defined as numbers that when incremented by 1 and squared gives an integer. Write a program to print all the sunny numbers within a given range.

3.

A Pythagorean triplet is a sequence of three integers, A, B, and C, such that A2 + B2 = C2. Write a program to print all the Pythagorean triplets within a given range.

4.

Fibonacci numbers are generated by the following recurrence relation:

Fi = Fi-1 + Fi-2 for all i>1

and F0=1, F1=1

For example, the first 5 Fibonacci numbers are 1, 1, 2, 3, 5.

Write a program to print the first n Fibonacci numbers where n is read in from the keyboard.

5.

Twin prime numbers are two prime numbers that have a difference of less than or equal to two. For example, 2 and 3 are twin primes, 3 and 5 are twin primes, and 11 and 13 are twin primes. Write a program to print all the twin prime numbers between two given bounds.

6.

A strong number is an integer that equals the sum of the factorials of its digits. Write a program to print the strong numbers within a given bound.

7.

Write a program to accept an integer, n, and print the integer in words. For example, if n=122, then the program gives ‘one hundred and twenty two’ as the output.

8.

Write a program to calculate the least common multiple (LCM) of n integers, where n is read in from the keyboard.

9.

Write a program to accept a date in the format dd-mm-yyyy and print if the date is a valid one. Also, print the day for the date and print whether the year given is a leap year or not.

10.

Write a program to accept two dates in the format dd/mm/yyyy and print the number of days between the two dates if both the dates are valid.