Reading
None.
Overview
This lecture is dedicated to odds and ends that we didn't
cover because they weren't critical, and yet that are often
nice to know. Of what's here, I'd say the short-circuit
evaluation of boolean operators at the bottom is the most
important. In my view (Dr. Brown here) the switch or i/o
formatting is the least
important.
switch statements
The switch statement is a bit of a holdover from the
C language on which C++ is based, but it is something you'll
probably see if you look at a lot of programs. You use a
switch statement when you want to test a single
variable or expression for several different cases. The hitch is
that the variable pretty much needs to be an int or a
char, which limits when switch can be
used. Switch breaks things up into cases. You write
switch(expr)
{
... where expr is an expression of type int
or char, and then list cases consisiting of possible
values of expr. These cases must be constants, and each
case is followed by a :, then a sequence of statements to
be executed, and finally a break;. In other words,
each case looks like this:
case constk:
stmt1
stmt2
...
stmtr
break;
You can list as many of these cases as you want. You can also put
default:
stmt1
stmt2
...
stmtr
break;
in as one "case". This is a catch-all that catches every
situation in which expr didn't match one of the other
cases.
Here's an
example program using switch.
It reads a date in "mm/dd/yyyy" format and returns the date in
"dd monthname, yyyy" format.
cin.get() and eof
When we read in a value to variable x with the
statement
cin >> x;
cin skips over leading whitespace in the input
stream, meaning it skips over newline characters ('\n'),
tabs ('\t'), and spaces (' '). This is
a bit of a problem if you want to do something like count the
number of lines in a file. You can read input a char
at a time without skipping over whitespace using
cin.get(), and you can read from
ifstream object fin a char
at a time without skipping over whitespace using
fin.get().
So, suppose you wanted to read in a line of text from the user
and print out how many characters were in the line, you'd write
this:
#include <iostream>
using namespace std;
int main()
{
int count = 0;
for(char c = cin.get(); c != '\n'; c = cin.get())
count++;
cout << "There were " << count << " characters!" << endl;
return 0;
}
Caveats (optional reading): The full behavior of fin.eof() is somewhat more complex: it will return true when a read (using the stream operator >> or using fin.get() ) has moved the file pointer forward so that the next character in the stream is the end-of-file marker. So, if you have just read the very last character in the file, fin.eof() will return true, even though you haven’t yet done a read that failed. However, in many cases (especially if using the stream >> operator) your program will only really observe this end-of-file after a failed read, because most files have a newline character at the end of the file. If you are using the >> stream operator, you will only move past this newline character when you try to read in the next value (like an integer or string) and fail.
Suppose fin is the name of an ifstream
object that you're reading from (remember to include
fstream if you want to read and write with files).
You can test whether or not you've come to the end of the file
with the expression fin.eof() which evaluates to
true if you have tried to read beyond the end of the file, and
false otherwise.
So if you wanted to write a program to count the number of
characters in the file
Input.txt, you'd do something like this:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
// Open file stream
ifstream FIS("Input");
// Read char c until the end of file
int count = 0;
for(char c = FIS.get(); !FIS.eof(); c = FIS.get())
count++;
cout << "There were " << count << " characters!" << endl;
return 0;
}
Formatting numbers with cout (or any
ofstream object)
Oftentimes the way cout decides to format things
might not agree with the way we'd like to see them formatted.
For example, if x is a double with value
4.0, cout will write "4". Or, for example, the
number of decimal places cout shows might not be
suffient.
Pages 42-43 and section 6.2 of your book contains
lots of information
about how to change the way output is formatted - it even includes
lots of examples.
Formatting can be affected by "i/o manipulators" (you have to
include the library iomanip for some of these). If
you want to force
cout to always show a decimal point, you "send" it the
manipulator showpoint (which does not come from
iomanip, rather is included in the
iostream library).
double x = 3.0;
cout << x << endl;
cout << showpoint;
cout << x << endl; |
YIELDS |
3
3.000000 |
If you want to set the precision to be displayed in printint a
number of type double use
the setprecision(k)
manipulator, where k is the number of digits
you want shown (which does require the
iomanip library). For example:
double x = 3.1234567890123456789;
cout << x << endl;
cout << setprecision(15);
cout << x << endl; |
YIELDS |
3.123456
3.12345678901235 |
Remember! Include the library iomanip when
using setprecision!
Exiting main() early
The "return 0;" at the end of your program exits your
program. In fact, inside main you can stick a
"return 0;" wherever you want and as often as you
want, and it'll exit the program. For example, maybe you want to
write a program that reads an integer k from
the user and writes out 1/k. If the user enters
zero, of course, there's a problem. Now we'll just castigate the
user and exit the program if he does that!
You may prefer to use "exit(1)" instead of "return 1", since when
we eventually write code outside of the main() block "exit(1)"
sill still exit the program, but "return 1" won't. The "exit"
function is available from the "iostream" library, for example.
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
// Get number from user
cout << "Enter a non-zero integer: ";
int k;
cin >> k;
// Deal with bad input
if (k == 0)
{
cout << "You follow directions like a Firstie!"
<< endl;
return 1;
}
// Write out decimal approximation of 1/k
cout << setprecision(20);
cout << "1/" << k << " is "
<< 1/double(k) << endl;
return 0;
} |
do-while Loops
We've spent a lot of time with while-loops and for-loops. Both of
these loops test whether to continue, and then go through the loop
body, i.e. the test is done at the beginning of the loop. A
"do-while" loop allows you to put the test at the end of the
loop. This is convenient for certain tasks. For example, we
looked at a program that reads expressions like
1 + 5 + 3 + 48 + 32 =
and prints out the resulting sum. This can be done nicely with a
do-while
#include <iostream>
using namespace std;
int main()
{
int next, sum = 0;
char op;
do {
cin >> next;
sum = sum + next;
cin >> op;
}while(op != '=');
return 0;
} |
#include <iostream>
using namespace std;
int main()
{
int next, sum = 0;
char op;
// Must initialize with something other
// than '=' just to make sure we enter
// the loop the first time.
op = 'X';
while(op != '=') {
cin >> next;
sum = sum + next;
cin >> op;
}
return 0;
} |
In case you don't find that compelling, here's another example.
Suppose we want to keep reading in ints from a list
until we read a negative number.
#include <iostream>
using namespace std;
int main()
{
int n;
do {
cin >> n;
}while(n >= 0);
return 0;
} |
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n; // read n the first time
while(n >= 0)
{
cin >> n;
}
return 0;
}
|
Short-circuit evaluation of boolean expressions
This is a fairly subtle point, and one whose use may not be
apparent quite yet. When the boolean expression
E1 && E2
gets evaluated, E1 is evaluated first. If it's false, the value
of the expression is false, without ever evaluating E2.
Similarly, when
E1 || E2
gets evaluated, E1 is evaluated first. If it's true, the value
of the expression is true, without ever evaluating E2.
This is
called short-circuit evaluation. This can have
interesting consequences, and can be quite usefull. For example:
suppose I want to read in integers from the user until I read one
that evenly divides 472, which I will then print out. My first
attempt might be
#include <iostream>
using namespace std;
int main()
{
int n;
do {
cin >> n;
}while(472 % n != 0);
cout << n << endl;
return 0;
}
|
There's a problem with this program, though. If the user enters
0, the program will crash, because 472 % 0 asks the computer to
divide by zero. Clearly if the user enters zero we need to keep
looping to look for a number that divides 472. So we'd like to
modify our program so that it keeps looping if the
n entered by the user is zero ... as opposed to
crashing, which is what it does now. The following modification
works:
#include <iostream>
using namespace std;
int main()
{
int n;
do {
cin >> n;
}while(n == 0 || 472 % n != 0);
cout << n << endl;
return 0;
}
|
Now, the only reason this works is the short-circuiting
evaluation, which makes sure that when n == 0 is
true, we never even try to evaluate 472 % n != 0.
This also means that ++ and -- in expressions involving booleans
can be extremely tricky, especially when a few implicit
conversions come into play as well. For example, here's a game
of C++ Jeapardy: This program outputs the answer, what's the
question?
#include <iostream>
using namespace std;
int main()
{
int k, n = 0;
cout << "Enter integer k: ";
cin >> k;
for(int i = 1; i <= k && (k % i || ++n); i++);
cout << "The answer is " << n << endl;
return 0;
} |
P.S. Don't ever write programs like this!