5日目 7日目

6日目

目標

課題 6

標準入出力

課題5までで出てきたプログラムでは、プログラムの実行が始まってしまうと、 対話的な場面はいっさいなく、いきなりプログラムが結果を出してしまっていた。 カレンダの場合には、それでも良かったのであるが、すべてのプログラムに当てはまるわけではない。
キーボードから打ち込めないワープロソフト等使い道があるだろうか?

一般に、プログラムには、入力(にゅうりょく, input)および 出力(しゅつりょく, output)がある。 すべてのプログラムは入出力を、少なくとも1つは持つはずである。 (入出力のどちらも持たないプログラムは CPU の浪費でしかない。) C では、あらかじめ用意されている入出力が 3つ存在する。 これらは標準入出力(standard input/output)と呼ばれる。

その3つとは次の通りである。

標準出力 : 一般的には画面になっている
標準入力 : 一般的にはキーボードになっている。
標準エラー出力 : 一般的には画面になっている

しかし、この入力元/出力先は固定されているわけではない。 たとえば課題5で作成した mycal7を次のように実行してみると、 画面には何も表示されない。

 ~/kadai05/mycal7 2007 11 > 2007-11.txt

kadai06 のフォルダの中を確認すると、 新しく 2007-11.txt というファイルが 作成されていることが分かるはずである。 ダブルクリック等で開いてみると(正しく mycal7.c を作成していれば) 今月のカレンダが入っているはずである。 「> 2007-11.txt」 はシェルに対する標準出力先を2007-11.txtという ファイルに変更せよという指示である。

同様に「<」を用いると標準入力元も変更することができるが、 現段階ではまだ標準入力を扱うプログラムを作成していないので試せない。

課題6では、この標準入出力について学習する。 というわけで、いままでのカレンダ作成から気分を一新して、次のようなプログラムをつくってみよう。

/* mycat1.c */
#include <stdio.h>

int main()
{
        int ch;

        for (;(ch = getchar()) != EOF;) {
                putchar(ch);
        }
}

実行しても何も起きないはずである。 しかも、今までのプログラムと異なりプロンプトも戻ってこない....。 闇雲にキーボードを叩いた人は、Enter キーを押すと、入力した内容がそのまま画面に 出てくることに気付いたかも知れない。 このプログラムを終了するには Ctrl-D(実際には stty -a で表示される eof に割り当てられているコード)を 入力する。

では、このプログラムの内容を見ていくことにしよう。

まず、気付くことはforの使い方が少し変わっているという事である。 2日目のところを確認すると、「最初に1度だけ行う分」と 「毎回の最後に行う分」が何もない形であることが分かる。 このように、for文では不要な部分を省略することができる

getchar() は標準入力から1文字(1バイト)を読み込み、返す関数である。 もし、なにも読み込むものが無くなった場合は、EOF という特別な値を返す。 そのため、getchar() は、char で表される256通りではなく、257通りの値を取るため、 char ではなく、int の型を持つ。 結局、変数 ch には読み込めた場合にはその内容が、読み込むものがなくなった場合には EOF という特別なコードが代入されることになる。 したがって、for文の条件文は、「標準入力から何か読み込める限り」という 意味になる。

一方、putchar(ch)は標準出力へ 変数chの内容を出力する関数である。 変数 chには、標準入力から読み込んだ内容が入っているのであるから、 結局、このプログラムは、標準入力(キーボード)から入力された内容をそのまま 標準出力(画面)に出力するという動作を行う事になる。

それを確かめるために次の操作を行ってみよ。

  1. > を用いて標準出力をファイルに変更した上で、キーボードから何かを入力してみる。
  2. < の後ろに上で作られたファイルを指定して、その内容が画面に出ることを確認してみる。

問題 6-1

mycat1.cを元に、行番号を表示するようなプログラムを作成し、 mycatn.cという名前で保存せよ。 行番号を表示する幅は5桁とし、ファイルの内容との間には" | "を 表示せよ。

出力例
% ./mycatn < mycat1.c
    1 | #include <stdio.h>
    2 |
    3 | int main()
    4 | {
    5 |         int ch;
    6 |
    7 |         for (;(ch = getchar()) != EOF;) {
    8 |                 putchar(ch);
    9 |         }
   10 | }

while 文

なお、今回のような繰り返し処理の場合には、for ではなく、 C 言語に存在する別の繰り返し構文である whileを用いて

    while ((ch = getchar()) != EOF) {
         putchar(ch);
    }

と書かれていることが多い。

英語の while には、「…するうち」という意味があるので、 「()で与えられた条件が成立する間、繰り返し処理を行う」というふうに 読みくだすと覚えやすいかも知れない。 while の構成は次のようにまとめられる。

 while (続けるかどうかの判定文) {
     <繰り返し処理>;
 }

このようにある条件文が成立する間の繰り返し処理には、while文をつかい、 あらかじめ繰り返し回数がわかっているような場合は for を用いるというように、 使い分けると良い。

問題 6-2

次のプログラム(先週使った arg_test.c である)を while を使って書き直すとどうなるか?

/* arg_test.c */
/* コマンドライン引数について */

#include <stdio.h>

int main(int argc, char *argv[])
{
	int i;

	for(i = 0; i < argc; ++i) {
		printf("argv[%d] = <%s>\n", i, argv[i]);
	}
}

5日目 表紙 7日目

tacha@tack.fukui-med.ac.jp
$Id: 06.html,v 1.1 2007/11/21 05:25:53 tacha Exp $