Lecture Set 4 – Selection Structures

 

Required Reading – HK (Hanly/Koffman), Chapter 4 (Skip the Water Bill with Conservation Case Study)

            Study Carefully: The Water Bill Problem

 

 

The next two Chapters (4 and 5) … what’s this all about?

 

It’s about patterns in programming.  We discussed this early in the course.

 

We examined the ATM example and found sequences, decisions, and repetitions embedded in our analysis of the required behavior of the ATM software system.

 

Until now, our focus has been on sequences, and features of the C language useful in

programming sequences.

 

In Chapters 4 and 5, we examine the other two primary patterns of programming – decisions and loops.

 

We will learn about several different forms of decision patterns and of loop patterns and about how and when to use these different patterns.

 

This is problem-solving … developing tools and recognizing when to use them.

 

We begin with decisions …

 

 

A.     Decisions in programs

 

Example 1:

if (toupper(dchar) == ‘M’) then

   draw_Mfig();

else

   draw_Ffig();

 

How does this work – i.e., what does it do?  We need to read it out loud!!

 

So – let’s do it!

 

Decision structures

 


 

B.     Psuedo-code examples of conditional statements and branching

 

Example 2: if x is not equal to zero then

                               divide y by x

 

This is a single-alternative decision pattern.

 

It can be read as follows: If the condition "x is not equal to zero" is TRUE, divide the value of y by the value of x

 

Otherwise (else), the condition "x is not equal to zero" is FALSE.  In this case, no alternative action is taken because no alternative actions have been specified if the statement is FALSE

 

      Example 3: if x is not equal to zero then

                              divide y by x

                         else // otherwise

                              display an error message

 

This is a double-alternative decision pattern.

 

We read it as follows:  If the condition "x is not equal to zero" is TRUE, divide the value of y by the value of x

 

Otherwise, the condition "x is not equal to zero" is FALSE.  Display an error message

 

      Example 4: if x is less than zero then

                              set y equal to -1

                         else if x is equal to zero then

                              set y equal to 0

                         else

                              set y equal to 1

 

This is a multiple-alternative decision pattern.

 

We can read it as follows: If the condition "x is less than zero" is TRUE, set the value of y to -1

 

Otherwise, the condition "x is less than zero" is a FALSE.  So if the condition "x is equal to zero" is TRUE, set the value of y to 0

 

Otherwise, the conditions "x is less than zero" AND  "x is equal to zero" are both FALSE, so we set the value of y to 1 no matter what

 

C.     Why use pseudo code at all?

 

The book also uses flow charts, which are sometimes handy for visualizing what is going on with a decision structure.  However, pseudo-code, if properly indented and written with a little care is a preferred mechanism for mapping out the logic of a decision before trying to program it (and having to worry about syntax).

 

 

D. Revisiting Examples 2, 3, and 4  -  pseudo-code => C

 

Example 2: if x is not equal to zero then

                               divide y by x

 

     if (x != 0)

          … = y / x;

 

 

      Example 3: if x is not equal to zero then

                              divide y by x

                         else // otherwise

                              display an error message

 

     if (x != 0)

          … = y / x;

     else

          printf (“ … “);

 

 

      Example 4: if x is less than zero then

                              set y equal to -1

                         otherwise if x is equal to zero then

                              set y equal to 0

                         otherwise

                              set y equal to 1

 

     if (x < 0)

        y = -1;

     else if (x == 0)  // be careful with this equality operator

        y = 0;

     else

        y = 1;

 

E. How Do These If Structures Work?

 

When the first condition in an "if" control structure evaluates to TRUE the dependent statements for that part of the structure are executed.  The rest of the statements in the "if" control structure are "skipped".  The program execution continues with the first executable statement after the end of the "if" control structure.

1)  When the "if" statement control structure has only ONE dependent statement then the curly braces { } are NOT required. 

 

       if (condition)

          // Single dependent statement executed when the

          //     condition evaluates to True

          dependent statement;

 

         However, it's ALWAYS a good idea to use braces { } even when they're not required.

 

    if (condition)

    {

       // Single dependent statement executed when the

       //     condition evaluates to True

       dependent statement;

    }

 

         When the "if" statement control structure has multiple dependent statements then the

         curly braces { } ARE required.

 

    if (condition)

    {

       // Dependent statements executed when the

       //      condition evaluates to TRUE                                                   

           dependent statement1;

           dependent statement2;

           ...

           dependent statementN;

     } // end if

 

      2)  Here are some other example forms of if statements …

 

