next up previous contents
Next: 5.2 実行プログラムの名前 Up: 5. 入力の読み込みと制御構造 Previous: 5. 入力の読み込みと制御構造

5.1 入力の読み込み

入力の読み込みと一口に言っても、状況により様々な事が要求される。 単に、キーボードから数値を読み込む場合、あるいは、ファイルから 読み込む場合、さらには、文字なども含めて読み込む場合など、 入力方法の種類は多種多様である。幸いなことに、UNIX では、標準 入力という概念があり、キーボード入力とファイルからの入力とは、 プログラムから見ると同じに取り扱える仕組みがある。従って、今回 我々が学習するのは、標準入力の読み込みに的を絞り、ファイルから 直接入力することは後に学ぶ。更に、入力されてくるものは、一般には 文字であるが、ここでは、整数のみに限定する。(これらの一般への 拡張は難しくない。)

 

整数変数への標準入力からの読み込みは、変数 cin と入力演算 >> を用いる。 その書式は、以下のとおりである。

        cin >> 整数変数名;

注意するのは、何も入力がなければ、入力されるまで待つという点である。

例1
        int a;
        cin >> a;

この例では、整数変数 a に、標準入力から整数を読み込む。しかし、 ディスプレイには、入力をうながすような目印は何も出ないので、これでは いささか不親切であるので、次の例のように通常は cout と組にして 使うほうが良い。

例2
        int a;
        cout << "整数を入力してください。 a = ";
        cin  >> a;

これで、画面上には、

整数を入力してください。 a =

と出力され、ユーザーがキーボードから整数を入力するまで、プログラムは 待つことになる。

 

しかし、これでも問題がある。何故ならば、もし、ユーザーが間違って文字を いれたとしよう。この場合、変数 a には何も入力されない。だから、入力に 成功したのか、それとも失敗したのかを知る必要がある。

 

そこで cin >> であるが、>> は、演算であるので結果があるよう になっている。if や for の判断の部分に使う場合には、 読み込みが成功した場合には !0 を返し、失敗した場合には 0 を返すようになっているので、それをifなどで判定すれば良いだろう。 (実は C++ ではこの辺の事情は意外と複雑であるが、今のところはこの程度に 理解しておけば良い。)

そこで、例2を改良すると以下のようになる。

例3
        int a, kosuu;
        cout << "整数を入力してください。 a = ";
        if ( cin >> a ){
                cout << "入力した数値は、a = " << a << endl;
        }else{
                cout << "入力が違います。" << endl;
        }

この例では、まず、キーボードから読み取った数値を変数 a に入れ、 その結果を if で判定している。

 

 

例3では、入力が間違っていた場合、再入力するためには、もう 一度プログラムを実行し直す必要があった。しかし、多くの入力を 要するプログラムでは、一度の間違いのために何度も入力をやり直させる のは、不親切というべきであろう。従って、入力が間違っていたら、 何度でも正しい入力が得られるまで繰り返すように変更してみよう。

例4
        int a;
        cout << "整数を入力してください。 a = ";
        for ( ;!(cin >> a); ){
                cout << "入力が間違っています。"<< endl <<  "a = ";
        }
        cout << " a = " << a << endl;

ここでは、繰り返しのために for 文を用いている。まず、初期化は 何も指定されていないので、継続条件が判定される。継続条件は、 !(cin >> a) なので、まず、cin >> aが実行される。 もし、入力が正しければ真なので、その否定(!)の結果、継続は 偽となる。一方、入力が正しくなければ(うまく整数が入力されない ような場合)、継続条件は真となり、「入力が間違っています。」が表示された後、 改行されて、「a = 」が表示されて、再び、継続条件の判定に移る筈である。

しかし、このプログラムを実行すると分かるのだが、うまく入力出来ている ときには正しく動作するのだが、入力が間違っている場合には次の入力を 待たずに無限に「入力が間違っています。」という文字列を出力し続ける。  

この事情を完全に説明するのはかなり難しいのであるが、第一に入力操作 というのは、入力が期待したものと違っていた場合には、読んだ 文字を返却するようになっている。何処に返却するかというと、標準入力に 返すのである。これは何か変なように思われるかもしれないが、入力というのは 実際に入力された文字を一つ一つ持っているわけではなくて、入力されたもの を全て持っているのである。例えば、入力が、「ab0」 であったとしよう。C 言語風に書けば、"ab0" となっていたとする。 この入力は、一旦貯蔵庫に納められる。そして、cin >> はその貯蔵庫に 文字を取りに行くのだと思えば良い。一回の cin>> で、"a" を 取り出し、文字 'a' を整数に変換しようとするが、これは失敗するので、 "a" を貯蔵庫に返却するわけである。そのために、何度cin>> をくり返しても同じ事のくり返しになってしまう。 従って、この入力を捨てる事が必要になる。また、同時に C++ では、この エラーの状態が cin 変数自体に記憶されている。従って、C++ ではこの エラーという記憶も元に戻さないといけない。

という訳で、エラーの記憶をcinから消去するおまじないが cin.clear() で、バッファに入っているものを消去するおなじないが cin.ignore() である。

例5
#include <iostream.h>
main(){
       int a;
       cout << "整数を入力してください。 a = ";
       for ( cin >> a ; !cin ; cin >> a){
                cin.clear();
                cin.ignore();
                cout << "入力が間違っています。" << endl <<  "a = ";
       }
       cout << " a = " << a << endl;
}

ところがこのプログラムでもまだ問題 がある。cin.ignore() はデフォルトでは1つづつしか 消去しないという性質なので、もし誤って入力されたものが1文字だけならば うまく動作するのであるが、誤って入力したものが複数の文字(文字列)ならば 問題が生じるのである。つまり、入力された文字の数の分だけループが 回ってしまうのである。試しに、上のプログラムに "aaa" と入力して見れば 分かるのだが、3回余分に「入力が間違っています。」という文章が出力 されてしまう。この問題を解消するには、cin.ignore() に 全部の入力を改行まで含めて消去せよと指示しなければならないのだが、 当面は困らないので、この問題は後程学習することにしよう。



Noriyo Kanayama