Proven C Book←↑→

26 Input

What to know first

chapter 23, Output · the two roads of output
chapter 9, The origin of streams · a stream runs both ways

Looking back

Chapter 9 said input, like output, is “a band of characters flowing a line at a time”, and that human input naturally comes in lines ending with Enter (line buffering). Then is the natural unit in which a program takes input also — the line?

A. Exactly so — and that is this chapter’s design principle. A person writes a line and presses Enter. So it follows the grain of the flow for a program to receive a whole line and then find the values it needs inside it. Lifting a line out of the band of characters, and interpreting the lifted line — split those two and each becomes simple.

The need for this chapter, and its context

There is a reason input comes after output (chapter 23): you need somewhere to put what you read, and that is chapter 24′s variable. And this chapter deliberately pays only half the debt — the rest of safe input belongs to chapter 44, after arrays and strings. Flagging the danger here and settling it later is the two-stage approach this book chose.

By the end of this chapter

We complete chapter 23′s promise — with somewhere to store a value (a variable), we take input. The way this book teaches from the start is exactly modern practice: read a whole line, then interpret that line. Separating reading from interpreting — that two-stage structure is the source of both convenience and safety. Part V is completed here.

The questions this chapter answers

  1. Why split into two stages? I hear there is also a function (scanf) that reads %d straight from the input.
  2. How big should the box be?
  3. So after reading 42 with %d, what is left in the tub?
  4. Set “outside the contract” aside for a moment. If the standard had given us a proper function for “empty the input buffer”, what would that function have to do?

26.1 Two stages — read, then interpret#

The demonstration first. A program that takes one integer from standard input and reports its square. (What was given on standard input for this run is shown in the middle box.)

examples-en/ch25/read.c

#include <stdio.h>

int main(void)
{
    char line[100];   /* room for 100 characters — properly explained in chapter 33 */
    int n = 0;

    fgets(line, sizeof line, stdin);   /* step 1: read one whole line */
    sscanf(line, "%d", &n);            /* step 2: interpret an integer out of that line */

    printf("%d squared is %d.\n", n, n * n);
    return 0;
}

Given on standard input

7

Output

7 squared is 49.

There are two new faces — one per stage.

Stage 1, fgets — read a whole line. fgets(line, sizeof line, stdin) reads one line from standard input (stdin is its name) and holds it in a space called line. The first line’s char line[100]; is a declaration meaning “take a space of 100 character slots and call it line” — but the formal syntax of a multi-slot space (an array) belongs to chapter 39, so for now know it only as “a container for a line” (a deliberate credit). The second material, sizeof line, is “the number of slots in the container” — a safety device telling fgets the container’s size so that nothing is ever put in past its edge (formal treatment of the sizeof operator is chapter 36).

Stage 2, sscanf — interpret the line we fetched. sscanf(line, "%d", &n) is the partner of chapter 23′s printf — it uses the same format language in the opposite direction. Where printf turned values into characters and sent them out, sscanf finds in the characters (the "7" inside line) a value matching the format (%d) and puts it into a variable. The & before the name is “a mark telling it the place of the variable to put the value in” — the moment addresses, learned in chapter 3, first show their face in the grammar; formal treatment is in chapter 36 (this is Part V’s last deliberate credit).

Q. Why split into two stages? I hear there is also a function (scanf) that reads %d straight from the input.

A. There is, and many primers teach it first — this book takes a different road for two reasons. First, the aftermath of failure is clean. Even if interpretation fails (something that is not a number arrives), the line is already in our own container, so the input band never stops half-way and gets tangled — read directly from the band and fail, and the leftover characters stay caught on the band and contaminate the next read, which is the classic headache of using scanf directly. Second, the grain of safety is the same. Reading a line is a structure in which you tell the container’s size as you read, so overflow is blocked at the source — what accidents the old ways that do not state a size caused, and how this two-stage practice seals them off, is the story of chapter 43. Getting the safe grain into your hands from the start — that is this book’s choice.

26.2 The contract of fgets — what it gives, and what it leaves to you#

Know the first stage exactly. fgets promises three things.

PromiseWhat it means
it will not exceed the boxit was told sizeof line, so it stores no more — overflow is cut off at the root
it appends a NULso what arrived can be used as a string (chapter 43)
it keeps the newlinethe \n of the line read is inside the box — stripping it is your job

Table 26.1 — What fgets promises

