3.8. More I/O Functions And Manipulators

Review

Graphical user interfaces (GUIs) have been an integral part of the computing experience for four decades. GUIs support program output in various ways beyond text, including graphs, images, animations, etc. But, depending on the programming language, utilizing these forms requires a deep understanding of the object-oriented paradigm and the APIs of the programming language and the host operating system. Despite GUI's dominance in modern programming, it's still necessary to understand how to format program output.

Formatting Prerequisites

C++ uses stream objects to read and write data. This section focuses on output stream objects - instances of the ostream class. Output stream objects save data to a file, formatting it as it moves from the program to the file. cout is a specialized output stream object that "saves" or displays its output to the console. Although cout is permanently attached to the console, it is an otherwise typical output stream, suggesting that programmers may use the features described here with all output streams.

How stream objects format data depends on their current configuration or settings. They maintain most of their settings with a set of 1-bit flags. Each flag is a binary switch - on or off - controlling some aspect of the output format. Stream objects group the flags into five functional sets of varying bit lengths. Streams always set default values for each flag, but programmers can dynamically (i.e., while a program is running) change the flags with the functions, manipulators, and symbolic constants described here.

The section begins by introducing or reviewing some syntax and fundamental concepts. The discussions present the concepts using the I/O features without giving them much detail - the focus is on the concepts and syntax. Following the concepts and syntax presentation, the section presents detailed descriptions of the features and reinforces them with programming examples. Please note that most examples adjust the vertical spacing in the program's output to align with the program's corresponding output statements.

endl: Simple Line Formatting

Program Output
#include <iostream>
using namespace std;

int main()
{
	cout << "See the quick red ";
	cout << "fox jump over the ";
	cout << "lazy brown dog." << endl;

	cout << endl;

	cout << "See the quick red" << endl;
	cout << "fox jump over the" << endl;
	cout << "lazy brown dog." << endl;
    
	cout << endl << endl << "See the quick red" << endl;
	cout << "fox jump" << endl << "over the" << endl;
	cout << "lazy brown dog." << endl;
    
	return 0;
}
See the quick red fox jump over the lazy brown dog.

See the quick red
fox jump over the
lazy brown dog.


See the quick red
fox jump
over the
lazy brown dog.
Inserting newlines with endl. Although previous examples have demonstrated endl, it's worthwhile adding that it may appear anywhere in an output statement any number of times - not just once at the end.

Flags, Symbolic Constants, and Bitwise Operations

Programmers change a stream's configuration by switching the formatting flags on and off - "flipping the switches" - with bitwise operations. They use the bitwise-OR operation to switch bits on and the bitwise-AND to switch them off. The bitwise operations require two operands. One operand is a variable - a bit-vector - where each bit is a switch governing a formatting feature. Sometimes, the bits within a group work together, creating more complex formatting options. The second argument is (typically) a constant representing the specific formatting feature the program is changing. Although programmers can use numeric values to denote a particular formatting setting, they rarely do because numbers convey little meaning in this context: how does "4" change a stream's formatting? To make their code more understandable, programmers universally use bitmasks - a symbolic constant whose value consists of mostly 0s and one 1-bit - 000...010...000 - to adjust stream objects.

Chapter 1 introduced us to non-object-oriented symbolic constants, but I/O streams are objects. The following examples use symbolic constants like ios::hex and ios::fixed. ios (sort for input/output system) is a class name, and :: is the scope resolution operator. Together, they bind symbolic constant names, like hex and fixed, to the ios class. Each flag is an integer, but C++ creates an artificial bitmask data type called fmtflags to represent them. Programmers use the stream flag functions to change a stream object's formatting flags.

