Back to CEO's Home Page

Control Structures I

Text: C++ Programming: From Problem Analysis to Program Design, 2nd Ed. by D. S. Malik

Charles E. Oyibo

Control Structures

A computer can process a program in one of three ways:

Control structures provide an alternative to sequential program execution and are used to alter the sequential flow of execution. The two most common control structures are selection (where the program executes particular statements depending on some condition(s)); and repetition (where the program repeats particular statements a certain number of times depending on some condition(s)).

Statements that are executed in a program only if certain conditions are met are called conditional statements. A condition is met if it evaluates to true.

Relational Operators

Certain items are compared for equality against a particular condition; others are compared for inequality--greater than or less than--against a particular condition. In C++, a condition is represented by a logical (Boolean) expression (i.e. an expression that has a value of, or evaluates to either true or false), and relational operators allow us to make comparisons in programs.

C++ includes six relational operators:

Operator Description
== equal to
!= not equal to
< less than
<= less than or equal to
> greater than
>= greater than or equal to

Note the distinction between that the assignment operator (=), which assigns the value of an expression to a variable, and the equality operator (==), which determines whether two expressions are equal.

Each of the relational operators is a binary operator as it requires two operands, and expressions using those operators evaluate to true or false. The identifier true is set to 1, and the identifier false is set to 0.

Relational Operators and Data Types

Comparing values of different data types may product unpredictable results.

For char values, whether an expression evaluates to true or false depends on a machine (ASCII) collating sequence.

The relational operators can be applied to variable to the type string. Variable of the type string are compare character-by-character, starting with the first character using the ASCII collating sequence. The character-by-character matching continues until either a mismatch is found or the last characters have been compared and are equal.

If two strings of different lengths are compared and the character-by-character comparison is equal until it reaches the last character of the shorter string, the shorter string (e.g. Bill) is evaluated to as less than the larger string (e.g. Billy).

Logical (Boolean) Operators and Logical Expressions

Logical (Boolean) operators allow us to combine logical expressions. C++ has three logical (Boolean) operators:

Operator Description
! not
&& and
|| or

Logical operators take only logical values as operands and yield only logical values as results. The operator ! is unary, so it has only one operand. The operators && and || are binary operators.

The Boolean Operators

The ! (not) operator

Expression !(Expression)
true (nonzero) false (0)
false (0) true (1)

The && (and) Operator

Expression1 Expression2 Expression1 && Expression2
true (nonzero) true (nonzero) true (1)
true (nonzero) false (0) false (0)
false (0) true (nonzero) false (0)
false (0) false (0) false (0)

The || (or) Operator

Expression1 Expression2 Expression1 || Expression2
true (nonzero) true (nonzero) true (1)
true (nonzero) false (0) true (1)
false (0) true (nonzero) true (1)
false (0) false (0) false (0)

Order of Precedence

Operators Precedence
!, +, - (unary operators) first
*, /, % second
+, - third
<, <=, >=, > fourth
==, != fifth
&& sixth
|| seventh
= (assignment operator) last

Short-Circuit Evaluation

With short-circuit evaluation, the computer evaluates the logical expression from left to right; as soon as the value of the entire logical expression is known, the evaluation stops. Consider the following statement for example:

(x > y) || (x == 5) // line1
(a == b) && (x >= 7) // line 2

If the operand (x > y) in statement one evaluates to true, then the entire expression evaluate to true because true || true is true and true || false is true. Therefore the value of the operand (x==5) has no bearing on the final outcome.

Similarly, if the operand (a==b) in the statement in line 2 evaluates to false, then the entire statement evaluates to false because false && true is false and false && false is false.

A short-circuit evaluation (of a logical expression), then, is a process by which the computer evaluates a logical expression from left to right and stops as soon as the value of the expression is known.

In C++, logical (Boolean) expressions can be manipulated or processed in either of two ways: by using int variables or by using bool variables. We go to these next.

int Data Type and Logical (Boolean) Expressions

Because logical expressions evaluate to either 1 or 0, the value of a logical expression could be stored in a variable of the type int. Therefore, it is possible to use the int data type to manipulate logical (Boolean) expressions. Observe:

int legalAge;
int age;

legalAge = 21; // the value of legalAge assigned by this statement is true (recall that nonzero values are treated as true).
legalAge = (age >= 21); // assigns the value of 1 to legalAge if the value of age is greater than or equal to 21, and assigns a value of 0 if the value is less than 21.

bool Data Type and Logical (Boolean) Expressions

More recent versions of C++ contain a built-in data type, bool, that has the logical (Boolean) values true and false. Therefore, one could manipulate logical (Boolean) expression using the bool data type. Consider the following declaration:

bool legalAge;
int Age;