The third bites beginners most often. The listing makes it visible — the newline is printed as @.

examples-en/ch25/lines.c

/* The contract of fgets — what it fills in, and what it does not tell you. */
#include <stdio.h>
#include <string.h>

int main(void)
{
    char line[16];          /* deliberately small — to show truncation */

    puts("[read one line at a time and echo it back]");
    while (fgets(line, sizeof line, stdin) != NULL) {
        size_t len = strlen(line);
        int has_nl = (len > 0 && line[len - 1] == '\n');

        /* make what arrived visible — the newline shown as a mark */
        printf("  got: \"");
        for (size_t i = 0; i < len; i++)
            putchar(line[i] == '\n' ? '@' : line[i]);
        printf("\"  (%zu bytes, newline at the end: %s)\n",
               len, has_nl ? "yes" : "no");

        if (!has_nl)
            puts("    -> no newline means 'the line was longer than the box and was cut'");
    }

    puts("\n[two reasons reading ends]");
    puts("  fgets returning NULL means 'nothing left (EOF), or an error'.");
    puts("  feof and ferror tell them apart; chapter 63 treats them properly.");
    return 0;
}

Given on standard input

hi
this line is definitely longer than the box
bye

Output

[read one line at a time and echo it back]
  got: "hi@"  (3 bytes, newline at the end: yes)
  got: "this line is de"  (15 bytes, newline at the end: no)
    -> no newline means 'the line was longer than the box and was cut'
  got: "finitely longer"  (15 bytes, newline at the end: no)
    -> no newline means 'the line was longer than the box and was cut'
  got: " than the box@"  (14 bytes, newline at the end: yes)
  got: "bye@"  (4 bytes, newline at the end: yes)

[two reasons reading ends]
  fgets returning NULL means 'nothing left (EOF), or an error'.
  feof and ferror tell them apart; chapter 63 treats them properly.

26.2.1 How do you know it was cut?#

The middle two lines of the listing answer that. When a line longer than the box arrives, fgets stores only as much as fills the box and returns — and then there is no newline at the end.

How the box endsMeaning
it ends with … \none whole line was received
it ends with no newlinethe line was cut — the rest is still on the band, and the next fgets picks it up

Table 26.2 — Reading the result from what the buffer’s end looks like

That is, “is there a newline at the end?” is the signal of truncation. The listing’s one long line arriving in three pieces is the proof.

Two idioms follow in practice.

line[strcspn(line, "\n")] = '\0';   /* strip the newline if there is one */

The first is stripping the newline. That one line is the idiom: strcspn (chapter 43) gives “where the first \n is”, so putting a NUL there removes it. With no newline it points at the end of the string and nothing happens — one line handles both cases.

The second is treating truncation as an error. Let “cut but fine” pass as success and looking up a file under a truncated name follows — chapter 44 treats it properly as one of five disciplines.

Q. How big should the box be?

A. There is no single answer, only a basis for judging.

For a line a person types, be generous — 256 or 1024 are common choices for a name, a path or a command. The listing used 16 deliberately, to show truncation.

Where the line length has no bound, enlarging the box does not end it. Then you check for truncation and join the pieces (calling fgets again), or use a tool that grows the box to the line — POSIX’s getline, which standard C does not have (chapter 71).

One thing to remember: as long as you use a function that takes the size, a box too small causes “truncation”, not “overflow”. Truncation can be checked; overflow brings the program down.

26.3 What stays in the tub — predict, take, leave#

Chapter 9 asked you to imagine a tub (a buffer) along the input band. Now we look into it, because this is the real reason for the two-stage way.

What a formatted read (scanf, sscanf and their family) does, put in the standard’s vocabulary, is three steps.

  1. It predicts. Every directive in the format is a prediction that “something of this shape will come”. %d predicts the shape of a decimal integer, %s the shape of a run of non-white-space characters.
  2. It takes. It takes the longest run of characters that fits the prediction. The standard calls this the input item and defines it as “the longest sequence of input characters which does not exceed any specified field width and which is, or is a prefix of, a matching input sequence” (§7.23.6.2p9).
  3. It leaves. And this one line is the heart of it: “the first character, if any, after the input item remains unread” (same clause). Only what was taken is gone; the rest is still in the tub.

