| |
Main Menu | Next Chapter |
| Section IV : Branch Statements | Section I: Variables | Section II: Our First Program | Section III: Iteration |
A. The Basic If...Else
As we just learned, the while statement allows us to repeat some number of
instructions over and over. It does not, however, allow us to decide which
instruction or set of instructions to execute and which to skip. For example, suppose we
wish to include the code to calculate overtime pay as part of the program
you just read. In English we might state the overtime rule as follows:
If the hours worked is greater than 40
-calculate the regular salary by multiplying the first 40 hours
by the rate of pay;
-calculate the overtime pay rate by multiplying the pay rate
by 1.5 ('time and a half');
-calculate the overtime salary by multiplying the hours over 40
by the overtime pay rate;
-add the two salaries together to get the full salary
Else
-calculate the full salary by multiplying the hours worked
by the rate of pay;
In other words, do the first set of instructions if the person has worked
more than 40 hours (a typical definition for overtime) and another set
if the person has not worked more than 40 hours. Just as the 'while' loop
construct uses a test condition to decide whether to execute the code inside
the loop, the code for the 'if' construct executes a test to determine
which code branch to take. Let's start with the simple, non-looping
form of the employee salary problem found in section
II-E above and add the necessary code to calculate overtime pay:
// A program to calculate the salary for one employee without // deductions. The salary and rate of pay are input by a user. // File: ch2prg6.cpp #include <iostream.h> const int REGULAR_HOURS = 40; const double OVERTIME_ADJUSTMENT = 1.5;
void main()
// Purpose: to calculate the salary for one employee
// Receives: NONE
// Returns: NONE
{
double rateOfPay;
double overtimeRateOfPay;
double regularSalary;
double overtimeSalary;
double fullSalary;
double hoursWorked; // can be a fraction of an hour
cout << "Please enter your rate of pay: ";
cin >> rateOfPay;
cout << "Please enter the hours you worked this week: ";
cin >> hoursWorked;
if (hoursWorked > REGULAR_HOURS)
{ regularSalary = REGULAR_HOURS * rateOfPay;
overtimeRateOfPay = rateOfPay * OVERTIME_ADJUSTMENT;
overtimeSalary = (hoursWorked - REGULAR_HOURS) *
overtimeRateOfPay;
fullSalary = regularSalary + overtimeSalary;
}
else
{ fullSalary = hoursWorked * rateOfPay;
}
cout << "Your f\salary is: " << fullSalary;
}
You can see the 'if' statement here but before we discuss it, let's take
a look at another item introduced, the named
constant.
The lines:
act like variable declarations (and definitions) with immediate initialization. The difference is that, because of the word const, these memory locations cannot have their values changed! It would be illegal given this code to write, for example:
elsewhere in this program.
Whenever there is a value that does not change in a program it can be called a constant. We have already used a number of string constants as in:
The two values 40 and 1.5 in the above program clearly do not change and are referred to as numeric constants. Note that neither the string constant "Your salary is" nor the numeric constants '40' or '1.5' have identifier names. In fact, they do not have any computer memory locations associated with them. However, 'REGULAR_HOURS' and 'OVERTIME_ADJUSTMENT' are identifiers and they represent symbolic names for specific memory locations. Since these two identifiers cannot be changed but they refer to specific memory locations with symbolic names, they are referred to as 'named constants'.
These two identifiers can be used anywhere a numeric constant can be used, for example, on the right side of arithmetic expressions or in comparisons. In such cases, any references to 'REGULAR_HOURS' or "OVERTIME_ADJUSTMENT' in the code will use the values '40' and 1.5' respectively.
It is usually wise not to use numeric constants (such as 40 and 1.5) directly in your code. Instead, you should uniquely identify any values that do not change in your program - your numeric constants - as named constants. There are two reasons for this. First, we talked above about providing good names for our variables, about how that makes our programs more readable. If you include a number in a program, that number does not explain itself. The values '40' and 1.5' have no meaning in themselves. Someone who knew that 40 was a value commonly used as the difference between regular and overtime work might recognize its use in this program but it would not be self-explanatory.
Imagine a more complex piece of code that used the value 1.324 to represent the salary adjustment for employees who work the night shift. It is most unlikely that anyone outside of the personnel department would know the meaning of 1.324. Since often programmers are not familiar with the intricacies of the department or organization for which they are coding, any code that used the value 1.324 in this way would not be intuitively readable. On the other hand, if the code had a reference to 'NIGHT_SHIFT_PAY_ADJUSTMENT', any programmer reading this code would have some sense of what this was about. He or she may not understand exactly how night shift pay is calculated, but they would know, at least in a general sense, what the code was attempting to do. As mentioned earlier, one should always strive to write code that is as readable as possible.
That is reason number one. The second reason for using 'named constants'
involves potential changes to code. For example, someday the United States
will realize that the benefits of factory automation need to be shared
with employees and the regular work week will be reduced to say 30 hours.
At that time the program we just wrote will need to be changed. If we had
written '40' in all the places where the letters 'REGULAR_HOURS' appear,
we would have to change all those '40's to '30's. In this example, all
the lines where the value '40' would appear are near each other but imagine
a much larger program where uses of this same '40' are separated by 100's
or 1000's of code lines. The odds are very good that at least one of the
40's would not get changed. However, if we declare REGULAR_HOURS' as a
'named constant' with the value 40 and use it in all the relevant places,
we only need to make the change from 40 to 30 in one spot - the constant
declaration. In other words, to use '30' as the basis for calculating overtime
pay in the above program you only need change:
Note that the only difference between a 'named constant' and a variable is that a 'named constant' cannot be changed once it is declared. Such constants are also symbolic names for memory locations and they can be used most any place a variable can be used if we are only accessing, not changing, the value of the 'named constant'. (At this point we shall stop making the distinction between numeric constants such as '40' and 'named constants' such as REGULAR_HOURS. Both will be referred to as constants unless the distinction is needed for clarity.)
Although constants and variables are almost the same they are still different. To emphasize that certain symbolic names represent constants and not variables, we will write all 'named constants' in upper-case letters with underbars to make multi-word constant names more readable. In contrast, variable names are written in lower case except that in multi-word variables the first letter of every word (except the first) is in upper case. See the Style Sheet for more details.
Back to the discussion of the 'if' statement and its use in calculating salaries. Now we can focus on the code:
cout << "Please enter your rate of pay";
cin >> rateOfPay;
cout << "Please enter the hours you worked this week";
cin >> hoursWorked;
if (hoursWorked > REGULAR_HOURS)
{ regularSalary = REGULAR_HOURS * rateOfPay;
overtimeRateOfPay = rateOfPay * OVERTIME_ADJUSTMENT;
overtimeSalary = (hoursWorked - REGULAR_HOURS) *
overtimeRateOfPay;
fullSalary = regularSalary + overtimeSalary;
}
else
{ fullSalary = hoursWorked * rateOfPay;
}
cout << "Your salary is: " << salary;
The fifth line down contains the 'if' statement. Note that the test is
written the same as it would be in a while statement:
In this case, the code is testing to see if the hours worked entered by the user is greater than 40, the value in the constant REGULAR_HOURS. If the answer is yes, the code in the brackets just after the test is executed; if not, the code in the brackets just after the 'else' is executed. When you stop to consider it, this is exactly the same way we would use an 'if...else' statement in English. Don't read into this construct something mysterious or complex.
Note further that there is no loop here. Either the code in the first set of brackets is executed OR the code in the second set is executed but not both and NOT over and over. Don't confuse the 'if' and 'while' statements. They have quite different purposes.
The code inside the 'if' statement should be clear from our earlier discussion of the arithmetic operators. The one new part is that the single arithmetic expression:
overtimeSalary = (hoursWorked - REGULAR_HOURS) * overtimeRateOfPay;is split over two lines. It turns out that spacing and line breaks are irrelevant in C++ in almost all circumstances. This code could just as easily have been written:
overtimeSalary = (hoursWorked - REGULAR_HOURS) * overtimeRateOfPay;The major exception to this rule is that one should not insert line breaks inside quoted text - as in output.
As this code stands, it is not very useful because it only calculates the salary for one employee. To allow this program to calculate the salary for ten employees you need to add a loop similar to the ones we have already seen. Inside that loop you place the code we just wrote. For example:
// A program to calculate the salaries for 10 employees // File: ch2prg7.cpp #include <iostream.h> const int REGULAR_HOURS = 40; const double OVERTIME_ADJUSTMENT = 1.5;void main() // Purpose: to calculate and output the salaries for 10 // employees based on rate of pay and hours worked data entered // by a user // Receives: NONE // Returns: NONE { double rateOfPay; double overtimeRateOfPay; double regularSalary; double overtimeSalary; double fullSalary; double hoursWorked; // can be a fraction of an hour int count = 0; // initialize the counter to 0 while (count < 10) { cout << "Please enter your rate of pay"; cin >> rateOfPay; cout << "Please enter the hours you worked this week"; cin >> hoursWorked; if (hoursWorked > REGULAR_HOURS) { regularSalary = REGULAR_HOURS * rateOfPay; overtimeRateOfPay = rateOfPay * OVERTIME_ADJUSTMENT; overtimeSalary = (hoursWorked - REGULAR_HOURS) * overtimeRateOfPay; fullSalary = regularSalary + overtimeSalary; } else { fullSalary = hoursWorked * rateOfPay; } cout << "Your salary is: " << fullSalary << endl; count++; } }Our program is beginning to look a bit more complex. Inside the function 'main' is a 'while' loop and inside of the while loop there is an 'if' statement. Such 'nested' code is very common in complex programs and it can occur in many forms. It is possible to have 'while' statements inside other 'while's; 'if' statements inside 'if's; and all possible mixtures. This complexity can lead to serious errors in the code and we shall see in future chapters that modern programs use a number of tools to manage and reduce such complexity.One minor point about this code: We have been skipping the 'endl' in many of our programs because the programs only output one value. Here we must include it in the line that outputs the salary or all the salary statements will appear on one ugly line.
More on the 'if' statement: As in English, it is possible to have an 'if' statement that does not include an 'else' part. A program can have 'if' and 'if...else' statements, but not simply 'else' statements. (Try beginning a sentence in English with 'else'.)
As an example of code involving only an 'if', suppose you were asked to write a program that simply counted the number of employees who worked more than 40 hours during the last pay period. Here is how such a program would look:
// A program to count the number of employees who worked more than 40 hours // during the last pay period // File: ch2prg8.cpp #include <iostream.h> const int REGULAR_HOURS = 40; void main() // Purpose: to count the number of employees working overtime // Receives: NONE // Returns: NONE { double hoursWorked; // can be a fraction of an hour int count = 0; // initialize the counter to 0 int numEmployeesWorkingOvertime = 0; while (count < 10) { cout << "Please enter the hours you worked this week"; cin >> hoursWorked; if (hoursWorked > REGULAR_HOURS) { numEmployeesWorkingOvertime++; } count++; } cout << "The # of employees working overtime: " << numEmployeesWorkingOvertime; }Aside from the existence of an 'if' without an 'else', there is nothing new in this program.B. The Relational Operators
As defined above, operators cause a computer to do something. So far we have seen two relational operators, '<' and '>'. These two operators cause a computer to compare two expressions and return true or false depending on whether the left expression results in a value that is less than (or greater than) the right expression's value. There are four other relational operators - operators that compare or 'relate' two values. We have ready said that '<' means "less than" while '>' means "greater than. If you think about it, in English there are four other possibilities and all six are shown here:The last one needs some commentary. There is an important difference between "=' or 'assignment' and "==" or 'equal to'. We described 'Assignment' (=) above. It says that whatever value is on the right side of the "=" symbol should be put into the memory location symbolized by the variable on the left side of the "=" symbol. You have been using this all along, for example in the lines:
< Less Than > Greater Than <= Less than or equal to >= Greater than or equal to != Not equal to == Equal to
The 'equal' symbol is used in comparisons. It essentially asks the question - is the left side equal to the right side and the answer that comes back is always C++'s equivalent of 'Yes' or 'No' / 'True' or 'False'. You need to be careful to always use "==" within 'if' and 'while' test conditions or the results you get might surprise you.
Unfortunately, the compiler may give you a warning when you use '=' when you mean '==' but it will let you go ahead. (Compilers have at least two levels of messages - 1) error messages - which are so serious that the compiler cannot translate the code and 2) warning messages which mean - "There might be a problem here that you should look at but I will go ahead and translate your code.") Watch out for these warning messages!
The compiler can make the translation when you use '=' instead of '==' in a test condition because all operators in C++ return a value and because of the way C++ treats True and False. "Returning a value" is an idea that you have already implicitly worked with. When you write:
the '*' operator 'returns' the value calculated by multiplying 'hoursWorked' by 'rateOfPay'. If '*' did not 'return' a value, there would be nothing to store in 'fullSalary'. All arithmetic operators (such as +, +=, -, -+, *=, /, /+, ++, --) return a value for the same reason.
In C++ not only arithmetic operators but all other types of operators return a value. For instance, the relational operators return a value. But, what value do '<', '>', '==' or the other relational operators return? It turns out that they return the value TRUE or FALSE where FALSE is defined as zero and TRUE is defined as ANY other value - – with 1 being the usual value. In other words, if we have the strange test "3 < 5", the '<' operator will return '1' since 3 is less than 5. But, if we have "3 == 5", the operator '==' returns 0 since 3 does NOT equal five. (By the way, note that "3 == 5" and "3 < 5" are not statements of fact as they would be in mathematics, they are operators that perform a test - Remember our earlier discussion of the difference in the way mathematics and C++ interpret the '=' symbol.)
The final piece to this puzzle is that the assignment (=) operator returns whatever value has been assigned. In other words, if we have the line of code:
'sum' gets the value 7 and 7 is returned by the '=' operator. Now consider the line:
The programmer probably meant to write "(sum == 0)" which simply tests to see if 'sum' contains 0. However, by writing "(sum = 0)" the programmer is telling the computer to place 0 in the memory location symbolized by the variable 'sum' and return that 0. Two problems arise: First, since the code always returns 0, the test is always determined to be False (since False is defined in C++ as 0)! Second, whatever value was in the variable 'sum' has been lost, replaced by 0. It is possible but unlikely that this is what the programmer wanted. The moral of the story - "Be careful to use "==' instead of '=' in equality tests." and "Pay attention to warning messages." (OK, so there are two morals to this 'story'.)
With this we complete our first look at the basics of C++. In the next chapter we will begin exploring tools we can use to make sure that the code we write is not only syntactically (grammatically) correct but that it causes a computer to perform the steps we actually want performed.
Examples of the 'if' Statement
| |
Main Menu | Next Chapter |