2002 年度「計算機基礎論3B」 2003-01-31

今回と次回は、文字や文字列を扱うプログラムを学びます。 事情があって、いままでのプリントと違い、 「これだけ読んでわかる」ように書けていません。 授業の際に補います。 また、文体が不統一ですがこの点もご容赦を。

unix の決まりごと(その1)

プログラム例(その1)

#include <stdio.h>

main()
{
    int c;

    while ((c = getchar()) != EOF) {
        putchar(c);
    }
}
K&R2 §1.5 の例である。 キーボードから一文字読み込んではその文字を画面に書いている。 プログラムの細部についてはあとで教科書を読むこと。 EOF の意味もそこに書いてある。

この種のプログラムもいままで通り「./a.out」 として起動するが、そのあとの操作に注意が必要である。

kenroku{iwase}1% ./a.out
abcdef                  <- 適当に打って最後に Enter
abcdef                  <- これはコンピュータの出力
ghi                     <- 適当に打って最後に Enter
ghi                     <- これもコンピュータの出力
kenroku{iwase}2%        <- 行頭で Ctrl+D を打つと終了

行頭でないところで Ctrl+D を打つと別の意味になる。 Ctrl+C だと、前に説明したように、そこで実行が中止される。 試してみよ。

プログラムそのものは「一文字読んではその文字を出力し……」 という形をしているが、 実際には改行が入力されてから一行をまとめて処理する。

あとでまた使うので、 上のプログラムをコンパイルしてできた実行ファイルの名前を a.out から mycat に変えておこう。 すると、「./a.out」ではなく「./mycat」 として起動することになる。試してみよ。










プログラム例(その2)

#include <stdio.h>
#include <ctype.h>

main()
{
    int c;

    while ((c = getchar()) != EOF) {
        putchar(toupper(c));
    }
}
前のプログラムをほんの少しだけ変えてみた。 toupper(c)c が小文字だったら大文字に変換し、 それ以外だったらそのまま返す関数である。 これを使うときは #include <ctype.h> が必要である。

このプログラムは、 入力された文字が小文字だったら大文字に変換し、 そうでなければそのまま、出力する。

あとでまた使うので、上のプログラムをコンパイルしてできた実行ファイルの名前を a.out から toupper に変えておこう。 その上で、このプログラムを動かしてみること。

unix の決まりごと(その2)

※ キーボードを「標準入力」、画面を「標準出力」と呼ぶことがある。











プログラム例(その3)

#include <stdio.h>

char buf[4096+1];

main()
{
    while(gets(buf)) {
        puts(buf);
    }
}
今度は、 char 型と呼ばれる、文字を格納する型の配列を用意して、 そこに gets() で一行をまとめて格納し、 puts() で出力するようにしてみた。 このプログラムは最初のプログラム例と同じように動作する。

ただし、コンパイル時に次のような警告が出る。

IPE2050{iwase}77% gcc test3.c
/tmp/ccYOD4UZ.o: In function `main':
/tmp/ccYOD4UZ.o(.text+0x11): the `gets' function is dangerous and should not be
used.
IPE2050{iwase}78%
これは “関数 gets() は危険なので使用は避けるように” と言っているのである。 その通りなのだが、 初級のプログラミングでは便利なので使うことにする。

教科書 §1.9 も参照のこと。

次のプログラムでは、puts() する前に自作関数 rev() で行を反転している。 関数 rev() ではまだ習っていないことがらを使っているので、 わからない点があって構わない。

#include <stdio.h>

char* rev(char*);
char buf[4096+1];

int main()
{
    while (gets(buf)) {
        puts(rev(buf));
    }
    return 0;
}

/* 文字列を反転する。日本語 euc に対応 */
char* rev(char* buf)
{
    unsigned char *p, *q;
    unsigned char tmp;

    /* 文字列の終わりを探しつつ2バイト文字の1バイト目と2バイト目を入れかえる */
    for (q = (unsigned char *) buf; *q != '\0'; q++) {
        if (*q & 0x80) {
            tmp = *q, *q = *(q+1), q++, *q = tmp;
        }
    }
    /* よくあるやりかたで文字列全体を反転する */
    for (p = (unsigned char *) buf, q--; p < q; p++, --q) {
        tmp = *p, *p = *q, *q = tmp;
    }
    return buf;
}
このプログラムをコンパイルして得られる実行ファイルの名前を rev に変えておこう。 それから、このプログラムで入出力リダイレクトなどを実験してみよ。

※ この linux には、 同様に動く rev というプログラムがすでにはいっているようである。

sort

unix にたいていはいっているプログラムです。 「sort」として起動します。 複数の行を入力し、最後に Ctrl+D を押すと、 それらをアルファベット順に並べ直して出力します。 これも入出力リダイレクトが効きますから試してください。

unix の決まりごと(その3)

以下の練習をやってみましょう。

※ 標準入力をを処理して標準出力に送るプログラムを 「フィルター」と呼ぶことがあります。

プログラム例(その4)

次のプログラムは、各入力行の長さを調べ、行頭に付して表示します。

#include <stdio.h>

char buf[4096+1];

main()
{
    int i;

    while(gets(buf)) {
        for (i=0; buf[i] != '\0'; i++) {
            ;
        }
        printf("%3d: ", i);
        puts(buf);
    }
}








次のプログラムは、各入力行末のスペースを取り除いて出力します。

#include <stdio.h>

char buf[4096+1];

main()
{
    int i;

    while(gets(buf)) {
        for (i=0; buf[i] != '\0'; i++) {
            ;
        }
        for (i--; buf[i] == ' '; i--) {
            ;
        }
        buf[i+1] = '\0';
        puts(buf);
    }
}
cat -E filename」ファイルを画面に出力しますが、 その際、行末に「$」をつけます。 これと組み合わせて使うと効果がよくわかります。

今までの知識を利用して、 「入力の各行末に $ を付加して画面に出力するプログラム」 を自分で書くことも(きっと)できます。

これを、 gets()puts() の組み合わせではなく getchar()putchar() の組み合わせで書くことも、 たぶんできます。 考えてみてください。

課題03

今回と次回とで、このプリントの内容を実習し、レポートしてください。 やったことを全部書く必要はありません。 「私は(それなりに)勉強しました」 ということが私に伝われば十分です。

宛て先は私(岩瀬)の実習用アカウント cf2135@mailedu1.ipc.kanazawa-u.ac.jp です。 件名は「kadai03」(←全て半角文字、アルファベットは小文字、 途中にスペースをいれない)としてください。 自分の学籍番号、氏名(として大学に届けてあるもの) をメールの本文内に書くのを忘れずに。

締め切りは 2003 年 02 月 07 日(金)17 時。

※ 次回に、今回の実習の補足を配るかも知れません。 その場合は、その部分をレポートしても構いません。

来年度前期の計算科学科の科目「     」(後藤俊一先生担当、金曜日1限)は、 数学科の3年生にも履修を認めてくださるそうです。 (他の他学科科目が履修可能かどうかは各自で確認してください。)


岩瀬順一