Essentialssec6.htm

Essentials of C++: Section VI


Selection Statements

There are four ways a computer can work its way through a set of instructions. It can:

  1. execute the instructions in sequence;
  2. jump to a different set of instructions via a function call or goto instruction (not covered in this write-up);
  3. use some test to decide which of two sets of instructions to perform;
  4. repeat some set of instructions over and over.

A. The If statement

In this section we look at the third way and the so-called selection statements. There are two such statements in C++, the if and the switch statement. The 'if' statement has the form:

if (some test condition )
{

some set of instructions
}
else
{
some set of instructions
}
// the program continues

The 'else' part is optional. Technically speaking, the brackets are not required in either part if only one statement is to be executed, but you are strongly advised to always include them to avoid certain kinds of ugly, hard to decipher, kinds of errors. In any case, the code in each part (whether in brackets or not) represents a block of code.

When executed, this statement first examines the test condition. If TRUE is returned, the system executes the lines inside the first set of brackets and then moves on to the code after the second set of brackets . If FALSE is returned by the test, the system executes the code inside the 2nd set of brackets (after the 'else' line) and then continues with the rest of the program, or, if there is no 'else' clause, it simply continues with the rest of the program.

The test condition can involve both relational and logical operators, where the logical operators allow the programmer to create one test result from a number of individual tests. For example:

if  ( (x  >  0)   &&   (x  <  20)  ||  !found() )
{

// some set of statements
}

The test, "(x > 0) && (x < 20) || !found()", seeks to find if either "x is greater than 0 and less than 20" or the function 'found' does not return TRUE - meaning that it returns 0. In general, any logical expression that returns a value that can be interpreted as an integer is valid. (TRUE is interpreted as any value other than 0, while 0 is interpreted as FALSE. )

In place of the "some set of instructions" lines in the general form, one can place any legal set of valid C++ statements. One can even have (or nest) as many 'if' statements as one needs. However, deeply nested if statements can be hard for humans to interpret and can cause hard to find syntactic or semantic errors. This is especially true when if statements with and without 'else' clauses are mixed. 'Else' clauses always match the closest 'if' that does not already have a matching 'else' at the same block or 'bracket' level. Consider the following pseudo-code:

   
      if (test1)
      {   if (test2)
          {   if (test3)
              {.........}
          }    // This bracket completely encloses the third 'if'
          else
          { ...........}
      }
      else
      {..........}

The indentation helps us interpret this but, remember, the compiler plays NO attention to indentation. The first else 'attaches' itself to the second 'if' statement only because the third 'if' statement is completely inside the brackets for the first part of the second 'if' statement. Those brackets represent a 'block' of code.

If the code were rewritten as:

 
      if (test1)
      {    if (test2)
           {   if (test3)
               {.........}
		 // There used to be a bracket here.
           else
           { ...........}
           }    // The bracket that was above has been moved here.
      }
      else
      {..........}

the indentation would be misleading and the first 'else' would be associated with the third 'if''if' since a bracket has been moved.

Properly indented, the code would look as follows:

 
      if (test1)
      {    if (test2)
           {   if (test3)
               {.........}
               else
               { ...........}
           }   
      }
      else
      {..........}

Now it is clear that the first else is inside the same block of code as the third 'if' and they should therefore be connected.

Notice that in both cases the second 'else' is associated with the first 'if'. In this last piece of code, if the curly brackets before the last else were removed, the second 'else' would be associated with the second 'if' and the indentation would again be misleading.
 

B. The Switch Statement
Although the 'if' statement provides all the power necessary to appropriately select code in a program, it can result in code that is hard to write and hard to comprehend. In some situations the 'switch' statement can make for much simpler code. All 'switch' statements start with:

switch (some expression)
{

// some set of 'case' statements
}

The code used for 'some expression' must represent or return an integer value (or some value that can be converted into an integer using the implicit conversion rules). This value will be compared with each of the 'case' statements that follow, and, if there is a match, the system will jump to the code associated with the matching 'case' statement.

A 'case' statement consists of:

  • the word 'case',
  • followed by a constant that is or can be implicitly converted to an integer value,
  • a colon, and
  • possibly one or more C++ statements (including other 'if' and 'switch' statements)
Here is a simple example:

case 1:
   sum = sum + x;

In this case the line "sum = sum + x;" will be executed if "some expression" evaluates to 1. One can interpret each 'case' as an implicit test for equality. In this code fragment the test is, "Does the value returned by 'some expression' equal 1?" Or, to put it in terms of code:

if (some expression == 1)

Thus, any 'switch' statement can be re-written as a set of 'if' statements involving tests for equality.

Usually a 'switch' statement includes some number of 'case' statements, each representing some test for equality. Once a match occurs the computer will execute the code inside that 'case' statement and will, by default, continue executing any code from that point until the end of the 'switch' statement - even code in other 'cases'. This default behavior can be changed by including a break statement at the end of the code one wishes to be executed for a given match. When the system encounters a 'break' statement inside a switch statement, the system jumps to the first instruction after the switch statement.

Each 'switch' statement can include one 'default' case, coded as:

       default:

    // some set of instructions

If the value returned by 'some expression' does not match any of the cases and there is a 'default' case, the system jumps to the code associated with the default. If there is no match and there is no default case, control shifts to the first instruction after the 'switch' statement.

Consider the example:

 
  	char char1;
	char1 = GetChoice();
	switch (char1)
	{   case 'a':
            case 'A':
               ProcessChoiceA();
               break;

            case 'b':
            case 'B':
               ProcessChoiceB();
               break;

            case 'q':
            case 'Q':
               ProcessChoiceQ();
               break;

            default:
               cout << "Not a valid choice\n";
        }

In this example, if 'char1' is either an 'a' or an 'A' the function 'ProcessChoiceA' is called. Notice that if 'char1' has the value 'a', the system 'jumps' to the code associated with that choice. There is none, but no 'break' statement is encountered so the system falls through to the code associated with case 'A' and executes the code found there. Note also that while 'char1' is declared to be of type 'char' and thus is technically not an integer, C++ has no trouble converting it into an integer value.

Links to 'The Story of C++" and other documents

The 'if' Statement
The 'switch' Statement
Test Conditions Involving Logical Operartors

Top of Section Main Menu of Essentials of C++ Next Section