legalAge = true // sets the value of the variable legalAge to true
legalAge = (age >= 21); // assigns the value true to legalAge if the value of age is greater than or equal to 21, and assigns the value of false to legalAge if the value of age is less than 21.

Note: The correct way to represent the expression 0 <= x <= 10 in C++ is:

0 <= x && num <= 10

or

num >= 0 && num <= 10

This highlights the need for caution when formulating logical expressions. When creating complex logical expressions, one must use the proper logical operators.

Selection: if and if...else

In C++, there are two selection, or branch control structure: if statements and the switch structure.

One-Way selection

  1. If customer's checking account balance falls below required minimum, send customer a notice;
  2. If policyholder of the premier health insurance is a non-smoker, apply a 10% discount to the policy premium;

These are examples of one-way selection. In C++, one-way selections are incorporated using the if statement:

if (expression)
    statement

The expression contained with the parenthesis is usually a logical expression. If the value of the expression is true, the statement executes. If the value is false, the statement does not execute and the computer goes on to the next statement in the program.

Note: Putting a semicolon after the parenthesis following the expression in an if statement (that is, before the statement) is a semantic error. If the semicolon immediately follows the closing parenthesis, the if statement will be an empty statement.

Two-Way Selection

  1. If a part-time employee works overtime, the paycheck is calculated using the overtime payment formula; otherwise the paycheck is calculated using the regular formula. To choose between the two alternatives--that is to implement a two-way selection--C++ provides the if..else statement:

if (expression)
    statement1
else
    statement2

In a two-way selection, if the value of the expression is true, statement1 executes. If the value of the expression is false, statement2 executes.

As with a one-way selection, putting a semicolon after the expression and before statement1 creates a syntax error. Semicolons should come only at the end of statements.

Compound (Block of) Statements

Suppose that we would like to execute more than one statement if the expression in an if or if...else statement evaluates to true, we could use a structure that C++ provides, called a compound statement or a block of statements:

{
  statement1
  statement2
  ...
  statementn
}

That is, a compound statement consists of a sequence of statements enclosed in curly braces, {...}.

Multiple Selections: Nested if

  1. Suppose that if the checking account balance is more than $50000, the interest rate is 7%; if the balance is between $25000 and $49999.99, the interest rate is 5%; if the balance is between $1000 and $24999.99, the interest rate is 3%, otherwise the interest rate is 0%.

This problem has four alternative--that is, four multiple selection paths. We could nest multiple selection paths in a program by using an if or if...else statement thus:

if (balance > 50000.00)
    interestRate = 0.07;