Function Comments Return
fmtflags setf(f)
fmtflags setf(f, m)
Sets the flags in f; doesn't change other settings
Sets the flags in f and m; clears all other settings
Previous settings
void unsetf(f) Unsets or clears the flags in f
fmtflags flags()
fmtflags flags(f)
Gets the current formatting flags
Sets the flags in f and clears the rest
Previous settings
I/O stream flag functions. Programs can call the flag functions to check or change a stream object's formatting flags. Setting a flag means to activate a feature; unsetting or clearing a flag deactivates the corresponding feature. Once a flag is set or cleared, that setting remains in force until the program changes it or terminates. Example programs appearing later in this section demonstrate the flag functions.

Imagine a large room with several independent lighting zones. We can turn the lights in each zone on and off without affecting the lights in the other zones or other rooms. Similarly, we can change some flags in a stream object without changing the other flags, and changing the flags in one object doesn't affect other streams. This observation suggests that we can gradually build the needed flags one flag at a time or change several with one operation while retaining the current values in others.

cout.setf(ios::hex);
cout.setf(ios::fixed);
cout.seft(ios::hex | ios::fixed);
 
(a)(b)
Configuring stream objects. While programs can set the flags one at a time, it's often more convenient to set them with a single function call.
  1. The first statement sets the hex flag; the second statement sets the fixed flag but leaves the hex flag unchanged.
  2. The bitwise-OR operation forms an expression whose value is an integer, specifically a fmtflagss, with two 1-bits corresponding to the hex and fixed flags. The setf function simultaneously sets both flags.

Programmers use the hex, dec, and oct constants to adjust the base or radix in which the stream displays data. Consequently, the operation setf(ios::dec | ios::oct | ios::hex) is meaningless as it's not possible to display data in multiple bases or radixes simultaneously. However, imagine that var is a variable the program sets somewhere to one of the radix values. In that case, the operation setf(var, ios::dec | ios::oct | ios::hex) sets the radix flag to the value saved in var and clears all other flags. Similarly, ORing the three flags together makes sense for the operation unsetf(ios::dec | ios::oct | ios::hex), clearing all three flags. The presence of ios::dec in the unsetf argument notwithstanding, the stream displays output in decimal until the program changes the radix to one of the other bases.

Manipulators

Although not apparent from their appearance, manipulators are functions. Unlike "normal" functions, they only work with the inserter and extractor operators, << and >> respectively, in conjunction with the I/O stream objects.

Manipulator Description
endl Insert an end of line \n and flush the output buffer (the last character is a lower-case 'L')
dec Display output in decimal
hex Display output in hexadecimal
oct Display output in octal
setw(int w) Sets the output field width to w.
right Right-align, pad on the left (used with setw)
left Left-align, pad on the right (used with setw)
fixed Display numbers in a fixed decimal point notation (no scientific notation)
scientific Display numbers in scientific notation
Some useful manipulators. This table is not an exhaustive list of manipulators but summarizes the most useful ones. A complete list of C++ manipulators and additional information may be found here.

Member Functions

Function Description
fill(char pad) Sets the padding or fill character when the output field is wider than the printed data. The default fill character is a space or blank. Used with setw. The function has the same effect as the setfill manipulator.
char fill() Returns the current fill character.
width(int w) Sets the output field width to w.
precision(int digits) Sets the number of significant digits displayed in the output of floating-point numbers - float, double, and long double - without affecting the appearance of integers.
get() Gets one character from the input stream, returning it as an int.
ignore() Discards one character from the input stream. ignore is often called without arguments.
ignore(int n) Discards n characters from the input stream or all the characters if the stream has fewer than n characters.
ignore(int n, char d) Discards characters from the input stream until it discards n characters or the delimiter character, d.
A partial but useful list of stream (istream and ostream) member functions.

Columnar Formatting

"Columnar formatting" is not as imposing as it may sound; it means formatting the output as neatly aligned columns, forming a table. The multtab.cpp program introduces the setw manipulator and serves as an example of a problem needing columnar output.

Left Aligned Right Aligned
x
xx
xxx
x
xx
xxx
(a)(b)
Left and right alignment. When we format output in columns, we can choose how to align or justify the data in the columns. Today, many students have previous experience with HTML, including alignment, but we demonstrate it here for completeness.