The end of the "if" control structure is defined by the closing curly brace of the last "if", "else if" or "else" code block if the curly braces are used, or the last dependent statement in the last "if", "else if" or "else" code block if the curly braces are not used.

 

Single Alternative Decision Structure

 

    if (condition)

    {

       // Dependent statements executed when the

       //      condition evaluates to TRUE                                                    

            dependent statement1;

              ...

            dependent statementN;

          } end if

          /* Closing curly brace of the "if” code block which

             is the end of the "if" control structure  */

         next executable statement;

 

 

Double Alternative Decision Structure

 

    if (condition)

    {

       // Dependent statements executed when the

       //      condition evaluates to TRUE                                                    

            dependent statement1;

            dependent statement2;

              ...

            dependent statementN;

          }

          else

          {

       // Dependent statements executed when the

       //      condition evaluates to FALSE                                                   

            dependent statement1;

            dependent statement2;

              ...

            dependent statementN;

          } // end if

          /* Closing curly brace of the "else" code block

             which is the end of the "if" control structure  */

 

          next executable statement;

 

 

Multiple Alternative Decision Structure

 

    if (condition)

    {

       // Dependent statements executed when the

       //      condition evaluates to TRUE                                                   

            dependent statement1;

            dependent statement2;

              ...

            dependent statementN;

          }   // end of “TRUE” block

          else if (condition1)

          {

       // Dependent statements executed when condition is

       //    FALSE and condition1 is TRUE                                                   

            dependent statement1;

            dependent statement2;

              ...

            dependent statementN;

          }

          /* Closing curly brace of first "else if" code block */

               ...

 

     else if (conditionN)

          {

             /* Dependent statements executed when condition, and

                condition1 through condition(n-1) all evaluate to

                FALSE and conditionN evaluates to TRUE

             */

             dependent statement1;

             dependent statement2;

              ...

             dependent statementN;

          }

          /* Closing curly brace of last "else if" code block */

          else

          {

             /* Dependent statements executed when ALL previous

                conditions evaluate to FALSE  

             */

             dependent statement1;

             dependent statement2;

              ...

             dependent statementN;

          }  end if

          /* Closing curly brace of the "else" code block which

             is the end of the "if" control structure */

 

          next executable statement;

 

3)   Note that in the above forms, anyone or more of the dependent statements are often just a single dependent statement (in which case the braces MAY be omitted).

 

      4)  Some coding examples:

           a.)    if (x > y)      

        {

           temp = x;

           x = y;

           y = temp;

         }

 

                   How can we figure out what this does?  Hand trace?  What about this:

 

           b.)  if (age >= 65)      

           printf ("Older than 65 year old male or female\n");

        else if (age >= 18 && age <= 21)

           if (gender == 'M' || gender == 'm') // the OR operator

              printf ("18 to 21 year old male\n");

           else

              printf ("18 to 21 year old female\n");

        else if (age < 16)

           printf ("Younger than 16 year old male or female\n");

        // end if

        printf ("Done with the if statement\n")

  5)   General form of a logical expression:

 

         (expression   relational_operator   expression)

 

         where

 

         "expression" is a variable, function that returns a value, constant,

           logical or mathematical expression or “any combination thereof”

 

         "relational_operator" is a comparison symbol showing a relationship

           between the two expressions:

 

Symbol  Relationship between expressions     Example

 ------  --------------------------------     -------

  <   exp1 is LESS THAN exp2              (exp1 < exp2)

  <=  exp1 is LESS THAN OR EQUAL TO exp2  (exp1 <= exp2)

  >   exp1 is GREATER THAN exp2           (exp1 >  exp2)

  >=  exp1 is GREATER THAN OR EQUAL TO exp2 (exp1 >= exp2)

  ==  exp1 is EQUAL TO exp2               (exp1 == exp2)

  !=  exp1 is NOT EQUAL TO exp2           (exp1 != exp2)

 

