5.1 入力の読み込み

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

 

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

        scanf("%d",&整数変数名);

注意するのは、何も入力がなければ、入力されるまで待つという点である。 また、ここで、整数変数名の前についている & は、実は重要な意味を持っている のだが、ここでは重要な意味を持つおまじないと思っておけばよい。 ダブルクォーテーションで囲まれた %d は、printf の時と同じような意味で、 整数として読み込むという意味である。

例1
        int a;
        scanf("%d", &a);

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

例2
        int a;
        printf("整数を入力してください。 a = ");
        scanf("%d", &a);

これで、画面上には、

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

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

 

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

これまで詳しい解説をして来なかったが、printf, scanf などは関数と 呼ばれるいわば部品である。C 言語では、このような部品を使ってプログラムを 作ることが出来るので、いい部品がたくさんあると全てを自分で作る必要が なくなり、プログラムの作成が非常に楽になる訳である。さて、この部品を呼び出し て何等かの仕事(例えば画面への表示)をさせるような場合、その仕事の結果 (うまく行ったかとか、失敗したか等)を知りたいこともある。そのために一般に C 言語では関数は値を持っている(これを返り値という)。 これは、関数を変数と同じように式の右辺等に使える ことを意味する。例えば、

            c = a * 3;

と同じような意味で、ある関数 mogemoge() があった場合、

            c = mogemoge() * 3;

などというような使い方が出来る訳である。勿論、変数とは違うので、

            mogemoge() = 2;

などのように関数にある値を代入することはできない。 詳しくは、後の関数の章で学ぶことにする。

 

そこで scanf であるが、scanf には、読み込みの成功や、成功した 個数、あるいは読み込みの失敗などを返り値で知らせるようになっている。 特に、読み込みに成功した場合は、変換に成功した個数を 返すようになっているのである。つまり、scanf は、キーボードからの 入力を読み取り、指定された形式に変換後、その変換に成功した個数を表わすと 思えばよい(この例の場合、1個しか読み込んでないので、変換に成功すると 1が返る筈である)。 そこで、例2を改良すると以下のようになる。

例3
        int a, kosuu;
        printf("整数を入力してください。 a = ");
        kosuu = scanf("%d", &a);
        if ( kosuu == 1 ){
                printf("入力した数値は、a = %d\n",a);
        }else{
                printf("入力が違います。\n");
        }

この例では、まず、キーボードから読み取った数値を変数 a に代入し、 scanf はその個数を返すので、それを変数 kosuu に代入している。 従って、もし正しく入力されていたならば変数 kosuu には、1が入っている はずで、そうでない場合には全て入力が正しくないと思われる。

 

例3では、分かりやすく入力の個数を変数 kosuu に代入していたが、 これはもっと簡単に書くことが出来る。

例4
        int a;
        printf("整数を入力してください。 a = ");
        if ( scanf("%d", &a) == 1 ){
                printf("入力した数値は、a = %d\n",a);
        }else{
                printf("入力が違います。\n");
        }

scanf の結果を判断しているのは1箇所なので、整数変数を使わずに、 そこに直接 scanf を書いている。c 言語では、こういう便利な事が 出来ることが一つの特徴である。ところが、実は、この例は更に 簡単に書ける。

例5
        int a;
        printf("整数を入力してください。 a = ");
        if ( scanf("%d", &a) ){
                printf("入力した数値は、a = %d\n",a);
        }else{
                printf("入力が違います。\n");
        }

例4との違いを良く比べてみよう。例4では、scanf の結果と1とを if 文の条件で比較していたが、今度はそれがない。これは、scanf が 正常な入力の場合には1を返し、1は真として解釈されることを利用 しているからである。

 

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

例6
        int a;
	char buf[64];
        printf("整数を入力してください。 a = ");
        for (; scanf("%d",&a)!=1 ;){
                printf("入力が間違っています。\n a = ");
		scanf("%s",buf);
                /* fpurge(stdin); for BSD */
                /* __fpurge(stdin); for Linux */
        }
        printf(" a = %d \n",a);

ここでは、繰り返しのために for 文を用いている。まず、初期化は 何も指定されていないので、継続条件が判定される。継続条件は、 scanf("%d",&a)!=1 なので、まず、scanf が実行され、 その結果が1と比較される。もし、入力が間違っていた場合は0なので 継続条件が真となり、「入力が間違っています。」が表示された後、 改行されて、「a = 」が表示されて、再び、継続条件の判定に移る。 重要なことは、最初に継続条件が判定されるので、もし、正しい 入力だったら継続条件は偽となり、その場合は、for 文の中の文は 実行されない点である。

 

また、scanf("%s",buf) という文がないと非常に困ったことになる。 実は、scanf は、入力が期待したものと違っていた場合には、読んだ 文字を返却するようになっている。何処に返却するかというと、標準入力に 返すのである。これは何か変なように思われるかもしれないが、入力というのは 実際に入力された文字を一つ一つ持っているわけではなくて、入力されたもの を全て持っているのである。例えば、入力が、「aリターンbリターン0リターン」 であったとしよう。C 言語風に書けば、"a\nb\n0\n" となっていたとする。 この入力は、一旦貯蔵庫に納められる。そして、scanf は、その貯蔵庫に 文字を取りに行くのだと思えば良い。scanf("%d",&a); で、"a\n" を 取り出し、文字 'a' を整数に変換しようとするが、これは失敗するので、 "a\n" を貯蔵庫に返却するわけである。そのために、何度 scanf をくり返し ても同じ事のくり返しになってしまう。従って、この入力を捨てる事が必要に なる。入力を捨てる方法には色々な方法があるが、ここでは scanf() を 使っている。scanf("%s",buf)buf は、ここでは詳しくは触れないが、 プログラムの先頭で char buf[64]; と宣言しておくようにする。 (ちなみに、BSD 系のOSでは、独自に 捨てるため専用の関数 fpurge() がある。Linuxでは、fpurge()は使えず、代わりに__fpurge() が使える。)

参考
scanf は、指定された形式への変換に失敗すると0を返す ことは上に書いた通りであるが、変換するべきものがなかった場合などには、-1 を返すことがある。通常、-1という値を用いずに、標準で定義されている EOF を用いる。従って、scanf の値を見るときには、0と等しいか 否かという判定をすると問題が生じる場合があるので、ここでは 1(又はそれ以上)か そうでないかで判定している点に注意しよう。



最初のページ 戻る 次へ 最後のページ 目次
Hiroyasu Asami