Output stream objects, like cout, typically display data using exactly the number of characters needed, making single data output relatively easy. However, to format table columns, programmers must place all data in a column whose width is greater than or equal to the widest data value. The setw manipulator formats displayed or printed data, giving it a minimum output width, called the field width. Data wider than the field width displays fully, taking as much space as needed. But if the data is not as wide as the field width, the output streams pad the unused space with the current fill character, a blank or space by default. Programmers change the default fill character with the setfill manipulator or the fill member function. Once the program adjusts the fill character, the stream continues using it until the program changes it again with another call to setfill or fill.

When the field width is wider than the displayed data, the stream can place the fill characters (the padding) on either side of the data. The default location is on the left, aligning the data on the right. Programmers can change the data alignment with the left and right manipulators, as the following program demonstrates.

Program Output
#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
	cout << "String" << endl;
	cout << "|" << "Hello world" << "|" << endl;
	cout << "|" << setw(20) << "Hello world" << "|" << endl;
	cout << "|" << left << setw(20) << "Hello world" << "|" << endl;
	cout << "|" << right << setw(20) << "Hello world" << "|" << endl;

	cout << endl;

	cout << "Number" << endl;
	cout << "|" << 123.45 << "|" << endl;
	cout << "|" << setw(20) << 123.45 << "|" << endl;
	cout << "|" << left << setw(20) << 123.45 << "|" << endl;
	cout << "|" << right << setw(20) << 123.45 << "|" << endl;

	return 0;
}
 
 
 
 
 
 
String
|Hello world|
|         Hello world|
|Hello world         |
|         Hello world|



Number
|123.45|
|              123.45|
|123.45              |
|              123.45|


 
Columnar formatting: setw, left, and right. The program uses the default fill character, a space, and surrounds most output lines with the '|' character to illustrate the manipulators' impact better.
Program Output
#include <iostream>
#include <iomanip>
using namespace std;

int main()
{
	cout << "|" << setw(20) << 123.45 << "|" << endl;

	cout << endl;

	cout << "|" << setfill('0') << setw(20) << 123.45 << "|" << endl;	// (a)
	cout << "|" << left << setw(20) << 123.45 << "|" << endl;
	cout << "|" << right << setw(20) << 123.45 << "|" << endl;

	cout << endl;

	cout << "|" << setw(20) << 123.45 << "|" << endl;

	cout << endl;

	cout << setfill(' ') << "|" << setw(20) << 123.45 << "|" << endl;

	return 0;
}
 
 
 
 
 
 
|              123.45|
 
 
 
|00000000000000123.45|
|123.4500000000000000|
|00000000000000123.45|
 
 
 
|00000000000000123.45|
 
 
 
|              123.45|
 
 
 
Formating output with manipulators. The program demonstrates the impact of the setw, setfill, left, and right manipulators. The '|' characters demark the output field, making it easier to see.
  1. An alternate version replaces the setw and setfill manipulators with the width and fill member functions:
    cout.fill(' ');
    cout.width(20);
    cout << "|" << 123.45 << "|" << endl;
cout << "|" << left << setw(20) << 123.45 << "|" << endl; |123.4500000000000000|
(a)(b)
cout << "|" << left << 123.45 << setw(20) << "|" << endl; |123.45|0000000000000000000
(c)(d)
Data and manipulator order. The relative order of the data and manipulators in the output statement is significant. I find it helpful to think of the data moving in the direction indicated by the inserter arrows, <<.
  1. First, the expression << 123.45 converts the numeric data to a string, then the setw(20) left manipulators format the string for output. The previous cout statement sets the fill character to '0': setfill('0').
  2. The data is left justified in a field 20 characters wide, padded on the right with 0's.
  3. This example reverses the order of the data and the setw manipulator.
  4. Reading and understanding code is an essential programming skill developed with practice. Can you tell why the program produces this output? Begin by asking yourself, "What is setw formatting?"
