No significant program is written in just a bare programming language. C++ provides its standard library as part of every complete C++ implementation. C++ input/output facilities are included in the library. This facility is commonly known as stream input/output, which supplies a set of functions and objects intended to solve the following problems:
Adding I/O to your programs can be tedious and somewhat challenging task. In our course we attempt "by example" approach to discover possible I/O solutions. When possible, we may encapsulate individual tasks into a stand-alone functions with relatively simple and well-documented set of parameters. All students are encouraged to use this improvised I/O library in their homeworks. Such approach is dictated by the fact that complete understanding of the stream manipulation syntax requires understanding of C++ user-defined types, operator overloading, and templates, all to be covered in the future. The concept of streams is used for transmitting objects between machines and networks, for encrypting messages, for data compression, and for persistent storage of objects, to name a few. However, our discussion of streams is restricted to a simple character-oriented input and output. |
The predefined object std::cout is an std::ostream instance that is attached to the standard output device, such as the console screen. |
Standard output stream is simply a mechanism for converting values of various types into sequences of characters: #include <iostream> int main() { std::cout << "Hello, world!"; return 0; } As you can imagine, characters are transmitted to a particular device using low-level output implementation. The <iostream> library header defines output for every built-in C++ type. For example, #include <iostream> int main() { int i = 1; double d = 0.5; std::cout << i << '\t' << d; return 0; } Output can be chained, because the result of each std::cout << i << '\t' << d; is equivalent to ( ( std::cout << i ) << '\t' ) << d; |
Output of individual characters is intended for output operations of any number of individual characters using member function cout.put( ): std::cout.put( 'A' ); Unformatted I/O using As a general rule, these low-level I/O functions recommended for programs where implementation efficiency is at a premium, and should be primarily reserved for the implementation of higher-level functions. |
The predefined object std::cin is an std::istream instance that is attached to the standard input device, such as the keyboard. |
The >> operator is intended for formatted input; that is, reading objects of an expected type and format. For example, because operator >> skips whitespace, you can read a sequence of whitespace-separated integers like this: #include <iostream> int main() { int one; int two; std::cout << "Please enter two integers: "; // Display message std::cin >> one >> two; // Get two integers from user return 0; } Whitespace is defined as the standard blank, tab, newline, formfeed, and carriage return. A non-integer on the input will cause the input operation to fail and thus terminate the input process. |
Where this formatted input is not desirable and we want to read a stream of individual characters and be able to examine each, we can employ the cin.get( ) function. The cin.get( ) and cin.getline( ) functions treat whitespace characters exactly like other characters. They are intended for input operations where one does not make assumptions about the meanings of the characters read. Unformatted input of individual characters allows input of multiple lines of text at once. Here is an example of cin.eof( ), cin.get( ), and cout.put( ), used together: #include <iostream> int main() { int onechar; // Note: char cannot represent EOF while ( ( onechar = std::cin.get() ) != EOF ) { std::cout.put( onechar ); } return 0; } As you can see, if there is no input character to return, cin.get( ) returns a suitable "end-of-file" marker, EOF. |
Unformatted I/O using A call The |
A couple of examples using std::cin.getline( ): #include <iostream> int main() { const int INPUT_SIZE = 256; char array_buffer[ INPUT_SIZE ]; std::cout << "Please enter a line of text and hit enter: "; std::cin.getline( array_buffer, INPUT_SIZE ); std::cout << "You entered: " << array_buffer << std::endl; std::cout << "Please enter text, terminated by semicolon: "; std::cin.getline( array_buffer, INPUT_SIZE, ';' ); std::cout << "You entered: " << array_buffer << std::endl; return 0; } |
The standard library provides a string type to complement the string literals like "Hello, World!" The string type offers a variety of useful string operations, such as concatenation of fragments of text and many other features. At this point we will focus on the topic of string streams. A string stream acts as a buffer to accumulate and consume sequences of characters in stream-like manner. All stream I/O operations discussed earlier can be applied to string streams. Interaction between std::cin, std::stringstream, and std::string is demonstrated by the sample program strstream.cpp (download source code here ) When efficiency isn't paramount, is it always better to read into a string. In fact, this should be a standard approach to get an arbitrary line of text from the user directly into std::string: #include <iostream> int main() { std::cout << "Please enter a line of text and hit enter: "; std::string input; std::getline( std::cin, input ); std::cout << "You entered: " << input << std::endl; return 0; } This little program extracts a string from the standard input. Again, this is the most common way of getting unformatted line of characters from the user. Another, slightly more complicated example, adds code to guarantee that program is capable of reading input of a particular length: #include <iostream> const int CUSTOM_BUFFER_SIZE = 256; // read up to 256 characters int main() { std::cout << "Please enter a line of text and hit enter: "; std::string input; if ( input.capacity() < CUSTOM_BUFFER_SIZE ) { // reserve increases the size of data accepted by getline(): input.reserve( CUSTOM_BUFFER_SIZE ); } std::getline( std::cin, input ); std::cout << "You entered: " << input << std::endl; return 0; } |
Sample program, strstr_demo.cpp (download), provides introduction to I/O manipulators. Another program, manipulators.cpp (download), demonstrates I/O formatting using stream manipulators. As promised earlier, actual low-level string stream implementation is hidden by a set of functions in string_format.h (download) header file. Here is a smaller version of the manipulators.cpp: #include <iostream> #include <iomanip> // needed for std::setw() #include "string_format.h" int main() { std::string input = "1234.56789"; double value; if ( string2type( input, value, std::fixed ) ) { std::cout << std::setw( 12 ) << input << '\t'; std::cout << std::setw( 12 ) << std::fixed << value << '\t'; std::cout << std::setw( 12 ) << type2string( value, std::fixed ); std::cout << "\t std::fixed"; } else { std::cout << "BAD input: " << input; } return 0; } Closer examination of this demo program yields the following observations:
Full version of manipulators.cpp generates this output: 1234.56789 1234.567890 1234.567890 std::fixed 1234.56789 1234.567890 1234.568 std::fixed + precision == 3 56e2 5600.000000 5600 56e+2 5600.000000 5600.00 std::showpoint 234.5678 2.345678e+002 2.345678e+002 std::scientific 255 255 255 FF ff ff std::hex 777 777 777 std::oct true true true std::boolalpha 1 true 1 Some additional manipulator flags that could be used with other data types are:
|
As a general rule, standard library string streams should be preferred for all in-memory formatting tasks. Sample functions string2type( ) and type2string( ) can solve a good range of formatting problems when transforming data from C++ types to plain text and vice versa. Implementation of string2type( ) and type2string( ) functions simplifies string conversions by hiding low-level string stream manipulations, while providing relatively simple interface to potentially messy (if written from scratch) conversion procedures. String-to-type conversion is able to signal a bad format, thus helping us to implement a simple validation check for protection against unwanted inputs. On the other hand, type-to-string conversion has no validation, because its implementation assumes that conversion from internal data to external text is a safer operation. |
|
|