The Relational Operators are binary operators that require two pieces of information, called operands, to operate on.  Relational Operators determine the relationship between two pieces of data which is what  makes them binary operators.  Note that == and != are sometimes referred to as equality operators.

 

         There is one additional Logical Operator called the "NOT" operator

         that is used to reverse the result of evaluating an expression:

 

         Symbol                Meaning                                   Example

         ---------  ----------------------------------------           ----------

              !        Opposite result of an expression              !exp1

 

         The NOT operator is a unary operator that requires one operand to operate on.

         The NOT operator is used to reverse the result of one expression.

 

         The result of using the NOT operator on an expression that evaluates

         to TRUE is read as NOT TRUE which is equal to FALSE.  The result of

         using the NOT operator on an expression that evaluates to FALSE is

         read as NOT FALSE which is equal to TRUE.

 

         Examples:

a)  x != y          !(x = y)

b)  x >=y          !(x < y)

         c) (x <= y)    

         d) (x != y + z)

         e) (m % n == 0)

 

         The NOT operator can be used to construct equivalent conditions in a

         more intuitive way.  For example, the following two expressions are

         equivalent ways of checking whether the value of x is NOT LESS THAN

         the value of y:

 

         (x >= y) The value of x is GREATER THAN OR EQUAL TO the value of y

 

                  This form of the condition requires you to understand that

                  the value of x is NOT LESS THAN the value of y if the value

                  of x is GREATER THAN OR EQUAL TO the value of y

 

         !(x < y) NOT the value of x is LESS THAN the value of y

 

                  This form of the condition is more intuitive because you are

                  checking directly to see if the value of x is LESS THAN the

                  value of y and using the NOT operator to reverse the outcome

                  which makes the expression equivalent to saying the value of

                  x is NOT LESS THAN the value of y

 

 

6)   Representation of logical or Boolean values in C –

     

                             BEWARE, THIS DOG BYTES!

 

 All logical conditions will evaluate to one of two possible outcomes, either TRUE or

 FALSE.  There is no such thing as both TRUE and FALSE, partially TRUE,

 somewhat FALSE, etc., there are only two possible outcomes from evaluating any

 logical condition, either TRUE or FALSE. 

 

 The TRUE dependent statement(s) OR the FALSE dependent statement(s),

 if there are any, will be executed depending upon whether the logical

 condition evaluates to TRUE or FALSE.

 

The logical values TRUE and FALSE are represented in by integer values.  The integer value 0 represents the logical value FALSE.  Any non-zero integer value (any integer value other than 0) represents the logical value TRUE. 

 

 
 

 

 

 

 


        

 


 

Let’s see what this implies by looking at examples.

 

Example 1:

 

int x = 0, y = 1;

 

if (x)

   printf ("x is TRUE\n");

else

   printf ("x is FALSE\n");

 

    The FALSE  dependent statement:

 

   printf ("x is FALSE\n");

 

     will be executed and display the following:

 

                  x is FALSE.    Why?

 

Example 2:

 

int x = 0, y = 1;

 

if (!y)

   printf ("!y is TRUE\n");

else

   printf ("!y is FALSE\n");

 

 

     Here, the FALSE dependent statement:

 

           printf ("!y is FALSE\n");

 

     will be executed and display the following:

 

                        !y is FALSE       Why?

 

 

 

7)   Joining two or more logical expressions

 

 

                        (logical_expression join_operator logical_expression)

 

         where

 

         logical_expression is a logical expression (involving the relational operators <=, >=, ==, <, >, !=) that results in a TRUE (non-0) or FALSE (0) value.

 

         "join_operator" is a join operator (&&, or ||) showing a relationship between the two logical expressions:

 

         Symbol  Name                            Meaning

         ------      --------  ----------------------------------------------------

          &&        AND    BOTH logical expressions MUST evaluate to TRUE in

                                     order for the overall expression to evaluate to TRUE

             ||          OR       EITHER logical expression can evaluate to TRUE in

                                     order for the overall expression to evaluate to TRUE

 

 

 

 

         For example, the expression 1 || 0 || 1 && 0 will NOT be evaluated

         in order from left to right because the AND operation is of higher

         precedence than the OR operations:

 

         Step 1: (1 || 0 || 1 && 0) - 1 && 0 evaluates to FALSE (0)

         Step 2: (1 || 0 || 0     ) - 1 || 0 evaluates to TRUE (1)

         Step 3: (     1 || 0     ) - 1 || 0 evaluates to TRUE (1)

         Step 4: (          1     ) - 1 is interpreted as TRUE

 

         The following matrix illustrates the results of joining two logical expressions using the AND '&&' operator:

 

         Logical Expression 1    Logical Expression 2                    Result  

                        T                                  T                                    T

                        T                                  F                                    F

                        F                                  T                                    F

                        F                                  F                                    F

         The following matrix illustrates the results of joining two logical

         expressions using the OR '||' operator:

 

         Logical Expression 1    Logical Expression 2                    Result  

                        T                                  T                                    T

                        T                                  F                                    T

                        F                                  T                                    T

                        F                                  F                                    F

 

      8) Coding Examples:

 

          Example 1:

 

       if (x == y)

       {

          printf ("x and y are equal\n");

       }

       else

       {

          printf ("x and y are NOT equal\n");

       }

 

           The condition (x == y) reads as "the value of x is EQUAL TO the value of y". This condition evaluates to TRUE if and only if x and y contain the same values.

 

            Example 2:

 

        if (x + y > 4)

        {

           printf ("x + y is greater than 4\n");

        }

        else

        {

           printf ("x + y is NOT greater than 4\n");

        }

 

            The condition (x + y > 4) reads as "the result of adding the value

            of x to the value of y is GREATER THAN 4". 

 

            How would you read the condition (x + (y > 4)), and how would you describe the result?

 

            How do we know the order of evaluation of expressions such as

               x + y > 4      x + y <= z*3     x + y && w + 3 != 16 * 2

 

            Answer:  We need to get familiar with the operator precedence chart.