With modern compilers, the relative order of the manipulators, setw and left, is no longer significant, but older compilers require the illustrated order.

Numeric Formatting

The default format for floating-point numbers, float, double, and long double, is decimal (base-10), six significant digits (aka significant figures or sig figs), and scientific notation for very large or very small (near zero) numbers. Stream objects maintain the number of significant digits to display in a distinct member variable, and the rest as two sets of 1-bit flags. The numerical-base set consists of three fields: dec, hex, and oct. The float-format set consists of two fields: fixed and scientific. The interaction of these latter two fields can produce some unexpected formats, as illustrated by the following example.

The following program is large, providing numerous examples of the formatting features. It is divided into parts, highlighting the impact of the formatting options and allowing better comments. Focus on the combination of the precision setting and the fixed and scientific flags.

Please note the following about the if-statements:

Program Output Comments
#define _USE_MATH_DEFINES
#include <iostream>
#include <cmath>
using namespace std;

int main()
{
    cout << "Default settings" << endl;
    if (cout.flags() & ios::fixed)
    	cout << "fixed flag set" << endl;
    else
    	cout << "fixed flag unset" << endl;
    if (cout.flags() & ios::scientific)
    	cout << "scientific flag set" << endl;
    else
    	cout << "scientific flag unset" << endl;
    cout << 123456789 << endl;
    cout << 123456789. << endl;
    cout << M_PI << endl;
    cout << endl;
    cout << 1.0/3.0 << endl;
    cout << 10.0/3.0 << endl;
    cout << 100.0/3.0 << endl;
    cout << 1.0/300000.0 << endl;
    cout << endl;







Default settings
fixed flag unset



scientific flag unset



123456789
1.23457e+08
3.14159

0.333333
3.33333
33.3333
3.33333e-06
 
Needed for M_PI with the Microsoft compiler.
See The cmath Header File






True if fixed is set



True if scientific is set



Integer output
Automatic scientific notation
Six significant digits: 3, 1, 4, 1, 5, 9

Six significant digits: "333333"
Ditto
Ditto
Automatic scientific notation
 
(a) The default numeric format is six significant digits, base-10, and automatic scientific notation for large and small numbers. Precision at default (6); with fixed and scientific unset, precision is the number of significant digits.
    cout.precision(2);
    if (cout.flags() & ios::fixed)
    	cout << "fixed flag set" << endl;
    else
    	cout << "fixed flag unset" << endl;
    if (cout.flags() & ios::scientific)
    	cout << "scientific flag set" << endl;
    else
    	cout << "scientific flag unset" << endl;
    cout << 123456789 << endl;
    cout << 123456789. << endl;
    cout << M_PI << endl;
    cout << endl;

fixed flag unset



scientific flag unset



123456789
1.2e+08
3.1
 
Two significant digits in the output








Integer format unchanged
Two significant digits: 1 and 2
Two significant digits: 3 and 1
 
(b) The program changes the output to two significant digits by calling the precision function. Floating-point numbers are rounded, but integer formatting is unchanged. Precision at 2; with fixed and scientific unset, precision is the number of significant digits.
    cout.setf(ios::fixed);
    if (cout.flags() & ios::fixed)
    	cout << "fixed flag set" << endl;
    else
    	cout << "fixed flag unset" << endl;
    if (cout.flags() & ios::scientific)
    	cout << "scientific flag set" << endl;
    else
    	cout << "scientific flag unset" << endl;
    cout << 123456789 << endl;
    cout << 123456789. << endl;
    cout << M_PI << endl;
    cout << endl;

fixed flag set



scientific flag unset



123456789
123456789.00
3.14
 
Fixed point output (not scientific)









Large numbers not printed in scientific notation

 
(c) The precision remains set at 2 from the previous block of code. With fixed set and scientific unset, precision is the number of digits following the decimal (or radix) point.
    cout << "Hexadecimal output" << endl;
    cout.setf(ios::scientific);
    if (cout.flags() & ios::fixed)
    	cout << "fixed flag set" << endl;
    else
    	cout << "fixed flag unset" << endl;
    if (cout.flags() & ios::scientific)
    	cout << "scientific flag set" << endl;
    else
    	cout << "scientific flag unset" << endl;
    cout << 123456789 << endl;
    cout << 123456789. << endl;
    cout << M_PI << endl;
    cout << endl;
Hexadecimal output

fixed flag set



scientific flag set



123456789
0x1.d7p+26
0x1.92p+1
 
Both flags set, "fixed" set above









Integers still display in base-10
Hexadecimal (base-16) output
Ditto
 
(d) Simultaneously setting the fixed and scientific flags causes floating-point numbers to display in hexadecimal or base-16 output but does not affect integers. Displaying floating-point numbers in hexadecimal is uncommon. With fixed and scientific set, precision is the number of digits following the decimal (or radix) point.
    cout << "Decimal output" << endl;
    cout.unsetf(ios::fixed);
    cout.setf(ios::scientific);
    if (cout.flags() & ios::fixed)
    	cout << "fixed flag set" << endl;
    else
    	cout << "fixed flag unset" << endl;
    if (cout.flags() & ios::scientific)
    	cout << "scientific flag set" << endl;
    else
    	cout << "scientific flag unset" << endl;
    cout << 123456789 << endl;
    cout << 123456789. << endl;
    cout << M_PI << endl;

    return 0;
}
Decimal output


