More on Assignment Statements
Common shortcuts for altering value of a variable:
1. Add a value to a variable:
var += value_to_add; //var = var + value_to_add
x += 4; //add 4 to x
2. Multiply a variable by a value:
var *= val_to_mult_by //var = var * val_to_mult_by
x *= 4; //multiply x by 4
3. Same for / and - and %
Examples:
int n = 5; double x = 3.5, y = 2.0; n += 2; // now n is 7 x *= y; // now x is 7.0 x *= y + 2; // mult x (7.0) by (y+2) so x is 28.0
Note that the last line is equivalent to:
x = x * (y + 2);
4. Incrementing and decrementing by 1 is quite common; so there is a special even shorter
notation:
i++; means "increment i by 1"
n--; means "decrement n by 1"
So:
i++; i += 1; i = i + 1; // all the same j--; j -= 1; j = j - 1; // all the same
Example: use these notations to accumulate (i.e. add up a series of values) and also to count the number of values :
int sum = 0; // init sum to 0 is vital int count = 0; // ditto for count int val; // no need to init this double average; // or this cout << "\nEnter 1st number: "; cin >> val; sum += val; count++; cout << "\nEnter 2nd number: "; cin >> val; sum += val; count++; cout << "\nEnter 3rd number: "; cin >> val; sum += val; count++;
// Now we could calculate an average... average = (double) sum/count;
Note the reuse of val - there is no need for a new variable for each new value, since we only need the sum.
Also - in some books or code you will see the notation ++i; This is also legal but is slightly different in some contexts. We will not cover this variation or use it in this course.
Example: Suppose we want to print squares of first few integers:
int i = 1; cout << i*i; // note use of expression i++; cout << i*i; // now i = 2; displays 4 i++; cout << i*i; // now i = 3; displays 9 ...
Example: Suppose we want to print squares of first few odd numbers:
int i = 1; cout << i*i; // i is 1; displays 1 i += 2; cout << i*i; // i is 3; displays 9 i += 2; cout << i*i; // i is 5; displays 25 ...
Control Structures
So far all programs execute from first to last instruction (in sequence top to bottom).
So we have one pattern of execution so far:
1. Sequence
To write complex programs, we need to alter the flow of execution.
We will need only 3 new patterns:
2. repeat a set of instructions ( also called looping)
3. decide which block of instructions to execute
4. branch to a separate group of instructions and return (or function calling - which we will study in detail later).
Any program - no matter how complex - can be written with just the first three patterns: sequence, repetition, decision.
Writing programs using these three patterns together is called structured programming.
Branch and return is nice and has real advantages in complex programs, but the first three are sufficient for any program.
Decisions
The decision structure allows the program to execute one or another set of instructions - to decide which set to execute. Or it can decide simply not to do a set of instructions.
So it determines whether or not sections of code are executed.
Example: imagine you need to calculate an average, but there is a possibility that actually no values have been accumulated. That is, the count of numbers whose average is to be found is 0.
We'd like to be able to code something that expresses:
"if count is 0 then display a message, otherwise calculate and display the average"
We should do this just when we are ready to try to calculate an average. And we can do it in C++ like this:
if (count == 0) //Note: two = signs for comparison cout << "\nNo data entered"; else cout << "\nAverage: " << (double) tempSum/count;
| Using one = is an assignment statement
which will compile and execute, but will not mean what you think it means.
In short: to compare for two things being equal, you must use two = signs: if (x == 10)
If you code: if (x = 0)
then you are assigning 0 to x and the truth of the condition will depend on the value stored into x. In C and C++ the value 0 is considered to be false and any other number is true. We will revisit this idea later. For now just remember to use
|
There are two forms of the if statement
if (condition)
{
block of statements to execute if condition is true;
}
if (condition)
{
block of statements to execute if condition is true;
}
else
{
block of statements to execute if condition is false;
}
If the block is only 1 statement long, the {} aren't required:
if (cond) stmnt;
if (cond) stmnt; else stmnt;
Note the use of ;
We will study a couple of further variations on if statements later as well as a couple of alternative instructions that implement decisions.
Repetition or Looping
In C++ there are 3 instructions that build loops:
The for Statement.
int i;
for (i = 0; i < 10; i++)
cout << i;
... the pgm continues...
This says:
This loop would produce the following output:
0123456789
Note that "running the loop" from 0 to 9 executes the body 10 times.
Recall the code to print the squares of the first few odd numbers? Now we can use a for loop to compress it:
int i;
int num = 1;
for (i = 1; i <= 5; i++)
{
cout << i << " The square of " << num
<< " is " << num*num << endl;
num += 2;
}
This would produce:
1. The square of 1 is 1
2. The square of 3 is 9
...
5. The square of 9 is 81
Notes:
If you don't code the {}, only the first statement following the for is considered to be part of the loop body.
and in the code above (without the {}), you would get:
1. The square of 1 is 1
2. The square of 1 is 1
...
5. The square of 1 is 1
because although i is incremented, num += 2; was not executed until after the loop finished.
The three expressions in the for loop's () can be thought of as:
The initialization and the "final" part can have more than one instruction - they are separated by commas. For example, if you wanted to initialize two variables, i and j to 0 and to increment both after the body of the loop is executed, it would look like this:
for (i = 0, j = 0; i < 10; i++, j++)
{ loop body }
Finally, because the exit condition is tested before the loop body is executed, the for loop is classified as a top-driven loop. If the exit condition is true the first time it is tested, the loop body will not execute at all.
The while Statement
Often we don't know in advance how many times loop should execute, so we can't use for in its role as a counting loop as shown above.
Example: ask the user to enter some numbers and then find their average.
We could:
We'll use the while loop to code the second way.
Format of while loop:
while (condition)
{
body of loop
}
This is a top-driven loop. The "condition" is tested before the execution of the code in the body of the loop. It is tested before the body is executed the very first time - and if it is false, the body of the loop will not be executed at all. So the loop could execute 0 times.
There are a couple of patterns we could use for the averages program.
Pattern 1:
get aTemp from the user
while (aTemp > -999) //using special value for exit
{
process aTemp
get next aTemp from user
}
calculate average
Pattern 2:
while (1)
{
get aTemp from user
if (aTemp <= -999)
break; //break jumps out of loop
process aTemp
}
calculate average
Notes:
Complete averages program, Pattern 1:
// Program to calculate average temperatures from // user input. // User enters -999 or less to quit #include <iostream> using namespace std;
int main() { int aTemp; int tempSum = 0; int tempCount = 0; cout << "\nEnter a temperature (-999 to quit): "; cin >> aTemp; while (aTemp > -999) { tempCount++; tempSum += aTemp; cout << "\nEnter next temperature (-999 to quit): "; cin >> aTemp; } cout << "\nAverage is " << (double)tempSum/tempCount;
return 0; }
(As an exercise: convert this to Pattern 2)
(One flaw: what if user enters -999 as first number? You should know how
to fix this by now.)
Another version of the average program
Some applications will not have any natural "special value" - e.g. a speed can be any + or - value.
So we need another way to tell when to stop the looping - that is, a different exit condition.
One way is to ask user each time, and accept an answer (as a string).
// Program to calculate average speeds from user input // User is asked after each value of there is more data. #include <iostream> using namespace std; int main() { int aSpeed; int speedSum = 0; int speedCount = 0; string choice = "y"; while (choice == "y") // see note below { cout << "\nEnter a speed: "; cin >> aSpeed; speedCount++; speedSum += aSpeed; cout << "\nAnother? (y/n) "; cin >> choice; } cout << "\nAverage is " << (double)speedSum/speedCount; }
Note: You will later learn more about strings and how to compare them. This technique is simple and will do for now.
Remember, though, In this case, as well as other comparisons for equality (e.g. for testing numbers) you must be careful to code two = rather than one. Using one is an assignment statement which will compile and execute, but will not mean what you think it means. In short, again:
to compare for two things
being equal, you must use two = signs:
if (x == 10)
if (s == "jim")
The do...while Statement
This version of a loop instruction ensures the body of the loop always executes at least once.
After each repetition, the exit condition is tested. So this is classified as a bottom-driven loop.
Format:
do // note: NO ; here
{
.. loop body
}
while (condition); // note: ; required here!!
You could re-write the average program using a do..while without having to initialize the variable choice.
#includes...
int main() { string choice; ... do { cout << "\nEnter a speed: "; cin >> aSpeed; speedCount++; speedSum += aSpeed; cout << "\nAnother? (y/n) "; cin >> choice; } while (choice == "y"); ... etc.
Loop Exit Conditions
Be very careful. You must ensure that
The following will loop forever:
i = 1;
while (i < 10)
{
n = i * 4 - j / 16;
cout << n;
}
Why? i was never changed, i.e. never became >= 10
Likewise:
i = 1;
while (i < 10)
n = i * 4 - j / 16;
cout << n;
i++;
... more ...
Why? (this won't ever display anything.)
You need to be careful to code loop exit conditions correctly for all three C++ loop constructs.
Code Formatting
Pay attention to consistent and clear indenting of loop bodies and decision blocks.
Also, include blank lines between major sections of your code (e.g. after variable declarations and around loops, etc.) Blank lines are free!
Type your code using good formatting the first time. Writing clear, clean code the first time will help you (and us) understand your program more quickly and easily - so that you and we can find and fix errors more quickly.
Note: some people like to put the opening { on same line as the control structure statement:
if (cond) {
stmnt;
stmnt;
}
else {
stmnt;
stmnt;
}
Loops, too:
for (...; ...; ...) {
stmnt;
stmnt;
}
Your text does this:
if (cond)
{
stmnt;
stmnt;
}
For this course, you should not use these styles. Use the block indent style used in these notes.
Symbolic Constants - C Version
Symbolic Constants allow us to associate a value with a symbolic and meaningful name. You use the name wherever you want the value.
In this course we will restrict use of symbolic constants to numeric values.
By convention, symbolic constants are always CAPITALIZED as a signal to the (human) reader of the program that the value is a constant.
A. Use these whenever you have a fixed value used in several places in a program.
This value will not change while the program is running, but the value may change at some
later time (example: postal rates - cents per ounce).
You would then change the value and recompile the program.
Using a symbolic constant allows a change to this value to be made in just one place
rather than finding and changing it in many places in the program. Finding and changing in
multiple places is error-prone. Then just re-compile the program.
B. Also, use symbolic constants for "magic" numbers whose values do not
explain their meaning:
Which is clearer?
Total = amt + amt * 0.0625;
Total = amt + amt * TAX_RATE; // TAX_RATE is a symbolic constant
You create C-style symbolic constants with #define statements at beginning of program (before main). The symbolic names are always capitalized by C and C++ programmers. In this course you should also capitalize them.
Note there are no commas or semi-colons in a #define:
#include ....
#define TAX_RATE 0.0625 //CAPS by convention
#define INDENT_PRCNT 0.0625 //diff meaning; same value
int main()
{
...
//0.0625 replaces TAX_RATE total = amt + amt*TAX_RATE; ... //0.0625 replaces INDENT_PRCNT x = 2 * INDENT_PRCNT; ... // then next is illegal: equivalent to // 0.0625 = 0.07 // generates an error TAX_RATE = 0.07; }
So:
A. Changing TAX_RATE in the #define changes it everywhere it occurs in the program
(potentially many times), but does not change INDENT_PRCNT anywhere.
B. Meaning is clearer.
Symbolic Constants - C++ Version
C++ has a alternate mechanism to create a symbolic constant. It is typically declared as a data item, but in the same place as a #define. The declaration is prefaced with the keyword const. The compiler will flag as an error any attempt by program instructions to alter the value of this data item.
#includes, etc.
const double TAX_RATE = 6.025;
const double PI = 3.14159;
int main()
{
...
total = amt + amt*TAX_RATE; // ok - as above
...
TAX_RATE = .07; // illegal - produces compiler error message
...
}
Formatted Numeric Output Using cout
All the examples so far that have displayed numeric output have used the simplest possible method:
cout << num;
This will not always display the number in the way you would like. Often you want to control the field width (the number of display columns that the number takes up) or the number of significant figures, or the number of decimal places. cout has a number of moderately awkward ways to control these things.
First, in order to use them you must #include <iomanip>
Then, in the particular cout operation, you include one or more of several special modifiers to the command. Several examples are given below. You should study the material in your text (Bronson, Sec 2.3) for more details and examples. For this course, you do not need to learn octal and hex formatting commands.
The output of the following program is shown below, assuming the user enters 3.14159, with notes about each output line.
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
double d;
double quo = 100.0/3.0;
cout << "100.0/3.0 as double is: " << quo; // line A
cout << "\nEnter a floating point number: ";
cin >> d;
cout << "Num in native format: " << d; // line B
cout << "\nW= 5 p = 3: |" << setw(5)
<< setprecision(3)
<< d << "|"; // line C
cout << "\nW= 5 fixed p = 3: |" << setw(5)
<< fixed
<< setprecision(3)
<< d << "|"; // line D
return 0;
}
Line A: "100.0/3.0 as a double is: 33.3333"
Note that with no special formatting commands, 6 figures are displayed, although
more could be: 33.3333333... If the division had been 100.0/2.0 the result
would have been 50 (not 50.0000).
Line B: "Num in native format: 3.14159" Again, 6 figures display. If you had entered more digits, still only 6 would display. If you had entered fewer, fewer would display.
Line C: "W= 5 p = 3: | 3.14|" Here we first use the io format manipulators. Before we send the value (num) to display, we tell cout how to display it.
setw() tells cout how many display positions to use for the value. If the value needs more space, it will just take it. If the number requires less space, it will be padded with blanks. You can control left- or right-justification with left or right. See the below. In this example, notice that there is a space before the 3.
Note that you must use setw() for each numeric value you output, even if the width is the same:
cout << setw(5) << num1 << setw(5) << num2;
setprecision() tells cout how many significant figures to display. Here we see 3.14 which is just 3 significant figures. If we had specified setprecision(4) we would see 3.142. (The value is rounded.)
Line D: "W= 5 fixed p = 3: |3.142|" Here, the fixed tells cout that the precision applies to the number of decimal places, so we see 3 decimal places. Note that all 5 width spaces are used up, so there is no space before the 3.
Unlike setw(), once setprecision() and fixed have been set, they retain their values (or settings) until you change them.
Field Justification and blank padding: left and right
If the field width (setw()) is larger than the number of characters needed, the data will display either all the way to the left or all the way to the right within the field, padded or filled with leading or trailing blanks. Numeric values will display to the right (right-justified) and strings to the left (left-justified). You can alter this behavior using the left and right manipulators:
cout << "xx" << right << setw(20) << "Jim Henry" << "xx";
cout << "\nyy" << setw(10) << left << quo << "yy";
will display:
xx Jim Henryxx
yy3.333 yy