The moral of the story here is not to memorize this table, but to be aware that precedence is something to be kept in mind when you write expressions.  If you are not absolutely sure what you will get as a result, either look up the operators involved in the table or use parentheses.

 

 
 

 

 

 

 

 

 

 


       

 

          Example 3:

 

       if (x != 'D')

       {

          printf ("x is NOT equal to the character 'D'\n");

       }

       else

       {

          printf ("x is equal to the character 'D'\n");

       }

 

The condition (x != 'D') reads as "the value of x is NOT EQUAL TO the character 'D'".  This condition evaluates to TRUE if the value of x is the character 'R' which is NOT EQUAL TO the character 'D'.   Otherwise it evaluates to FALSE.

 

         Example 4:

 

(marital_status == ‘S’ && gender == ‘M’)

 

This expression evaluates to TRUE if the contents of marital_status is ‘S’ (for single) and if the contents of gender is ‘M’ (married).  Otherwise it evaluates to FALSE.  Note that if marital_status == S is FALSE (marital_status does not contain an S) the gender == ‘M’ evaluation will be short-circuited (not bothered with).  Once we know that any part of a logical expression involving && is FALSE, the entire expression must be FALSE. 

 

Example 5:

 

a.     (!(marital_status == ‘S’ || gender == ‘M’))

b.     !(!(marital_status == ‘S’) || !(gender == ‘M’))

 

One of these logical expressions is identical to the logical expression in Example 4.

Can you tell which one?  How did you do it?

How do you know whether the operator || or ! is evaluated first?

Does it matter which is evaluated first?  Justify your answer.

 

 

   8)  The "switch" statement

 

         General form of the "switch" statement control structure:

 

         switch (expression)

         {

            case value1:

               /* Sequence of one or more dependent statements

                  executed when the expression is equal value1

               */

 

               dependent statement1;

               dependent statement2;

                  ...

               dependent statementN;

               break;

            case value2:

               /* Sequence of one or more dependent statements

                  executed when the expression is equal value2

               */

               dependent statement1;

               dependent statement2;

                  ...

               dependent statementN;

               break;

            case valueN:

               /* Sequence of one or more dependent statements

                  executed when the expression is equal valueN

               */

 

               dependent statement1;

               dependent statement2;

                  ...

               dependent statementN;

               break;

                          default:

               /* Sequence of one or more dependent statements

                  executed when the expression none of the values

                  value1, value2, … valueN is equal to the

                  expression.

               */

               dependent statement1;

               dependent statement2;

                  ...

               dependent statementN;

               break;

         }

         where

 

"expression" (called the controlling expression) can be any integer –valued or character-valued expression and the values (value1 … valueN) are integer or character values to which the expression is compared. 

 

         The expression that you "switch" on must evaluate to either an integer

         OR a character value.  The resulting value is compared to the value

         in each of the case statements until a matching case value is found. 

         Once a matching case value has been found no more comparisons take

         place and the remaining case statements are in effect ignored.  The

         the switch statement executes the appropriate dependent statements

         until the switch statement has finished executing.

 