fixed flag unset



scientific flag set



123456789
1.23e+08
3.14e+00
 
 
 

Switches off (i.e., sets to 0) the fixed flag









Integer format unaffected
Scientific notation
Small numbers display in scientific notation
 
 
 
(e) The unset function unsets or switches off the fixed flag but leaves the scientific flag intact, displaying all floating-point numbers in scientific notation. With fixed unset and scientific set, precision is the number of digits following the decimal (or radix) point.
Formatting floating-point numbers. The example demonstrates the flags function, symbolic constants, bitwise-AND, and the fixed and scientific manipulators.
ProgramOutput
#include <iostream>
using namespace std;

int main()
{
	cout << 23.5 << endl;
	cout << 1000000.0 << endl;
	cout << 6.0221413e23 << endl;
	cout << 1.0 / 30000.0 << endl;

	cout << endl;

	cout << fixed << 23.5 << endl;
	cout << fixed << 1000000.0 << endl;
	cout << fixed << 6.0221413e23 << endl;
	cout << fixed << 1.0 / 30000.0 << endl;

	cout << endl;

	cout << scientific << 23.5 << endl;
	cout << scientific << 1000000.0 << endl;
	cout << scientific << 6.0221413e23 << endl;
	cout << scientific << 1.0 / 30000.0 << endl;

	return 0;
}





23.5
1e+06
6.02214e+23
3.33333e-05



23.500000
1000000.000000
602214130000000022740992.000000
0.000033



2.350000e+01
1.000000e+06
6.022141e+23
3.333333e-05


 
Formatting numbers with manipulators. Two manipulators, fixed and scientific, set the corresponding stream formatting flags, accomplishing the same formatting task as setting the ios::fixed and ios::scientific flags with the setf function. Once set, the flags retain the settings until reset. So, only the first occurrence of fixed in the second code block and the first occurrence of scientific in the third block is necessary. Nevertheless, I typically include them in all statements to clarify the intended formatting.

get.cpp: Single Character Input

Some programs must read a data stream one byte or character at a time. For example, the C++ compiler reads individual characters from a source code file while constructing an intermediate program representation it can convert to machine code. The get function, a member of the istream class, performs this operation. Less often, a program may also use get to read characters from the console. Given this description, the get function's most surprising aspect is its return type.

int get();
 
int c = cin.get();
 
