1.9 関数2 Menuへ戻る

  前回に引き続いて関数です。関数の仕組みについては大体理解できたでしょうか?
ではおさらいとして半径を与えると円の面積を返す関数を作ってみましょう。

  まず、問題なのは円周率です。ここでは面倒なので 3.1415 としましょう。これを
じかにプログラムの中に書き込むのはやらしいので #define 文をつかいましょう。
見ての通り、適当な名前に数値や文字列を対応させる命令です。以下の様に書きます。

#define  PI   3.1415

  これを書くと、この後プログラムの中で書いた PI という文字列は 3.1415 として
コンパイルされます。では、はじめから 3.1415 と書けばいいじゃないかと思うかも
知れませんが、こうしておくと後で簡単に変更する事ができるのです。この #define
の部分だけ変更すれば、後の PI と書いた部分には自動的に変更されるのです。

  ある程度規模の大きいプログラムではこのようにして、後々の仕様変更に耐えられ
る様にするのも一つのテクニックです。さてさて、話を戻しまして関数作りといきま
しょう。どのような仕様にしましょうか。

  まず、返す値の型は普通、小数点の入った物ですから関数の型は float がよいと
思われます。そして受け取る半径ですが、これもついでに float 型にしておきましょ
う。すると関数宣言は

float CalcCircle(float fr)

  となります。では中身の実装といきましょう。これは簡単ですね。まず、計算用
に一つ変数を作りましょう。そして、そいつに面積を代入してみましょう。

float fCalc;

fCalc = fr * fr * PI;

  そして結果を返してやるので最後に

return fCalc;

  とすれば出来上がりです。全部書くと次のようになります。

float CalcCircle(float fr)
{
    float fCalc;
    fCalc = fr * fr * PI;

    return fCalc
}

  しかしこれだけでは芸がありませんね。もう一つ引数をとって、その値が 1 なら
面積、2 なら円周を返す様に改良しましょう。もう一つの引数は1か2にしかならな
いので int 型でいいでしょう。すると関数の宣言は

float CalcCircle(float fr, int iMode)

  となります。中身はもうわかるでしょう、以下に示します。

float CalcCircle(float fr, int iMode)
{
    float fCalc;
    switch(iMode)
    {
        case 1:
            fCalc = fr * fr * PI;
            break;
        case 2:
            fCalc = 2*fr*PI;
            break;
        default:
            printf("予期しないモード!");
            fCalc = 0;
    }

    return fCalc;
}

  では半径が 5,10,15,20 の面積と円周を計算し、表示するプログラムを書いてみま
しょう。

/* プログラム開始 */
#include "stdio.h"

#define PI  3.1415          /* define は通常プログラムのはじめに書く */

float CalcCircle(float fr, int iMode)
{
    float fCalc;
    switch(iMode)
    {
        case 1:
            fCalc = fr * fr * PI;
            break;
        case 2:
            fCalc = 2*fr*PI;
            break;
        default:
            printf("予期しないモード!");
            fCalc = 0;
    }

    return fCalc;
}


void main()
{
    int i;            /* カウンタ */
    float fResult;    /* 結果受け取り用 */

    for( i=5 ; i<25 ;i+=5)
    {
        fResult = CalcCircle((float)i,1);
        printf ("半径(%d)の円の面積 = %f\n",i,fResult);
        fResult = CalcCircle((float)i,2);
        printf ("半径(%d)の円の円周 = %f\n\n",i,fResult);
    }
}

/* プログラム終了 */

  これをコンパイルしてみて下さい。おかしな WARNING メッセージが出ますが、
これはコンパイラが親切心で出しているものなので今は無視して構いません。

  まず、まだ説明していないものの中で printf に %d と %f と2つの %? が
あります。実は printf はいくつでも書けるのです。その分、後ろに対応する
変数があればの話ですが。

  それから今までは %d しか見た事なかったかも知れませんが %f というのが
登場しています。これは fResult に対応しているのですが、この fResult は
float 型であり小数なのです。よって今までの整数型である %d は使用不可で、
小数の %f を使わなければならないのです。

  次の奴が問題です。CalcCircle の引数に (float)i としているのに気づいた
でしょうか?これは一体なんでしょう。

  まず、考えて見ましょう。CalcCircle の第一引数は何型だったでしょうか?
そうです、float 型でした。ではでは i というのは何型でしょうか。これは単
にカウンタ用に作ったものなので整数型です。

  要するに float型 を待っている所に int型 を渡そうとしているのです。
これは非常にまずいのです。型が違うので全く代入など出来ないのです。そこで
出てきたのがキャストという物で、型の違う代入の場合に型の変換をお願いする
ものです。変数の前にカッコで変換して欲しい型を囲んで書くのです。

  今回は int型 である i を float に変換して欲しいので、(float)i と書き
ました同じ様にいろいろな型に変換できます。これは今後の Windows プログラ
ミングには必須のアイテムです。

  では関数の最後に関数の決まりを説明します。ま、あまり意識する必要はあり
ませんが、知らないと思わぬ罠にはまります。では、その約束とは

  関数は呼び出す場所よりも前で宣言されていなければならない!

  つまり、どういう事かというと、前回の一番簡単な関数プログラムの順序を
変えてみましょう。

#include "stdio.h"

void main()
{
    Message();
}

void Message()
{
    printf("関数の例");
}

  これをコンパイルしてみて下さい。コンパイラに怒られましたか?

  未定義の関数 'Message' ...

  となります。つまり呼び出した場所 main よりも後ろに書いてあるので、
わからないのです。だから、この様に怒られてしまうのです。

  しかし!いちいちプログラムを書く時に順序なんか考えてられません。関数から
関数を呼び出して、そのまた呼び出された関数で関数なんか呼び出したりしたら、
もう、そんな事いってられません。

  そこで、宣言だけ先にする!という作法を普通は使います。どのような引数を持ち
返値がどんな型であるか、という事だけを最初に書いてしまうのです。そして、後か
ら好きな所で、関数の中身を書くということが許されています。つまり、どういう事
かというと

#include "stdio.h"

void Message();     /* 宣言だけ。この場合は後ろに;がいる */

void main()
{
    Message();
}

void Message()      /* ここで中身を書く */
{
    printf("関数の例");
}

  これでコンパイラは許してくれます。以上でざっと関数について説明しました。
次はC言語の最後、変数とスコープです。難しいですよ、ウフフフ。では