else
    if (balance >= 25000.00)
        interestRate = 0.05;
    else
        if (balance >= 1000.00
            interestRate = 0.03
        else
            interestRate = 0.00;

Pairing an else with an if: In a nested if statement, C++ associates an else with the most recent incomplete if. There is however one general rule: you cannot look inside a block (that is inside braces, { ... }) to pair an else with an if.

Input Failure and the if Statement

In Chapter 3: Input/Output, we saw that an attempt to read invalid data causes the input stream to enter a fail state, all subsequent statements associated with that input stream are ignored, and the computer continues to execute the program, which produces erroneous results.

In addition to reading invalid data, two additional common causes of input failure are:

  1. Attempting to open an input file that does not exist
  2. Attempting to read beyond the end of an input file

We could use the if statement to check the status of an input statement variable and, if the input stream enters a fail state, include instructions that stop program execution. We do this by using the input statement variable as a logical expression in an if statement. When the input stream variable is used as an expression in an if statement, it evaluates to true if the last input succeeded and to false if the last input failed.

The statement:

if (cin)
    cout << "Input is OK." << endl;

prints:

Input is OK.

if the last input from the standard input device succeeded. Similarly, if infile is an ifstream variable, the statement:

if (!infile)
    cout << "Input failed." << endl;

prints

Input failed.

if the last input associated with the stream variable infile failed.

 

... discussion of Input failure continues here...

 

Confusion Between the Equality Operator (==) and the Assignment Operator (=)

Suppose that the discount on a car insurance policy is based on the insured's driving record. A driving record of 1 means that the driver is accident-free and receives a 25% discount on the policy. The statements:

if (drivingCode == 1)
    cout << "The discount policy on the policy is 25%." << endl;

outputs:

The discount policy is 25%

only if the value of drivingCode is 1. However, the statement:

if (drivingCode = 1)
    cout << "The discount policy on the policy is 25%." << endl;

always outputs:

The discount policy is 25%

because the right side of the assignment expression evaluates to 1, which is nonzero and so evaluates to true. Therefore, the expression on the if statement always evaluates to true. Also, the value 1 is assigned to the variable drivingCode. Suppose that before the if statement, the value of the variable drivingCode is 4. After the if statement executes, not only is the output wrong, but the new value also replaces the old driving code!

The appearance of = in place of == in a program is something of a silent killer. It is not a syntax error, so the compiler does not warn you of an error. Rather it is a logical error.

 

Moreover, the appearance of the equality operator in place of the assignment operator can also cause errors in a program. Suppose, for example, that x, y, and z are int variables. The statement:

x = y + z;

assigns the value of the expression y + z to x. The statement

x == y +z;

compares the value of the expression y + z with the value of x; the value of x remains the same, however. If elsewhere in the program you are counting on the value of x being y + z, a logic error will occur: the program would be incorrect, but you would receive no warning of this from the compiler. The compiler provides feedback only about syntax errors, not logic errors.

Conditional Operator (?:)

...discussion of the conditional operator (?:)...

 

switch Structures

While the if and if...else selection or branch structures require the evaluation of a (logical) expression, C++'s switch structure gives the computer the power to choose from among many alternatives.

The general structure of the switchs statement is:

switch (expression)
{
case value1: statements1
     break;
case value2: statements2
     break;
...
case valuen: statementsn
     break;
default: statements
}

First the expression is evaluated. The value of the expression is the used to perform the action specified in the statements that follow the reserved word case.

The expression, (also called the selector) is usually an identifier and can be only integral. Its value determines which statement is selected for execution. A particular case should appear only once, and may hold multiple statements. There is no need to use braces to turn multiple statements into a single compound statement. The break statement may or may not appear after each statement.

The switch statements executes according to the following rules:

  1. When the value of the expresion is matched against a case (also called a label), the statement executes until either a break statement is found or the end of the switch statement is reached.
  2. If the value of the expression does not match any of the case values, the statements following the default label execute. If the switch structure has no default label, and if the value of the expression does not match any of the case values, the entire switch statement is skipped.
  3. A break statement causes an immediate exit from the switch structure.

Example:

switch ( grade )
{
case 'A': cout << "Grade: A";
          break;
case 'B': cout << "Grade: B ";
          break;
case 'C': cout << "Grade: C ";
          break;
case 'D': cout << "Grade: D ";
          break;
case 'F': cout << "Grade: F ";
          break;
default: cout << "Invalid Grade ";
          break;
}

Here, the expression in the switch statement is a variable identifier (grade) of the data type char, which is an integral type.

Note: When the value of a switch expression matches a case value, all statements execute until a break is encountered, and the program skips all case labels in between.

In addition to being a variable identifier or a complex expression, the switch expression can evaluate to a logical value:

switch (age >= 18)
{
case 1: cout << "Old enough to be drafted." << endl;
        cout << "Old enough to vote." << end;
        break;
case 0: cout << Not old enough to be drafted." << endl;
        cout << "Not old enough to vote." << end;
}

If the value of age is greater than or equal to 18, the expression evaluates to 1--that is, true, and the statements following the case label 1 execute. If the value of age is less than 18, the expression evaluates to 0--that is, false, and the statements following the case label 0 execute.

We can also use true and false instead of 1 and 2 in the preceding switch statement:

switch (age >= 18)
{
case true: cout << "Old enough to be drafted." endl;
        cout << "Old enough to vote." end;
        break;
case false: cout << Not old enough to be drafted." endl;
        cout << "Not old enough to vote." end;
}

Though there aren't any hard and fast rules in this matter, the following considerations should be remembered when deciding whether to use an if...else structure or a switch structure.

Terminating a Program with the assert Function

C++ includes a predefined function, assert, that is useful in stopping program execution when certain elusive errors occur. In program execution situations in which certain conditions are not met, it would be useful to halt the program execution with a message indicating where in the program the error occured. We handle these types of situations by including output and return statements in our program.

The syntax of the assert function is:

assert (expression);

Here, expression is any logical expression. If the expression evaluates to true, the next statement executes; if the expression evaluates to false, the program terminates and indicates where the program error occured.

The specification for the assert function is found in the header file cassert. Hence, for a program to use the assert function, it must include the statement:

#include <cassert>

Example 1:

assert (denominator)
quotient = numerator / denominator

Here, if denominator is 0, the assert statement halts the execution of the program with an error message because 0 evaluates to false.

Example 2 (demonstrates the use of an explicit logical expression):

assert (hours > 0 && (0 < rate && rate <= 15.50 ));
if (hours > 0 && (0 < rate && rate <= 15.50 ))
    wages = rate * hours;

assert statements can be disabled in programs that have been developed, tested, and are ready to ship (to prevent end-users from seeing error messages that might be unintelligible to them). We disable assert statements by using the preprocessor directive:

#define NDEBUG

The preprocessor directive #define NDEBUG must be placed before the directive #include <cassert>.

Top of page

Contact Information

Page Last Updated: Saturday February 12, 2005 10:21 AM