標準入力からの読み込み

プログラムで読み込むデータは、まず変数に格納する必要がある。例えば、入力から生徒の人数を読み込むプログラムでは、この情報を変数に格納する必要がある。この変数の型は、intだ。

前の章で見たように、出力に表示する場合、stdoutは暗黙的に指定されているため、入力する必要はない。さらに、表示する内容は引数として指定する。したがって、studentCountの値を表示するには、write(studentCount)で十分だ。要約すると、

ストリームstdout
操作write
データstudentCount変数の値
ターゲット通常はターミナルウィンドウ

writeの逆はreadfだ。これは標準入力から読み込む。その名前の"f"は"formatted"に由来し、読み込む内容は常に特定の形式で表示される必要があるためだ。

前の章で、標準入力ストリームはstdinであることを確認した。

読み込みの場合、パズルのピースがまだ一つ欠けている。データをどこに格納するかだ。要約すると:

ストリームstdin
操作readf
データいくつかの情報
ターゲット?

データの保存場所は、変数のアドレスによって指定される。変数のアドレスは、その値がコンピュータのメモリ内のどこにあるかを正確に示す。

Dでは、名前の前に入力する&文字は、その名前が表すもののアドレスだ。例えば、studentCountのアドレスは&studentCountだ。ここで、&studentCountは"studentCountのアドレス"と読み、上記の疑問符を置き換える欠けている部分だ。

ストリームstdin
操作readf
データいくつかの情報
ターゲットstudentCount変数の位置

名前の前に&と入力すると、その名前が表すものを指すことになる。この概念は、後の章で説明する参照やポインタの基礎となる。

readfの使用に関する1つの特異点は後で説明する。現時点では、readfの最初の引数は必ず"%s":

readf("%s", &studentCount);
D

実際、readf&文字がなくても動作する:

readf("%s", studentCount);    // 上記と同じ
D

&文字がない方がコードはすっきりして安全だが、参照参照関数パラメータの概念に備えるため、ここではポインタとともにreadfを使い続けることにする。

"%s"は、データが変数の型に適した方法で自動的に変換されることを示す。例えば、'4'および'2'という文字がint型の変数に読み込まれると、これらは整数値42に変換される。

以下のプログラムは、ユーザーに学生の人数を入力するよう求める。入力後、Enterキーを押す必要がある。

import std.stdio;

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

    /* 入力から読み込んだ情報を格納するために
     * 使用する変数の定義。 */
    int studentCount;

    // 入力データをその変数に格納する
    readf("%s", &studentCount);

    writeln("Got it: There are ", studentCount, " students.");
}
空白文字のスキップ

データを入力した後に押すEnterキーも、特別なコードとして保存され、stdinストリームに入れられる。これは、情報が1行で入力されたか、複数行で入力されたかをプログラムが検出するのに役立つ。

このような特殊コードは、時には便利だが、ほとんどの場合、プログラムにとっては重要ではないため、入力からフィルタリングする必要がある。そうしないと、入力がブロックされ、他のデータを読み取ることができなくなる。

この問題をプログラムで確認するため、入力から教師の数を取得しよう:

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.");
}

残念ながら、このプログラムは、intの値を期待しているときに、その特別なコードを使用することはできない。

生徒は何人いる? 100
  ← ここで例外がスローされる

前の100を入力した際に押されたEnterキーを表す特殊コードが、入力ストリームに残ったままブロックしている:

100[EnterCode]

解決策は、 %sを使用して、教師の数を読み込む前に表示される Enterコードは重要ではないことを示すことだ。 " %s"。フォーマット文字列内のスペースは、入力に表示される可能性のあるゼロ個以上の不可視文字を読み取り無視するために使用される。このような文字には、実際のスペース文字、Enterキーを表すコード、Tab文字などがあり、これらを空白文字と呼ぶ。

一般的には、入力から読み取るデータごとに " %s"を使用できる。上記のプログラムは、以下の変更を加えると期待通りに動作する:

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

出力:

生徒は何人いる? 100
教師は何人いる? 20
わかった: 生徒は100人、教師は20人だ。
追加情報
演習

プログラムが整数値を期待している箇所に、数字以外の文字を入力して、プログラムが正しく動作しないことを確認しよう。