int c;
while ((c = cin.get()) != EOF)...
(a)(b)(c)
get function examples. The get function returns a single byte or character from an input stream as an integer. Returning returning an integer allows it to return numeric values outside the character range, including the end-of-file marker, EOF.
  1. The function prototype.
  2. A simple example of get returning a character from the console stream object, cin.
  3. The pattern utilizes three sets of parentheses, each set representing a different feature. The inner set (highlighted in blue) is the function call operator, which has a high precedence and operates first. The middle set (in red) is the grouping operator, causing the assignment operation to operate before the not-equal operation. The outer set (in black) is part of the while-loop syntax. The while-loop reads a byte from the input stream, saves it in c, and compares it to EOF. The loop continues reading and processing bytes until it reaches the end of the input.

    The illustrated pattern is common and helpful for processing a file's contents one character at a time. get automatically returns EOF when it reaches the end of the file's contents. It's more difficult to signal the end-of-file when reading input from the console (cin). A Ctrl-Z (press and hold the control key while pressing the "Z" key) inserts an EOF in a Windows input stream. However, Unix and Linux systems allow users to configure what character to use for EOF; by default, it is Ctrl-D (probably the same on a Mac).

ignore: Discarding newline characters

Sometimes, programs need to skip data present in an input stream - read it from the stream and discard it. The ignore function provides many options for performing this task. The following figure details the three ways programs can call the ignore function, distinguished by the call's arguments.

istream& ignore(int n = 1, int d = EOF);
ignore()
ignore(n)
ignore(n, d)
(a)(b)(c)(d)
ignore function options. Programs can call the ignore function in three ways. C++ implements the options with default arguments: n = 1 and d = EOF. The program uses the default values if a function call, (b) and (c), has fewer arguments than the prototype, (a). We explore default arguments in greater detail in Chapter 6.
  1. The (slightly simplified) ignore function prototype, which is where C++ specifies default arguments. In practice, programs often don't use the function's return value, so you may disregard the strange return type.
  2. Discards the next character in the input stream. The function call doesn't have any arguments, so the program uses the defaults, making the call equivalent to ignore(1, EOF).
  3. Discards n characters from the input stream. The function returns before discarding n characters if it encounters the end-of-file marker (EOF).
  4. The explicit arguments, 10 and '\n', replace the default values of 1 and EOF, respectively. The function discards 10 characters unless it detects an EOF, causing it to return early.

Programs use version (a) more often, especially when reading from the console. So, for simplicity, the following examples focus on discarding a single newline character from the console input stream. Our first step is understanding when and why a program might need to skip input.

The Setup The Problem
int counter;		// (a)
cin >> counter;

int c0;			// (b)
cin >> c0;
c0 = cin.get();
Abstract representations of the input stream when reading numeric and character data. The picture represents each byte as a square containing a character. The first input statement reads an integer, 15, from the console with the extractor operator; the picture represents the characters as three squares containing 1, 5, and the newline. The second input operation reads a character, 'A.' A C++ program can read a character with the extractor or the get function. The abstract representation is the same either way: the stream contains two characters, 'A' and the newline.
char c1;		// (c)
cin >> c1;

int c2 = cin.get();	// (d)
The input stream is viewed as a row of three boxes. Left to right: a newline, the letter 'B,' and another newline.
The newline problem. A user enters data into a C++ program through the console by typing a sequence of characters on the keyboard and pressing the Enter key. The pictures represent the console input stream as rows of boxes with a character in each box. As a user presses keys on the keyboard, the operating system adds the characters to the right side of the stream, and the program reads or removes them from the left side. Pressing the Enter signals the end of input and places a newline character (shaded in blue) in the stream.
  1. The user types the number "15" on the keyboard, and the operating system puts it in the input stream as two characters: '1' and '5.' The picture illustrates numeric input with an integer, but all numeric types behave similarly. The user ends the input by pressing the Enter key. The picture shows the number 15 and the newline character in the input stream. The extractor operator, >>, reads the 15 but leaves the newline character.
  2. The user enters the letter 'A' and presses enter. The corresponding picture shows the input stream with an 'A' and newline characters. The program can read the character with the extractor or the get function; both remove the 'A' but leave the newline.
  3. The picture illustrates the input stream after a user types a 'B' and presses the Enter key - the OS inserts the character 'B' and the newline, but the stream still contains the newline (shaded blue) from the previous read operations, (a) and (b). The extractor, >>, automatically discards the first (blue) newline, reads 'B,' removing it from the stream, but leaves the last newline - but the read operation works correctly. The demonstrated behavior is relatively recent: in the past, the extractor failed to read past a leading newline character in the input stream, at least with the compiler I use most often, until around 2020.
  4. The problem arises with a subsequent character read operation with the get function. The function reads and returns the (blue) newline, failing to read the 'B.' This error occurs whenever a program reads a character with the get function following a previous read operation.
