前回はBattle関数を作り、戦闘後のhpがmain関数のhpに反映されないことが問題でした。
今回は対応策を考えてみます。
関数には「戻り値」というものがあります。
関数から1つデータを戻せるという機能です。
これを使えば、戦闘後のhpをmain関数に戻せるのでは無いでしょうか?
早速やってみますので、前回のプログラム↓を出してください。
<sample program 131-05>
#include <stdio.h> void Status(int hp); void Battle(int hp); /* @ */ int main(void) { int hp; hp = 100; Status(hp); Battle(hp); /* A */ Status(hp); return 0; } void Status(int hp) { printf("Player's Status\n"); printf("HP = %d\n", hp); } void Battle(int hp) /* @ */ { hp -= 50; /* B */ } |
@戻り値としてhpを戻すためvoidからintに変更します。
ABattle関数は戻り値を返すため、main関数のhpで受け取ります。
Bhpを減らした後、return文を使ってhpを戻さなければなりません。
以前やったことを思い出して変更してみてください。
解答例です。
<sample program 132-01>
#include <stdio.h> void Status(int hp); int Battle(int hp); /* @ */ int main(void) { int hp; hp = 100; Status(hp); hp = Battle(hp); /* A */ Status(hp); return 0; } void Status(int hp) { printf("Player's Status\n"); printf("HP = %d\n", hp); } int Battle(int hp) /* @ */ { hp -= 50; return hp; /* B */ } |
<実行結果>
Player's Status HP = 100 Player's Status HP = 50 続行するには何かキーを押してください・・・
実行結果を見るとhpの変化が反映されていることが分かります。
前回と同じように図で流れを書いてみます。
<sample program 132-01>
#include <stdio.h> void Status(int hp); int Battle(int hp); int main(void) { int hp; hp = 100; /* @ */ Status(hp); /* A */ hp = Battle(hp); /* B */ Status(hp); /* E */ return 0; } void Status(int hp) { printf("Player's Status\n"); printf("HP = %d\n", hp); } int Battle(int hp) { hp -= 50; /* C */ return hp; /* D */ } |
初期状態からです。
main関数 Battle関数 +------+ +------+ int hp | ???? | int hp | ???? | +------+ +------+
@の部分でmain関数のhpに初期値がセットされます。
main関数 Battle関数 +------+ +------+ int hp | 100 | int hp | ???? | +------+ +------+
Aの部分でmain関数のhpが表示されます。
main関数 Battle関数 +------+ +------+ int hp | 100 | int hp | ???? | +------+ +------+ ↓ 画面に出力
Bの部分でバトル関数が呼び出されmain関数のhpの中身がコピーされます。
main関数 Battle関数 +------+ +------+ int hp | 100 | → コピー int hp | 100 | +------+ +------+
Cの部分でBattle関数のhpが50減ります。
main関数 Battle関数 +------+ +------+ int hp | 100 | int hp | 50 | +------+ +------+
Dの部分でBattle関数のhpがmain関数に戻されます。
main関数 Battle関数 +------+ +------+ int hp | 50 | 戻り値 ← int hp | 50 | +------+ +------+
※関数の実行が完了すると引数の変数は解放されます。
Eの部分でmain関数のhpが表示されます。
main関数 Battle関数 +------+ +------+ int hp | 50 | int hp | ???? | +------+ +------+ ↓ 画面に出力
これで上手くいったように感じますが、パラメーターを増やしたらどうなるでしょう?
パラメーターとしてmp(マジックポイント、マナポイント、マジックパワーなどの略)を追加してみましょう。
まずは、Status関数を改良してmpも表示できるようにしましょう。
main関数に変数mpを追加し初期値50を入れ、Status関数の引数にもmpを追加します。
hpの次の行にmpを表示するプログラムを追加します。
それでは作ってみてください。
※プロトタイプ宣言を変更した場合、本体も同じように変更するのを忘れないようにしましょう。
<実行結果>
Player's Status HP = 100 MP = 50 Player's Status HP = 50 MP = 50 続行するには何かキーを押してください・・・
解答例です。
<sample program 132-02>
#include <stdio.h> void Status(int hp, int mp); int Battle(int hp); int main(void) { int hp; int mp; hp = 100; mp = 50; Status(hp, mp); hp = Battle(hp); Status(hp, mp); return 0; } void Status(int hp, int mp) { printf("Player's Status\n"); printf("HP = %d\n", hp); printf("MP = %d\n", mp); } int Battle(int hp) { hp -= 50; return hp; } |
<実行結果>
Player's Status HP = 100 MP = 50 Player's Status HP = 50 MP = 50 続行するには何かキーを押してください・・・
Status関数はこれで完成です。
続いてBattle関数にも引数mpを追加し、mpを渡せるようにしましょう。
途中まで書いてみます。
<sample program 132-03>
#include <stdio.h> void Status(int hp, int mp); int Battle(int hp, int mp); int main(void) { int hp; int mp; hp = 100; mp = 50; Status(hp, mp); hp = Battle(hp, mp); Status(hp, mp); return 0; } void Status(int hp, int mp) { printf("Player's Status\n"); printf("HP = %d\n", hp); printf("MP = %d\n", mp); } int Battle(int hp, int mp) { hp -= 50; return hp; } |
Battle関数の中身以外は変更しました。
さて、この中身が問題です。
とりあえず、mpを20ほど減らしてみましょう。
int Battle(int hp, int mp) { hp -= 50; mp -= 20; return hp; } |
さて、どうやってmpを戻すのでしょうか?
return文は1つのデータしか戻せません。
return hp, mp; |
とは書けませんし、
hp = Battle(hp, mp); |
こちらもhpしか受け取れない状態です。
return hp; return mp; |
このように2行に分けて書いたとしても、最初のreturn文が実行されたら関数は実行を終わります。
return hp; return mp; ← こっちは実行されない。(コンパイル時に警告が出ます) |
困りました・・・ゲームのパラメーターはhp、mpだけではありません。
構造体を使うことで一時的には解決出来ますが、構造体を2つ渡すことになれば同じ問題が発生します。
この問題を解決するため、次回から「ポインタ変数」「アドレス渡し」という考え方を説明します。