Programming in D – Tutorial and Reference
Ali Çehreli

Other D Resources

Reading from the Standard Input

Any data that is read by the program must first be stored in a variable. For example, a program that reads the number of students from the input must store this information in a variable. The type of this specific variable can be int.

As we've seen in the previous chapter, we don't need to type stdout when printing to the output, because it is implied. Further, what is to be printed is specified as the argument. So, write(studentCount) is sufficient to print the value of studentCount. To summarize:

stream:      stdout
operation:   write
data:        the value of the studentCount variable
target:      commonly the terminal window

The reverse of write is readf; it reads from the standard input. The "f" in its name comes from "formatted" as what it reads must always be presented in a certain format.

We've also seen in the previous chapter that the standard input stream is stdin.

In the case of reading, one piece of the puzzle is still missing: where to store the data. To summarize:

stream:      stdin
operation:   readf
data:        some information
target:      ?

The location of where to store the data is specified by the address of a variable. The address of a variable is the exact location in the computer's memory where its value is stored.

In D, the & character that is typed before a name is the address of what that name represents. For example, the address of studentCount is &studentCount. Here, &studentCount can be read as "the address of studentCount" and is the missing piece to replace the question mark above:

stream:      stdin
operation:   readf
data:        some information
target:      the location of the studentCount variable

Typing a & in front of a name means pointing at what that name represents. This concept is the foundation of references and pointers that we will see in later chapters.

I will leave one peculiarity about the use of readf for later; for now, let's accept as a rule that the first argument to readf must be "%s":

    readf("%s", &studentCount);

Actually, readf can work without the & character as well:

    readf("%s", studentCount);    // same as above

Although the code is cleaner and safer without the & character, I will continue to use readf with pointers partly to prepare you to the concepts of references and reference function parameters.

"%s" indicates that the data should automatically be converted in a way that is suitable to the type of the variable. For example, when the '4' and '2' characters are read to a variable of type int, they are converted to the integer value 42.

The program below asks the user to enter the number of students. You must press the Enter key after typing the input:

import std.stdio;

void main() {
    write("How many students are there? ");

    /* The definition of the variable that will be used to
     * store the information that is read from the input. */
    int studentCount;

    // Storing the input data to that variable
    readf("%s", &studentCount);

    writeln("Got it: There are ", studentCount, " students.");
}
Skipping the whitespace characters

Even the Enter key that we press after typing the data is stored as a special code and is placed into the stdin stream. This is useful to the programs to detect whether the information has been input on a single line or multiple lines.

Although sometimes useful, such special codes are mostly not important for the program and must be filtered out from the input. Otherwise they block the input and prevent reading other data.

To see this problem in a program, let's also read the number of teachers from the input:

import std.stdio;

void main() {
    write("How many students are there? ");
    int studentCount;
    readf("%s", &studentCount);

    write("How many teachers are there? ");
    int teacherCount;
    readf("%s", &teacherCount);

    writeln("Got it: There are ", studentCount, " students",
            " and ", teacherCount, " teachers.");
}

Unfortunately, the program cannot use that special code when expecting an int value:

How many students are there? 100
How many teachers are there? 20
  ← An exception is thrown here

Although the user enters the number of teachers as 20, the special code(s) that represents the Enter key that has been pressed when entering the previous 100 is still in the input stream and is blocking it. The characters that appeared in the input stream are similar to the following representation:

100[EnterCode]20[EnterCode]

I have highlighted the Enter code that is blocking the input.

The solution is to use a space character before %s to indicate that the Enter code that appears before reading the number of teachers is not important: " %s". Spaces that are in the format strings are used to read and ignore zero or more invisible characters that would otherwise appear in the input. Such characters include the actual space character, the code(s) that represent the Enter key, the Tab character, etc. and are called the whitespace characters.

As a general rule, you can use " %s" for every data that is read from the input. The program above works as expected with the following changes:

// ...
    readf(" %s", &studentCount);
// ...
    readf(" %s", &teacherCount);
// ...

The output:

How many students are there? 100
How many teachers are there? 20
Got it: There are 100 students and 20 teachers.
Additional information
Exercise

Enter non-numerical characters when the program is expecting integer values and observe that the program does not work correctly.