2004 年度「計算機基礎論3B」 2004-12-03

(続き)

「プロトタイプ宣言」の行。 ここには、power() の定義の一行目と同じものを書く。 ただし、最後の中カッコ「{」を取り除き、 代わりにセミコロン「;」をつける。 これはコンパイラに 「これから出てくる power() というのはこういう関数 (int 型の引数を二つとって int 型の値を返す関数) なんだぞ」 と教えるためのものである。

※ C言語に元々そなえつけの関数(printf(), sin() など) を使う場合はプロトタイプ宣言を自分で書く必要はなかった。 実はそれらは include された stdio.h や math.h に書いてあるのだ。 これらのファイルはディレクトリ /usr/include にある。

main() も関数の一つなので返り値がある。 実は main() は OS に int 型の値を返す。 その使いみちについてはこの実習では説明しないが、 プログラムが正常に終わったときは 0 を、 そうでないときは 0 以外を返すのが普通とされている。

このプログラムは main() の中で変数 i を使い、 関数 power() の中でも変数 i を使っている。 しかし、どちらもそれぞれの関数の中だけの変数なので、 両者は全く無関係である。 すなわち、 power() の中で i の値が変わっても、 main() 側の i は変わらない。

return は、必要なら一つの関数の中に複数個おいてもよい。

    if (...) {
        return 0;
    } else {
        return 1;
    }
のように。

※ 実用の上では、 ベキ乗の計算にはそなえつけの数学関数 pow() を使うのがよいだろう。 なお、 二乗や三乗の場合は pow(x,2), pow(x,3) よりも x*x, x*x*x のほうが速い。

※ 教科書 33 ページの「旧式の版」と書かれた書き方を覚える必要はまったくない。

※ 教科書では省略されている中カッコもこのプリントでは省略せずにつけているのは、 次のようなミスに気づかないことがあるからだ。 上の main()for ループを K&R2 のように中カッコなしで書いたあと、 「0 のベキ乗もテストに加えよう」と思いたち

int main() {
    int i;

    for (i = 0; i < 10; i++)
        printf("%d %d %d\n", i, power(2, i), power(-3, i));
        printf("%d\n", power(0, i));
    return 0;
}
のようにもう一つの文をつけ加えたが、 0 のベキ乗は一つしか出力されない……?!

練習問題

その1. 上の int power(int base, int n) を改造し、 浮動小数点型の整数ベキ乗も計算できるようにした double power(double base, int n) を書け。 さらに、n が負の整数のときも正しく計算できるように改良せよ。

※ 単に「関数 power()」でなく 「関数 int power(int base, int n)」と呼ぶことで、 引数の数や型、返り値の型をも伝えることができる。

※ 「関数を作る」というのは、 「テキストファイルとして作成して終わり」ではなく、 検査用の main() も書いて、コンパイルして実行し、 思ったように動くことを確認することである。

その2. 階乗を計算する関数 factorial() を書け。 引数や返り値の型は自分で考えること。 main() では

    0 の階乗は 1 です.
    1 の階乗は 1 です.
    2 の階乗は 2 です.
    3 の階乗は 6 です.
    4 の階乗は 24 です.
     ...
のように出力させてみるとよいだろう。

※ すぐにできない人はその前に

    int n, f;

    printf("いくつの階乗を計算しますか?\n");
    scanf("%d", &n);
    /* ここで n の階乗を計算する */
    printf("%d の階乗は %d です.\n", n, f);
として 「4 の階乗は 24 です.」が出力されるようなプログラムを書いてみよ。 それを参考にすればできるはずだ。

関数の自作(続き)

次のプログラム片は、K&R2 §1.8 からの引用である。 (一部変更してある。)

int power(int base, int n) {        /* K&R2 より */
    int p;

    for (p = 1; n > 0; n--) {
        p = p * base;
    }
    return p;
}

前のプログラムの関数 power() の定義の部分だけを上で置き換えてもプログラムは同じように動く。

関数 power() の中で引数 n の値を変えても、 呼び出し側の i の値は変わらない。 power(2, 3) を計算するときに power() に渡した 3 は i のコピーであって変数 i そのものではない、 というのがC言語の約束である。

このことを「call by value(値による呼び出し)」ということがある(らしい)。


岩瀬順一