A Little C Primer/C Control Constructs

C contains a number of looping constructs, such as the "while" loop:

   /* while.c */

   #include <stdio.h>

   void main()
   {
     int test = 10;
     while( test > 0 )
     {
       printf( "test = %d\n", test );
       test = test - 2;
     }
   }

If "test" starts with an initial value less than or equal to 0 the "while" loop will not execute even once. There is a variant, "do", that will always execute at least once:

   /* do.c */

   #include <stdio.h>

   void main()
   {
     int test = 10;
     do 
     {
       printf( "test = %d\n", test );
       test = test - 2;
     }
     while( test > 0 );
   }

The most common looping construct is the "for" loop, which creates a loop much like the "while" loop but in a more compact form:

   /* for.c */

   #include <stdio.h>
   
   void main()
   {
     int test;
     for( test = 10; test > 0; test = test - 2 )
     {
       printf( "test = %d\n", test );
     }
   }

Notice that with all these loops, the initial loop statement does not end with a ";". If a ";" was placed at the end of the "for" statement above, the "for" statement would execute to completion, but not run any of the statements in the body of the loop.

The "for" loop has the syntax:

   for( <initialization>; <operating test>; <modifying expression> )

All the elements in parentheses are optional. A "for" loop could be run indefinitely with:

   for( ; ; )
   {
     ...
   }

—although using an indefinite "while" is cleaner:

   while( 1 )
   {
     ...
   }

It is possible to use multiple expressions in either the initialization or the modifying expression with the "," operator:

   /* formax.c */

   #include <stdio.h>

   void main()
   {
     int a, b;
     for ( a = 256, b = 1; b < 512 ; a = a / 2, b = b * 2 )
     {
       printf( "a = %d  b = %d\n", a, b );
     }
   }

The conditional tests available to C are as follows:

   a == b    equals                       
   a != b    not equals
   a < b     less than                    
   a > b     greater than
   a <= b    less than or equals          
   a >= b    greater than or equals

The fact that "==" is used to perform the "equals" test, while "=" is used as the assignment operator, often causes confusion and is a common bug in C programming:

   a == b    Is "a" equal to "b"?
   a = b     Assign value of "b" to "a".

C also contains decision-making statements, such as "if":

   /* if.c */

   #include <stdio.h>
   #define MISSILE 1

   void fire( int weapon );

   void main()
   {
     fire( MISSILE );
   }

   void fire( int weapon )
   {
     if( weapon == MISSILE )
     {
       printf( "Fired missile!\n" );
     }
     if( weapon != MISSILE )
     {
       printf( "Unknown weapon!\n");
     }
   }

This example can be more easily implemented using an "else" clause:

   /* ifelse.c */

   void fire( int weapon )
   {
     if( weapon == MISSILE )
     {
       printf( "Fired missile!\n" );
     }
     else
     {
       printf( "Unknown weapon!\n");
     }
   }

Since there is only one statement in each clause the curly brackets aren't really necessary. This example would work just as well:

   void fire( int weapon )
   {
     if( weapon == MISSILE )
       printf( "Fired missile!\n" );
     else
       printf( "Unknown weapon!\n" );
   }

However, the brackets make the structure more obvious and prevent errors if you add statements to the conditional clauses. The compiler doesn't care one way or another, it generates the same code.

There is no "elseif" keyword, but "if" statements can be nested:

   /* nestif.c */

   #include <stdio.h>
   #define MISSILE 1
   #define LASER 2

   void fire( int weapon );

   void main()
   {
     fire( LASER );
   }

   void fire( int weapon )
   {
     if( weapon == MISSILE )
     {
       printf( "Fired missile!\n" );
     }
     else
     {
       if( weapon == LASER )
       {
         printf( "Fired laser!\n" );
       }
       else
       {
         printf( "Unknown weapon!\n");
       }
     }
   }

This is somewhat clumsy. The "switch" statement does a cleaner job:

   /* switch.c */

   void fire( int weapon )
   {
     switch( weapon )
     {
     case MISSILE:
       printf( "Fired missile!\n" );
       break;
     case LASER:
       printf( "Fired laser!\n" );
       break;
     default:
       printf( "Unknown weapon!\n");
       break;
     }
   }

The "switch" statement tests the value of a single variable; unlike the "if" statement, it can't test multiple variables. The optional "default" clause is used to handle conditions not covered by the other cases.

Each clause ends in a "break", which causes execution to break out of the "switch". Leaving out a "break" can be another subtle error in a C program, since if it isn't there, execution flows right through to the next clause. However, this can be used to advantage. Suppose in our example the routine can also be asked to fire a ROCKET, which is the same as a MISSILE:

   void fire( int weapon )
   {
     switch( weapon )
     {
     case ROCKET:
     case MISSILE:
       printf( "Fired missile!\n" );
       break;
     case LASER:
       printf( "Fired laser!\n" );
       break;
     default:
       printf( "Unknown weapon!\n");
       break;
     }
   }

The "break" statement is not specific to "switch" statements. It can be used to break out of other control structures, though good program design tends to avoid such improvisations:

   /* break.c */

   #include <stdio.h>

   void main()
   {
     int n;
     for( n = 0; n < 10; n = n + 1 )
     {
       if( n == 5 )
       {
         break;  /* Punch out of loop at value 5. */
       }
       else
       {
         printf( "%d\n", n );
       }
     }
   }

If the "for" loop were nested inside a "while" loop, a "break" out of the

"for" loop would still leave you stuck in the "while" loop. The "break" keyword only applies to the control construct that executes it.

There is also a "continue" statement that skips to the end of the loop body and continues with the next iteration of the loop. For example:

   /* continue.c */

   #include <stdio.h>

   void main()
   {
     int n;
     for( n = 0; n < 10; n = n + 1 )
     {
       if( n == 5 )
       {
         continue;
       }
       else
       {
         printf( "%d\n", n );
       }
     }
   }

Finally, there is a "goto" statement:

   goto punchout;
   ...
   punchout:

—that jumps to an arbitrary tag within a function, but the use of this

statement is generally discouraged and it is rarely seen in practice.

While these are the lot of C's true control structures, there is also a special "conditional operator" that performs a simple conditional assignment of the form:

   if( a == 5) 
   {
     b = -10;
   }
   else
   {
     b = 255;
   }

—using a much tidier, if more cryptic, format:

   b = ( a == 5 ) ? -10 : 255 ;

the ?: construct is called a ternary operator—or the ternary operator—as it takes 3 arguments.