166_IO

advertisement
“cin” Overview
screen
keyboard
Everything
typed is
“echoed”
input
buffer
When the entry of an input
line is complete (ENTER is
hit), the keystrokes are
placed in the input buffer.
It is like a pipe – keystrokes
are placed in one end and
removed from the other.
Operations on cin (eg “cin
>> i”) cause keystrokes to
be extracted from the input
buffer and processed.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
1
Reading an “int” Value
“cin >> i” is actually a form of function call. The
pseudo-code below is a (very) simplified view of
how the called function operates.
while next keystroke in buffer is “whitespace” {
extract keystroke from buffer and discard it
}
if next keystroke is not a numeric digit {
set error flag and return
}
extract keystroke; value = digit value;
while next keystroke is a numeric digit {
extract keystroke;
value = (value * 10) + digit value;
}
store value into variable supplied;
If the input buffer becomes empty at any point in
these proceedings, the function simply waits for
more input to arrive.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
2
Handling Input Errors
If the input is invalid (e.g. the input is “JUNK”),
the input operation will fail. An “error flag”
within cin is raised, and the variable being read is
not given a new value.
To test whether the error flag is raised, use
function “cin.fail”. It returns a bool result (at
least conceptually).
if (cin.fail()) {
To reset the error flag and permit further read
operations (while the flag is raised, all operations
automatically fail), use function “cin.clear”.
cin.clear(); // clear the error flag
To get the rest of the current input line out of the
buffer, use function “cin.ignore”. It requires two
arguments – the maximum number of keystrokes
to be discarded and the keystroke it is to stop at.
cin.ignore (INT_MAX, ‘\n’); // flush input
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
3
A Bulletproof Input Function
void read_position (double &lat, double &lng) {
cin >> lat >> lng;
while ( cin.fail() ||
(lat > 90.0) || (lat < -90) ||
(lng > 180) || (lng < -180) ) {
// either the input was total garbage (not
// numeric) or bad numbers were entered.
in
// the first case we must clear the cin error
// flag and discard all unprocessed characters
// (the junk), and in the second case there's
// no harm in doing this.
cin.clear(); // reset cin error flag
cin.ignore (INT_MAX, '\n'); // discard garbage
cout << "Invalid values entered - try again: ";
cin >> lat >> lng;
}
}
See sample program dstnce2.cpp.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
4
A New Type - Char
Variables of type “char” conceptually contain a
single character. In reality they contain the code
used to represent this character.
In general constants of type “char” consist of a
single character between a pair of single quotes.
examples: ‘a’, ‘b’, ‘9’, ‘4’, ‘+’, etc.
In somes cases a two character sequence starting
with a backslash is used.
‘\n’ – the “newline” character
‘\t’ – the tab character
‘\\’ – a single backslash
‘\r’ – carriage return
etc.
The newline character and the backslash are the
only sequences we’re likely to use.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
5
Character Codes
Generally ASCII (American Standard Code for
Information Interchange) codes are used in
representing characters within computers (two
other posibilites are EBCDIC and Unicode).
Character ASCII
Character ASCII
‘a’
97
‘A’
65
‘b’
98
‘B’
66
...
...
...
...
‘z’
122
‘Z’
90
‘0’
48
‘\n’
10
‘1’
49
‘+’
43
...
...
‘$’
36
‘9’
57
‘(‘
40
‘ ‘ (blank) 32
‘)’
41
Note that the codes for the lower case alphabet
are contiguous, are are those for the upper case
alphabet and the numerical digits (‘0’ to ‘9’).
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
6
Using Characters
Assume:
char a, b, c;
Char variables can be read into:
cin >> a;
“a” will get the next non whitespace character in
the input buffer (or, if whitespace skipping is
disabled, the next character, period).
Characters may be written:
cout << a << ‘ ‘ << b;
The character stored in “a” will be written to the
screen, followed by a blank and the character in
“b”.
Characters may be used in expressions:
a = ‘x’; // a now contains ‘x’
c = a + 1; // c now contains ‘y’
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
7
Char/Int Conversions
If a char value is used in a context which requires
an arithmetic value, it gets converted to int.
int value is the character code for char value
If an int value is used in a context which requires
a char value, it gets converted to char.
char value is char having int value as its code
Examples:
char a, b, c;
a = ‘x’; // char to char assignment
b = 65; // b = (char) 65, b gets ‘A’
c = a + 1; // c = (char) (((int) a) + 1)
if (b < c) { // if ((int) b < (int) c) {
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
8
Char Manipulation Example
This function accepts a character and returns the
same character, converted to uppercase if the
character supplied is one of ‘a’ through ‘z’.
char make_upper (char ch) {
if ((‘a’ <= ch) && (ch <= ‘z’)) {
// we have a lower case character –
// return its uppercase equivalent
// ‘A’-’a’ = ‘B’ – ‘b’ = … = -32
return (char) (ch + (‘A’ – ‘a’));
}
// just return the character supplied
return ch;
}
This function is available (as “toupper”) in the
C++ libraries. To make it available “ctype.h”
must be included.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
9
Char Example
The following code snippet illustrates one use of
char variables. There are many others (think of
word processors – which maniplate characters on
a grand scale).
void main (void) {
char reply;
do {
// play game (or whatever)
...
cout << “Do it again (Y/N): “;
cin >> reply;
while (make_upcase(reply) == ‘Y’);
} // end main
Not very sophisticated – anything other than ‘Y’
is taken as meaning no. For a more elaborate
example, see sample program dstnce2.cpp.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
10
I/O Flags (1)
Both cin and cout contain “formatting flags”
which control exactly how they operate. The
following list was extracted from “iostream.h”.
// formatting flags
enum {
skipws = 0x0001, // skip whitespace on input
left = 0x0002, // left-adjust output
right = 0x0004, // right-adjust output
internal = 0x0008, // padding after sign or base indicator
dec = 0x0010, // decimal conversion
oct = 0x0020, // octal conversion
hex = 0x0040, // hexadecimal conversion
showbase = 0x0080, // use base indicator on output
showpoint = 0x0100, // force decimal point (floating output)
uppercase = 0x0200, // upper-case hex output
showpos = 0x0400, // add '+' to positive integers
scientific = 0x0800, // use 1.2345E2 floating notation
fixed = 0x1000, // use 123.45 floating notation
unitbuf = 0x2000, // flush all streams after insertion
stdio = 0x4000, // flush stdout, stderr after insertion
boolalpha = 0x8000 // insert/extract bools as text or numeric
};
As this enumeration is defined inside a class
called “ios”, flag names must be preceded with
“ios::” when used (e.g. ios::fixed).
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
11
I/O Flags (2)
Formatting flags can be turned on and off by
using the “setiosflags” and “resetiosflags”
manipulators:
cout << setiosflags (ios::fixed);
cout << resetiosflags (ios::fixed);
There are also a pair of functions that can be used
to do the same thing:
cout.setf(ios::fixed); // sets specified flag(s)
cout.unsetf(ios::fixed); // resets specified flag(s)
In both of the above cases, combinations of flags
may be selected by using the bitwise OR operator
(e.g. ios::fixed | ios::showpoint).
The total state of the flags may be manipulated as
a long value. The function involved may be used
with either no arguments (get) or one (set).
long flag_state;
flag_state = cout.flags(); // get total state of flags
...
cout.flags (flag_state); // restore total state of flags
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
12
File IO - Introduction
Programs which require significant amounts of
data don’t usually read it from the keyboard.
Instead data is normally read from a previously
prepared data file. Similarly programs which
produce significant amounts of data normally
write it to a file.
The advantages should be obvious. Imagine, for
example, they we want to do some anlaysis on the
academic records of all Carleton students. We
could have our program read all this data from the
keyboard, but what if we make a mistake part way
through? Or what if our program turns out to
have a bug, and we must do the whole thing over
again? It’s far better to get the data in some kind
of file, and then have our program read this file.
On the output side, writing the results of the
analysis to a file creates a permanent record that
can be examined as often as desired, sent to a
printer, transmitted as an email attachment, and so
on…..
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
13
Cin and Cout as Objects
To date, all input has involved dealing with “cin”,
and all output has been performed through “cout”.
keyboard
cin
screen
cout
istream
“object”
ostream
“object”
Input is performed
by operating upon
the cin “object”.
Output is performed
by operating upon
the cout “object”.
Cin and cout are both automatically defined (if
one includes iostream.h) and automatically
connected to the keyboard and the screen. They
are also “global” and hence accessible from
within all functions.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
14
Reading from a File (1)
To read from a file, we must first declare a new
istream object and attach it to the file of interest.
// the declaration (goes with other declarations).
// type is “ifstream”, name (in this case) is “fin”
ifstream fin;
// attach this object to the file “input.dat”
fin.open (“input.dat”);
input.dat
fin
istream
“object”
Input is performed
by operating upon
the fin “object”.
There is nothing magical about
the name “fin” - any name can
be used. The declaration of an
ifstream object is entirely
analogous to declaration of,
say, an int variable.
An “ifstream” is a specialized
form of “istream” adapted for
reading files. An “ifstream” is
an “istream”, just as a “fourth
year student” is a “student”,
and may be used as such.
“fstream.h” must be included.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
15
Reading from a File (2)
Once we’ve declared and attached an object in
this manner, using it is just like using cin. The
only difference is that, whereas the cin input
“stream” is made up of lines of data entered by
the user, the fin “stream” is made up of lines of
data read from the attached file.
fin >> x; // read a value from the file
if (fin.fail()) {
. . . // something has gone wrong
Function “names” containing a dot can now be
understood as the combination of an object name
and a function name.
cin.ignore (. . .);
object to which
function is to be
applied
function name
arguments
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
16
Summary of Istream Functions
The following functions can be applied to istream
objects (cin, and any we define ourselves):
bool fail (void);
- returns the state of the failed flag
void clear (void);
- resets the failed flag
void ignore (int count, char stop_char);
- discards up to “count” input characters, stopping when
“stop_char” (usually ‘\n’) is seen and discarded
void setflag (long flags);
- sets the formatting flags selected by “flags”
void unsetflags (long flags);
- resets the formatting flags selected by “flags”
long flags (void);
- returns the total state of the formatting flags
void flags (long state);
- loads the formatting flags with the total state specified
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
17
The Eof Function
When reading from a file, we can stop upon
reading a special “sentinal value” (just as when
reading from the keyboard). This approach is
illustrated by sample program large1.cpp.
There is a better approach, however. This is to
keep reading until we get to the end of the file.
We can tell when we’re at the end by applying
function “eof” to the istream object.
bool eof (void)
- returns true if the stream is in the failed state (failure
flag up) because we’ve tried to read past the end of
the input file
Sample Use:
fin >> value;
if (fin.fail()) { // read failed for some reason
if (fin.eof()) { // read failed due to eof hit
...
} else { // read failed for some other reason
See sample program large2.cpp.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
18
Reading File Names
“Hard-wiring” the name of the input file to be
read into a program is a bit limiting, and it is far
better to ask the use for the name of the file to be
read. This involves some things we’ve yet to get
to (arrays and strings), but the process is
sufficiently simple it can be done without really
understanding all aspects of it (see text p230).
// in declarations
ifstream fin;
char file_name [60]; // an array of characters
// in code
cout << “Enter file name (max 59 chars): “;
cin >> file_name;
fin.open (file_name);
// the filename can be output if desired
cout << “The input file is “ << file_name << endl;
See sample program large3.cpp.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
19
Writing to a File (1)
To write to a file, we must first declare a new
ostream object and attach it to the file of interest.
// the declaration (goes with other declarations).
// type is “ofstream”, name (in this case) is “fout”
ofstream fout;
// attach this object to the file “output.dat”
fout.open (“output.dat”);
output.dat
fout
ostream
“object”
Output is performed
by operating upon the
fout “object”.
There is nothing magical about
the name “fout” - any name can
be used. The declaration of an
ofstream object is entirely
analogous to declaration of, say,
an int variable.
An “ofstream” is a specialized
form of “ostream” adapted for
writing files. An “ofstream” is
an “ostream”, just as a “fourth
year student” is a “student”, and
may be used as such.
“fstream.h” must be included.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
20
Writing to a File (2)
Once we’ve declared and attached an object in
this manner, using it is just like using cout. The
only difference is that, whereas writing to cout
sends characters to the screen (and “newlines”
move the cursor to a new line), writing sends
characters to the file being created (and
“newlines” end one file line and start a new one).
fout << “This will be line 1 of our file.”
<< endl;
fout << i << j << endl; // second line of file
// lines can be created in sections
fout << “Start of line “;
fout << i << j; // some values
fout << “End of line.” << endl;
All manipulators (e.g. setw, etc.) and functions
(e.g. setf, etc.) that can be used with cout can also
be used with user-defined ostream objects and
work in exactly the same way.
See sample program large4.cpp.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
21
Scope Rules
The concept of scope applies to istream and
ostream objects. An object declared within a
function is belongs to that function, and can only
be accessed by it.
Objects declared outside functions are global and
can be used from within all functions. If we were
to declare fin and fout at the start of our program,
they could be used everywhere (like cin and
cout). Though this amounts to having global
variables (forbidden), this particular case is OK.
ifstream fin; // globally accessible
ofstream fout; // ditto
int func1 (…) {
}
void main (void) {
…
fin.open (…); // somebody has to do this
fout.open (…); // and this
…
}
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
22
Objects as Arguments
A more sophisticated way of making objects
available to the functions which need them is to
pass them as arguments. An istream or ostream
declared in one function can be made available to
another function by passing it by reference.
// writes“Hello there” to some ostream
void say_hello (ostream &os) {
os << “Hello there.” << endl;
}
void main (void) {
ofstream fout;
…
// write “hello there” to the screen
say_hello (cout);
// write “hello there” to a file
say_hello (fout);
…
}
Note that, because an ofstream is an ostream, it is
permissable to supply an ofstream object to a
function which expects an ostream.
91.166 Copyright © 2000, Department of Systems and Computer Engineering, Carleton University
23
Download