第12回

戻り値のある関数

00/06/29 サンプルプログラムのインデントを改善した
98/11/06 IE4.xに対応させた
98/04/29メールアドレス訂正

今回は値を返す関数です。前回のふざけた関数「sakebi」に、戻り値を追加してみたいと思います。さて、戻り値は、ええと・・・・・!「与えるダメージ」にしましょう。とりあえず以下のようにしてみました。あ、あくまで、と・り・あ・え・ず・です。(^_^;
#include<stdio.h>
#include<stdlib.h>
int sakebi(int a);
main(){
int dmg;
    printf("これは、お前に踏み潰されたスライムの痛みだッ!!\n");
    dmg=sakebi(3);
    printf("ラスボス(首)は、%dポイントのダメージ!!\n",dmg);

    printf("これは、ひなたぼっこ中に不意打ちを喰らったゴブリンの怒りだッ!\n");
    dmg=sakebi(6);
    printf("ラスボス(腹)は、%dポイントのダメージ!!\n",dmg);

    printf("ええと、余計なお世話の回復呪文で浄化してしまったスケルトンの分だぁッ!\n");
    dmg=sakebi(9);
    printf("ラスボス(右足すね)は、%dポイントのダメージ!!\n",dmg);

    printf("そしてこれは、全てを失った俺の怒りだッ!!\n");
    dmg=sakebi(0);
    printf("カウンターッ!!\n貴方は、%dポイントのダメージ!!\n",dmg);
    printf("ぐふッ。\n");
}
int sakebi(int a){
int i;
    if(a==0)printf("いい加減にしろ。>いーざ\n");
    else{
        printf("うぎゃ");
        for(i=0;i<a;i++)printf("ぁ"); 
        printf("ッ!!\n");
    }
    return rand();
}
すぐに気が付く問題点は、まず、戻り値を追加した意味が無いということでしょう。(^_^;
mainの中にある、与えた(与えられた)ダメージを表示するprintfの2番目の引数を、直接sakebi関数の戻り値に当たるrand()にすればいいからです。っていう指摘はとりあえずしないで下さい。これから、このプログラムをどんどん改良していきますので・・・。

まず注目したいのが、インクルードするヘッダファイルが1つ追加されたことです。2行目のstdlib.hがそれです。本プログラムでは、ランダムな整数を返すrand関数を呼んでいるのですが、その関数の宣言部分、つまり関数プロトタイプが存在するヘッダファイルが、stdlib.hという訳です。
では、実際にメモ帳またはエディタを使って、stdlib.hを開いてみることにしましょう。rand関数の関数プロトタイプは以下のようになっています。

int rand(void);
パラメータ(仮引数)がvoidになっていることは、パラメータが無いということです。で、本プログラムでは、sakebi関数の最後に追加した1行で、rand関数を呼んでいます。
return rand();
つまりこのreturn文で、rand()で得た整数を、呼び出し側(main)へ返している訳です。return文の書式は以下の通りです。
return 式;

さっきのプログラムの実行結果です。
これは、お前に踏み潰されたスライムの痛みだッ!!
うぎゃぁぁぁッ!!
ラスボス(首)は、16838ポイントのダメージ!!
これは、ひなたぼっこ中に不意打ちを喰らったゴブリンの怒りだッ!
うぎゃぁぁぁぁぁぁッ!!
ラスボス(腹)は、5758ポイントのダメージ!!
ええと、余計なお世話の回復呪文で浄化してしまったスケルトンの分だぁッ!
うぎゃぁぁぁぁぁぁぁぁぁッ!!
ラスボス(右足すね)は、10113ポイントのダメージ!!
そしてこれは、全てを失った俺の怒りだッ!!
いい加減にしろ。>いーざ
カウンターッ!!
貴方は、17515ポイントのダメージ!!
ぐふッ。
rand関数で返ってきた値はさまざまだと思います。ただ、ここで問題となるが、何度実行しても同じ乱数が返ってくることだと思います。
それはmainでsrand関数time関数を上手く使うことで解決します。話が脱線しない程度に説明します。
プログラムに、新たにtime関数の関数プロトタイプがあるtime.hをインクルードするよう加えた上で、mainの中で、
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int sakebi(int a);
main(){
int dmg;
    srand((unsigned int)time(NULL));
    printf("これは、お前に踏み潰されたスライムの痛みだッ!!\n");
    dmg=sakebi(3);
    printf("ラスボス(首)は、%dポイントのダメージ!!\n",dmg);

    ・・・ 以下省略 ・・・
と書けばいいです。time関数のパラメータのNULLは、ヌルポインタ定数と呼びます。これは、本プログラムでインクルードされるstdio.hstdlib.h、そしてtime.hで定義されています。確認しておいて下さい。
もう1つの問題点は、乱数の範囲が指定できないということでしょう。でも、これは手っ取り早く(でも、あんまり良くない)、以下のようにすることで解決できます。例えば、

rand()%5

とすれば、乱数の範囲が0から4になりますし、

rand()%5+1

とすれば、1から5までが、その範囲となります。

ちなみに、ここで使われている%は、第1オペランドを第2オペランドで割った時の余り(整数)です。


では、先程の乱数の範囲を指定する方法を、sakebi関数に導入することにしましょう。以下のプログラムは、sakebi関数のパラメータに、乱数の上限値を受け取る為の引数を1つ追加したもの(関数定義部分のみ)です。これでこの関数の戻り値は、1からパラメータ(2番目の引数)で受け取った値の範囲のどれかの整数となります。ただし、その引数で受け取った値が0である場合、そのまま処理を進めるとrand()%0となり怒られちゃいます。そこで、そういった場合は、戻り値が必ず0になるようにしました。
int sakebi(int a,int b){
int i;
    if(b!=0)b=rand()%b+1;
    if(a==0)printf("いい加減にしろ。>いーざ\n");
    else{
        printf("うぎゃ");
        for(i=0;i<a;i++)printf("ぁ"); 
        printf("ッ!!\n");
    }
    return b;
}
次回は、mainの方を改良したいと思います。

[メニュー][第11回][第13回]
[質問]

いーざ
email:CQP00202@nifty.ne.jp