Lecture Set 4 Selection Structures
Study Carefully: The Water Bill
Problem
The
next two Chapters (4 and 5)
whats this all about?
Its 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
lets 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
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).
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.
Lets 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?
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?