では、関数についてもう少し考えてみます。
何度も繰り返し実行するプログラムは関数にしておくことで簡単に呼び出せ、修正も1カ所で済みます。
RPGなどのゲームで、プレイヤーのパラメーターを表示するStatusという関数を作ってみましょう。
とりあえず、最初はヒットポイントだけをパラメーターとしておきます。
<sample program 131-01>
#include <stdio.h> void Status(int hp); int main(void) { int hp; hp = 100; Status(hp); return 0; } void Status(int hp) { printf("Player's Status\n"); printf("HP = %d\n", hp); } |
<実行結果>
Player's Status HP = 100 続行するには何かキーを押してください・・・
このStatus関数は移動中や戦闘中などいろいろな状況で使えそうな関数です。
ステータスを表示したい時に、ヒットポイントを渡して呼び出せば良いのです。
例えば次のようなケース
<sample program 131-02>
#include <stdio.h> void Status(int hp); int main(void) { int hp; hp = 100; Status(hp); /* ここに戦闘プログラムを書く */ Status(hp); return 0; } void Status(int hp) { printf("Player's Status\n"); printf("HP = %d\n", hp); } |
↑のケースでは、戦闘前と戦闘後のステータスを表示するようにしています。
関数を使わない場合↓のようになります。
<sample program 131-03>
#include <stdio.h> int main(void) { int hp; hp = 100; printf("Player's Status\n"); printf("HP = %d\n", hp); /* ここに戦闘プログラムを書く */ printf("Player's Status\n"); printf("HP = %d\n", hp); return 0; } |
関数を作ればいちいち↑のように書かなくても1行で済みますね。
さて、では実際に戦闘プログラムを書いてみましょうか。
とは言え、ヒットポイントしか無い上に戦う相手もいませんから単純にヒットポイントを減らしてみます。
<sample program 131-04>
#include <stdio.h> void Status(int hp); int main(void) { int hp; hp = 100; Status(hp); /* ここに戦闘プログラムを書く */ hp -= 50; Status(hp); return 0; } void Status(int hp) { printf("Player's Status\n"); printf("HP = %d\n", hp); } |
<実行結果>
Player's Status HP = 100 Player's Status HP = 50 続行するには何かキーを押してください・・・
戦闘の変わりにヒットポイントを50減らしました。
戦闘前と戦闘後でヒットポイントが変わっています。
では、この戦闘も関数にしてみましょう。
Battle関数を作成し、ヒットポイントを渡して、関数の中で値を減らしてみましょう。
<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); Status(hp); return 0; } void Status(int hp) { printf("Player's Status\n"); printf("HP = %d\n", hp); } void Battle(int hp) { hp -= 50; } |
<実行結果>
Player's Status HP = 100 Player's Status HP = 100 続行するには何かキーを押してください・・・
実行した結果を見るとヒットポイントが変わっていません。
これまで何度か「関数が違えば同じ名前の変数でも別々の変数」だと書きました。
これがどのような意味、仕組みになっているか調べてみましょう。
※もし読んでいなければ、コラム「メモリアドレスについて」を読んでください。
まず、main関数で宣言している
int hp; |
があります。
もう一つ、Battle関数の引数のところにも
int hp; |
と書いてあります。
これらは独立した2つの変数です。
実際の証拠を見るためにアドレスを表示してみましょう。
<sample program 131-06>
#include <stdio.h> void Status(int hp); void Battle(int hp); int main(void) { int hp; /* main関数のhpのアドレス */ printf("main hp = %p\n", &hp); hp = 100; Status(hp); Battle(hp); Status(hp); return 0; } void Status(int hp) { printf("Player's Status\n"); printf("HP = %d\n", hp); } void Battle(int hp) { /* Battle関数のhpのアドレス */ printf("Battle hp = %p\n", &hp); hp -= 50; } |
<実行結果>
main hp = 00C9F824 Player's Status HP = 100 Battle hp = 00C9F750 Player's Status HP = 100 続行するには何かキーを押してください・・・
※実行結果は毎回変わる可能性があります。
↑を見ても分かる通り、2つの変数はアドレスが異なります。
ここはしっかりと認識して欲しいので、図にして説明します。
ポイントになる箇所に番号を付けますね。
<sample program 131-07>
#include <stdio.h> void Status(int hp); void Battle(int hp); int main(void) { int hp; hp = 100; /* @ */ Status(hp); /* A */ Battle(hp); /* B */ Status(hp); /* D */ return 0; } void Status(int hp) { printf("Player's Status\n"); printf("HP = %d\n", hp); } void Battle(int hp) { hp -= 50; /* C */ } |
まず、main関数とBattle関数のhpは別々に用意されます。
変数の初期値は「不定」ですね。
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の部分でmain関数のhpが表示されます。
main関数 Battle関数 +------+ +------+ int hp | 100 | int hp | ???? | +------+ +------+ ↓ 画面に出力
main関数のhpとBattle関数のhpは異なるものなので、Battle関数のhpを変更してもmain関数のhpには何の影響もないのです。
このままでは、戦闘中に増減したパラメーターが反映されなくなってしまいます。
しかし、Battleを関数にせずそのままmain関数に書き込むことは避けたいです。
次回、色々と考えてみましょう。