Two further rules ride along. Most directives skip leading white space first — only [, c and n do not (§7.23.6.2p8). And a white-space character in the format is a directive meaning “read up to the first non-white-space character”, and it never fails (p5).

Q. So after reading 42 with %d, what is left in the tub?

A. The newline is left. If 42\n was in the tub, %d takes only 42 — a newline is not the shape of a decimal integer, so it is “the first character after the input item” and, by the rule, stays unread.

That leftover newline is the classic place where beginners are caught. Read a line next and you get an empty line (the leftover newline ends it); read a character next and you get the newline instead of a character. The program looks as if it “skipped the input”, when in fact it ate this time what it left last time.

In practice. Why reading in two stages makes this go away

Here is why this chapter chose “read a whole line, then interpret”.

fgets does not predict. It takes up to the newline (or until the vessel is full). So no scraps of this line are left in the tub — only the next line, whole. Interpretation then happens inside my own vessel (sscanf), so even when it fails the tub is already clean.

Two stages, then, means moving the prediction out of the tub and into a vessel. When a prediction misses, what gets messy is my vessel rather than the tub, and trying again is easy.

Platform note. when you want to clear what is left

It is easy to think “just flush the tub, then”, and there really is a great deal of code on the internet that writes fflush(stdin). But as chapter 9 said, flushing is an outgoing act, so this is outside the contract. On one implementation it appears to work, on another it does nothing at all — chapter 68 returns to it with the clause.

The right way to clear what is left is to read it and throw it away: a short loop reading one character at a time until a newline. With the two-stage way of this book, though, the occasion rarely arises.

Q. Set “outside the contract” aside for a moment. If the standard had given us a proper function for “empty the input buffer”, what would that function have to do?

A. Try to write it down and the definition will not hold still, because — as chapter 9 showed — the program does not know what is on the other end of the band.

  • At a terminal with a person, input mostly comes a line at a time. If they have typed nothing yet, the tub is empty and there is nothing to discard.
  • Through a redirection from a file, it is all there already. “Emptying” could mean throwing away the entire file.
  • Through a pipe with a program upstream, it is still arriving. Empty it now and more lands an instant later.
  • Across a network, that “still arriving” is far longer and far more uneven.

One sentence cannot define all four. Forced to write one, you get “discard what had arrived by the moment this function was called” — and then the amount discarded is decided by the other side’s pace, not by my program. Such a function does not give the same result for the same input; it is less a specification than a race.

So it is fairer to read the standard’s silence here as deliberate rather than as an omission. What to discard must be named as a boundary, not an instant — not “whatever has arrived” but “up to the newline”. That is why the loop above is written the way it is, and why two-stage reading avoids creating such a place at all. Chapter 68 arrives at the same conclusion from the standard’s own clause.

26.4 Interpretation can fail#

Unlike output, input has one wholly new problem — you do not know what the other side will send. You expected 7 and seven may arrive. So sscanf’s return value is the number of values successfully interpreted — in the example above, 1 on success and 0 on failure.

As we are now, we have no syntax — branching — for checking that return value and taking one road on success and another on failure. So the example above discarded the return value and laid a floor for the failing case by initialising n to 0 (chapter 24′s habit). The fork appears in the next part (chapter 31), and the discipline of “report failure as a value and always check it” is established formally in chapter 53 — checking input will be that discipline’s first real exercise.

A common misconception. “Input comes from the keyboard”

Mostly it does, but that is not its essence — input comes from the standard input stream (chapter 9). In fact the demonstration just given is the proof: there is nobody striking a keyboard at this book’s example-verification machine — the input 7 above was held in a file and flowed onto the band of standard input (redirection). Just as chapter 23′s output is not screen-bound, input is not keyboard-bound, so the same program serves conversation with a person, file processing, and joining programs together, unchanged. The power of the stream design repeats on the input side too.

26.5 Closing Part V#

We have learned all of how to make names — the name of a value (chapter 24), the name of work (chapter 25), and how to take a value from the outside world and hold it in a name (chapter 26). Chapter 16′s credit ledger is settled, and the credit newly taken is exactly two — the line container (char line[100], in chapter 39) and the place marker (&, in chapter 36) — and both have their due dates written down.

Above all, a program can now converse. Take in, calculate, answer — in the next part we forge the calculation itself: facing the world of integers (chapters 28–29), comparing and deciding (chapters 31–32), repeating (chapter 33), and completing the meaning of functions (chapter 34). It is the part of values and flow.