Concepts / Custom Input and Output Operators for User-Defined Types

Custom Input and Output Operators for User-Defined Types

The is>>c input operator skips whitespace by default, so it stores the first non-whitespace character it finds.

  • Programming

Why Input Does Not Always Match Your Expectations

When a program reads input from a stream, the characters it receives are not always the ones it expects. Spaces, tabs, and newlines are all whitespace, and whether they get consumed or left in the stream depends on which input operation you use. Two operations that look almost identical can return different results for the same input. This article focuses on that difference, because it determines what your program actually sees when it reads a value.

The source introduces this idea in the context of user-defined types. When you write your own input operation, you decide how it reads from the stream. You must also know how the built-in operators behave, so that your code makes the same choices deliberately rather than by accident.

A Stream That Starts With Spaces

Imagine a stream whose first two characters are spaces, followed by the letter x. You want to read a single character from it into a variable named c. Before reading the explanation, make a prediction: which character will end up in c when you use the is>>c form, and which will end up in c when you use the is.get(c) form?

What do you think happens?

Given the stream " x" (two spaces then x), what does is>>c store in c?

  • A space character

  • The letter x

  • Nothing, because the read fails

Reveal answer
Answer:

The letter x

The is>>c form skips leading whitespace by default, so it passes over both spaces and stores the first non-whitespace character it finds, which is x. The is.get(c) form, covered later in this article, behaves differently.

Tracing How is>>c Moves Through the Stream

The is>>c input operator skips whitespace by default, so it stores the first non-whitespace character it finds. The read position starts at the beginning of the stream. The operator moves past every space, tab, or newline it encounters. As soon as it reaches a character that is not whitespace, it stores that character in c. In the two-space example, the read position moves past both spaces, reaches x, and stores x.

Stream starttwo spaces, then xSkip whitespacepasses both spacesFirst non-whitespacex foundStore in cc holds xread beginsstops at non-spacestored
When the input stream starts with spaces, tabs, or newlines, where does the read position move, and which character is actually stored in c?

The diagram above traces the read from start to finish. The whitespace is consumed, not stored. The operator does not hand you the spaces at all, which is why the variable holds a visible letter rather than a blank.

cpp
Output
[x]
Walk through it
  1. 1
    The string literal contains two spaces followed by x, which is the stream we are reading from.
  2. 2
    The is >> c operation begins at the start of the stream and skips leading whitespace by default.
  3. 3
    After skipping, it stores x in c, and the output shows [x] with no space inside the brackets.
Notes on the code
  • istringstream wraps the string " x" so it can be read like a stream
  • is >> c skips the two leading spaces and stores the first non-whitespace character
  • The brackets make the stored character visible in the output

Why Whitespace Skipping Is the Default

Formatted input is designed to read values that are separated by spacing and line breaks. Because is>>c skips whitespace by default, you can lay out your input across lines or add extra spaces between values without changing what the program reads. The operator treats whitespace as separation rather than as data, so the value you care about is the first real character it meets.

Best practice

For each input operation you write, decide whether leading or surrounding whitespace is noise to be discarded or meaningful content to be kept. Make that choice on purpose, because the built-in default may not match what your data means.

Reading the Same Stream With is.get

The is.get(c) form is the contrasting case. It does not skip whitespace. It starts reading exactly at the current position, so it stores whatever character is next in the stream, including a space. Using the same two-space stream, the first character is a space, and is.get(c) stores that space rather than the x.

cpp
Output
[ ]
Walk through it
  1. 1
    The stream is the same as before: two spaces followed by x.
  2. 2
    is.get(c) reads the character at the current position without skipping anything.
  3. 3
    That character is a space, so c holds a space, and the output shows [ ] with the space inside the brackets.
Notes on the code
  • is.get(c) does not skip whitespace
  • The stored character is the first space in the stream
  • The output shows a space between the brackets
Consumedtwo spaces and xStored in cxConsumedone spaceStored in cspacestores first non-spacestores next character
Given the same whitespace-prefixed input, how do is>>c and is.get(c) differ in which characters they consume and which character each stores?

Whitespace Inside and Outside an Entry Name

The source describes an Entry input operator, a user-defined input operation for a type that holds a name. Its whitespace rule is specific: it ignores whitespace outside its name string, but it does not ignore whitespace within that string. In other words, spaces that surround the name are discarded as separators, while spaces that belong to the name itself are kept as part of the name.

In the real world

Suppose an input record reads the text " Ada Lovelace " with extra spaces on both ends. Under the Entry rule described in the source, the leading and trailing spaces are ignored as separators, while the single space between Ada and Lovelace is kept, so the stored name is "Ada Lovelace". This example is an illustration of the stated rule rather than a reproduction of the source's code.

Mistakes When Mixing Whitespace Rules

  • Common mistake

    Assuming is.get(c) skips spaces the way is>>c does

    What it looks like

    Reading from the stream " x" with is.get(c) and expecting x in c

    Why it fails

    is.get(c) does not skip whitespace, so it stores whatever character is next, which here is a space.

    Do this instead

    Use is>>c when leading whitespace should be skipped, and is.get(c) when every character, including spaces, must be read.

  • Common mistake

    Expecting every space in the input to disappear

    What it looks like

    Assuming an Entry name stored as "Ada Lovelace" will lose the space between its words

    Why it fails

    The Entry operator ignores whitespace outside its name string but not whitespace within it.

    Do this instead

    Decide which spaces are separators and which are part of the value, then design the operation to match.

  • Common mistake

    Choosing an input operator without checking what the surrounding whitespace means in the data

Looking Ahead to Pattern Matching

Reading one character at a time works when you know exactly what each position should contain. When you need to recognize a pattern across a stream of characters, the source points to a more systematic technique, regular expression matching. The source covers it in a later section and mentions it only as a pointer, so this article does not describe how it works.

For now, the useful takeaway is that character-by-character reading, with its whitespace rules, is the foundation that a pattern-recognition technique would build on. Understanding exactly which characters are consumed and which are stored is what makes later pattern work predictable.

Predict the Stored Character

MEDIUM

A stream holds three characters: a tab, a newline, and then the letter q. For each of is>>c and is.get(c), state which character ends up in c and whether the tab and newline are consumed. Then explain the difference in one sentence.

Hints
  • Ask whether the operator skips whitespace before it starts reading.
  • is.get(c) reads exactly the next character, which here is the tab.
EASY

Write a short paragraph describing an input record of your own design, such as a label followed by a value, and state for each part of the record whether surrounding whitespace should be discarded or kept.

Hints
  • Separate the separators from the content.
  • Consider whether a space that sits inside a value means the same thing as a space between values.

Key Takeaways

  • The is>>c input operator skips whitespace by default and stores the first non-whitespace character it finds.
  • The is.get(c) form does not skip whitespace, so it stores whatever character is next, including a space.
  • The Entry input operator ignores whitespace outside its name string but not whitespace within it.
  • Whitespace handling is a design decision for each input operation and must match what the data means.
  • Regular expression matching is a later, more systematic technique for recognizing patterns in character streams, built on character-by-character reading.

Related concepts

More concepts starting with C