#include <iostream>
using namespace std;

int main()
{
    while (true)
    {
        cout << "A\tAdd\n";
        cout << "S\tSub\n";
        cout << "M\tMult\n";
        cout << "D\tDiv\n";
        cout << "E\tExit\n";

        cout << "Operation: ";
        char operation;
        cin >> operation;

        switch (operation)
        {
            case 'A' : cout << 'A' << endl; break;
            case 'B' : cout << 'B' << endl; break;
            case 'C' : cout << 'C' << endl; break;
            case 'D' : cout << 'D' << endl; break;
            case 'E' : exit(0); break;
        }
    }

    return 0;
}
#include <iostream>
using namespace std;

int main()
{
    while (true)
    {
        cout << "A\tAdd\n";
        cout << "S\tSub\n";
        cout << "M\tMult\n";
        cout << "D\tDiv\n";
        cout << "E\tExit\n";

        cout << "Operation: ";
        int operation = cin.get();
        cin.ignore();

        switch (operation)
        {
            case 'A' : cout << 'A' << endl; break;
            case 'B' : cout << 'B' << endl; break;
            case 'C' : cout << 'C' << endl; break;
            case 'D' : cout << 'D' << endl; break;
            case 'E' : exit(0); break;
        }
    }

    return 0;
}
(a)(b)
Reading single characters. The programs outline a four-function calculator. They print a menu, prompt the user to select an operation, read the selection, and process it. While the examples omit the numeric input and arithmetic operations for simplicity, they still demonstrate realistic situations requiring programs to read single characters. The user selects an operation by entering a letter and pressing Enter; the operating system inserts the letter and a newline in the input stream.
  1. On the loop's first iteration, the extractor, >>, reads the letter but leaves the newline in the input stream. On subsequent loops, the extractor reads and discards the newline left from the previous input operation, reads the letter, but leaves the newline. Throughout my career as a software engineer and educator, the behavior of the extractor in this situation has evolved from C to C++ and matured from early C++ to the current behavior.
  2. Similarly, on the loop's first iteration, the get function reads the letter from the input stream but leaves the newline. However, the ignore function discards the newline, readying the stream for the next read with the get function.

Non-Standard Input Functions

int getch()Get and return a character from the console.
int _getch()
int getche()Get a character from the console, echo it back to the console, and return it.
int _getche()
Non-standard input functions. The family of getch functions returns a character entered with a single key press to the program without waiting for the user to press the Enter key. The versions that end with "e" echo the character back to the console; otherwise, the console doesn't display the character. The functions are non-standard - the ANSI C++ standard does not require them - and are not supported by all compilers. When supported, the function names may begin with an underscore character on some systems.
#include <conio.h>
	.
	.
	.
while (true)
{
	cout << "A\tAdd\n";
	cout << "S\tSub\n";
	cout << "M\tMult\n";
	cout << "D\tDiv\n";
	cout << "E\tExit\n";

	cout << Operation: ";
	int operation = _getche();

	switch (operation)
	{
		.
		.
		.
	}
}
A _getch example. This code fragment is similar to the Figure 15 examples but uses _getch, which returns a character without requiring the user to press Enter, avoiding the newline problem.