Previous Page
Next Page

6.5. Unconditional Jumps

Jump statements interrupt the sequential execution of statements, so that execution continues at a different point in the program. A jump destroys automatic variables if the jump destination is outside their scope. There are four statements that cause unconditional jumps in C: break , continue, goto, and return.

6.5.1. The break Statement

The break statement can occur only in the body of a loop or a switch statement, and causes a jump to the first statement after the loop or switch statement in which it is immediately contained:

break;

Thus the break statement can be used to end the execution of a loop statement at any position in the loop body. For example, the while loop in Example 6-7 may be ended either at the user's request (by entering a non-numeric string), or by a numeric value outside the range that the programmer wants to accept.

Example 6-7. The break statement
// Read user input of scores from 0 to 100
// and store them in an array.
// Return value: the number of values stored.
// ------------------------------------------
int getScores( short scores[ ], int len )
{
   int i = 0;
   puts( "Please enter scores between 0 and 100.\n"
         "Press <Q> and <Return> to quit.\n" );
   while ( i < len )
   {
      printf( "Score No. %2d: ", i+1 );
      if ( scanf( "%hd", &scores[i] ) != 1 )
         break;          // No number read: end the loop.
      if ( scores[i] < 0  ||  scores[i] > 100 )
      {
         printf( "%d: Value out of range.\n", scores[i] );
         break;          // Discard this value and end the loop.
      }
      ++i;
   }
   return i;             // The number of values stored.
}

6.5.2. The continue Statement

The continue statement can be used only within the body of a loop, and causes the program flow to skip over the rest of the current iteration of the loop:

continue;

In a while or do ... while loop, the program jumps to the next evaluation of the loop's controlling expression. In a for loop, the program jumps to the next evaluation of the third expression in the for statement, containing the operations that are performed after every loop iteration.

In Example 6-7, the second break statement terminates the data input loop as soon as an input value is outside the permissible range. To give the user another chance to enter a correct value, replace the second break with continue. Then the program jumps to the next iteration of the while loop, skipping over the statement that increments i:

// Read in scores.
// --------------------------
int getScores( short scores[ ], int len )
{
   /* ... (as in Example 6-7) ... */
   while ( i < len )
   {
      /* ... (as in Example 6-7) ... */
      if ( scores[i] < 0  ||  scores[i] > 100 )
      {
         printf( "%d : Value out of range.\n", scores[i] );
         continue;         // Discard this value and read in another.
      }
      ++i;                  // Increment the number of values stored.
   }
   return i;                // The number of values stored.
}

6.5.3. The goto Statement

The goto statement causes an unconditional jump to another statement in the same function. The destination of the jump is specified by the name of a label:

goto label_name;

A label is a name followed by a colon:

label_name: statement

Labels have a name space of their own, which means they can have the same names as variables or types without causing conflicts. Labels may be placed before any statement, and a statement can have several labels. Labels serve only as destinations of goto statements, and have no effect at all if the labeled statement is reached in the normal course of sequential execution. The following function uses a label after a return statement to mark the entry point to an error handling routine:

// Handle errors within the function.
// ----------------------------------
#include <stdbool.h>        // Defines bool, true
                            // and false (C99).
#define MAX_ARR_LENGTH  1000
bool calculate( double arr[ ], int len, double* result )
{
   bool error = false;
   if ( len < 1  ||  len > MAX_ARR_LENGTH )
      goto error_exit;
   for ( int i = 0; i < len; ++i )
   {
     /* ... Some calculation that could result in
      * the error flag being set ...
      */
     if ( error )
        goto error_exit;
     /* ... Calculation continues; result is
      * assigned to the variable *result ...
      */
   }
   return true;              // Flow arrives here if no error

   error_exit:               // The error handler
   *result = 0.0;
   return false;
}

You should never use a goto statement to jump into a block from outside it if the jump skips over declarations or statements that initialize variables. However, such a jump is illegal only if it leads into the scope of an array with variable length, skipping over the definition of the array (for more information about variable-length arrays, which were introduced with C99, see Chapter 8):

static const int maxSize = 1000;
double func( int n )
{
   double x = 0.0;
   if ( n > 0  &&  n < maxSize )
   {
      double arr[n];         // A variable-length array
      again:
      /* ... */
      if ( x == 0.0 )
        goto again;          // Okay: the jump is entirely
   }                         // within the scope of arr.
   if ( x < 0.0 )
      goto again;            // Illegal: the jump leads
                             // into the scope of arr!
   return x;
}

Because code that makes heavy use of goto statements is hard to read, you should use them only when they offer a clear benefit, such as a quick exit from deeply nested loops. Any C program that uses goto statements can also be written without them!

The goto statement permits only local jumps; that is, jumps within a function. C also provides a feature to program non-local jumps to any point in the program, using the standard macro setjmp( ) and the standard function longjmp( ). The macro setjmp( ) marks a location in the program by storing the necessary process information, so that execution can be resumed at that point at another time by a call to the function longjmp( ). For more information on these functions , see Part II.


6.5.4. The return Statement

The return statement ends execution of the current function, and jumps back to where the function was called:

return [expression];

expression is evaluated and the result is given to the caller as the value of the function call. This return value is converted to the function's return type, if necessary.

A function can contain any number of return statements:

// Return the smaller of two integer arguments.
int min( int a, int b )
{
   if   ( a < b ) return a;
   else           return b;
}

The contents of this function block can also be expressed by the following single statement:

return ( a < b ? a : b );

The parentheses do not affect the behavior of the return statement . However, complex return expressions are often enclosed in parentheses for the sake of readability.

A return statement with no expression can only be used in a function of type void. In fact, such functions do not need to have a return statement at all. If no return statement is encountered in a function, the program flow returns to the caller when the end of the function block is reached. Function calls are described in more detail in Chapter 7.


Previous Page
Next Page