Note that is a break statement is omitted at the end of any set of dependent   statements, then all dependent statements following the first matching case statement are executed one after another until EITHER a

 

i)  another break statement is reached or

   ii) the end of the switch statement is reached,

 

which ever comes first.  The break causes the program execution to "break" out of the switch statement and transfer control to the first executable statement that occurs after the end of the switch statement.  This causes the remainder of the switch statement to be skipped.  The end of the switch statement is defined as the closing curly brace on the switch statement.

 

It's EXTREMELY important to remember that the dependent statements following the first matching case statement are executed until EITHER a break statement is encountered or the end of the switch statement has been reached.  This means that if there are no break statements encountered, additional dependent statements will be executed that may belong to subsequent case statements.  This is commonly referred to as "falling through" into the next case statement.  This is not a problem if it is done intentionally since you presumably wanted the additional dependent statements to execute.  However, if the break statement or statements are omitted unintentionally the results will not be what you expect!

 

 

 
 

 

 

 

 

 

 

 

 

 

 

 

 

 


      Example 1:

 

     int main()

     {

         char grade;   // Hold a letter grade entered by a user

 

         /* Get the letter grade from the user */

         printf ("Enter the student's grade > ");

         scanf ("%c", &grade);

 

         /* Display the appropriate message by "switch"ing on the 

         /* letter grade entered by the user                      

 

         /* Compare the value of the variable grade to the each

            of the cases until it matches a case.  Once you have

            matched a case, no other attempts are made to match

            any more cases.  At this point, the computer executes

            the dependent statements for the matched case until

            a break is encountered or the end of the switch is

 encountered, which ever comes first.

         */

 

         switch (grade)

         {

            case 'A': // if grade matches case 'A', continue here

            case 'a'    // if grade matches case 'A', continue here

                printf ("%c = Excellent\n", grade);

                break;

            case 'B': // if grade matches case 'B', continue here

            case 'b': // if grade matches case ‘b’, continue here

                printf ("%c = Good\n", grade);

                break;

            case 'C': // if grade matches case 'C', continue here

            case 'c': // if grade matches case ‘c’, continue here

                printf ("%c = Average\n", grade);

                break;

            case 'D': // if grade matches case 'D', continue here

            case 'd': // if grade matches case 'd', continue here

                printf ("%c = Below Average\n", grade);

                break;

            case 'F': // if grade matches case 'F', continue here

            case 'f': // if grade matches case 'f', continue here

                printf ("%c = Failing\n", grade);

                break;

            default:

                /* The only way to reach here is if grade did NOT

                   match any of the cases 'A', 'a', 'B', 'b',

                   'C', 'c', 'D', 'd', 'F' or 'f'.

                */

                printf ("Invalid grade entered - %c\n", grade);

        } // end of switch

       return (0);

   ;

           

Example 2: 

 

       int main()

       {

                    char color;  // contains color entered by user

 

           // Get the color from the user as a capital letter

           printf ("Enter the color > ");

           scanf ("%c", &color);

 

/* Display the appropriate message by "switch"ing on the color entered by the user. Compare the value of the variable color to the each of the cases until you match a case. until it matches a case.  Once you have matched a case, no other attempts are made to match any more cases.  At this point, the computer executes the dependent statements for the matched case until a break is encountered or the end of the switch is encountered, which ever comes first.                                          

*/

 

           switch (color)

           {

              case 'R': 

                 printf ("%c = Red\n", color);

              case 'G':         

                 printf ("%c = Green\n", color);

              case 'B': 

                 printf ("%c = Blue\n", color);

                 break;

              case 'Y': 

                 printf ("%c = Yellow\n", color);

                 break;

              case 'O': 

                 printf ("%c = Orange\n", color);

              case 'P': 

                 printf ("%c = Purple\n", color);

              default:

                 /* The only way to reach here is if color did

                    NOT match any of the cases 'R', 'G', 'B',

                    ‘Y’, ‘O’, or ‘P’.

                                     */

                 printf ("Invalid color entered - %c\n", color);

         } // end of switch

      return (0);

   ;

 

 

Note that we omitted break statement from the Red, Green, Orange and Purple cases.      

 

Describe what will happen in the execution of this switch statement if the variable color is Red?  What if the variable color is Orange?

 

What will happen if the user enters ‘V’ for violet?