引数としての構造体について説明します。
まずは適当な構造体を宣言します。
typedef struct { int hp; int mp; } Player; |
この構造体を関数に渡すには変数と同じように考えれば良いです。
以前のプログラムと同じく、ステータスを表示するStatus関数を作ってみます。
プロトタイプ宣言は↓の通り。
void Status(Player player); |
Player構造体でplayerという実体を作り、ここでデータを受け取ります。
本体は構造体を受け取っているので、
void Status(Player player) { printf("Player's Status\n"); printf("HP = %d\n", player.hp); printf("MP = %d\n", player.mp); } |
のように書きます。
では、実際に作ってみましょう。
<sample program 138-01>
#include <stdio.h> typedef struct { int hp; int mp; } Player; void Status(Player player); int main(void) { Player player; player.hp = 100; player.mp = 50; Status(player); return 0; } void Status(Player player) { printf("Player's Status\n"); printf("HP = %d\n", player.hp); printf("MP = %d\n", player.mp); } |
<実行結果>
Player's Status HP = 100 MP = 50 続行するには何かキーを押してください・・・
※Player構造体は関数の外で宣言しているため、main関数でもStatus関数でも使用可能です。
では、これも以前と同じように戦闘の関数を加えてみたいと思います。
戦闘中に変化したパラメーターは戦闘後にも反映されていなければなりませんので、構造体のアドレスを渡す必要があります。
構造体のアドレスも、実体の先頭に「&」を付けることで表せます。
ポインタ変数も構造体で宣言しますので、Battle関数のプロトタイプ宣言は↓のようになります。
void Battle(Player *pPlayer); |
本体は、hpを50減らし、mpを20減らすよう作ります。
void Battle(Player *pPlayer) { pPlayer->hp -= 50; pPlayer->mp -= 20; } |
ここが注目点です。
構造体のアドレスを受け取ってメンバ変数にアクセスする時には「.」ドット演算子ではなく「->」アロー演算子を使います。
当然、「.」ドット演算子を使った場合はエラーになります。
error C2231: '.hp': 左のオペランドが 'struct' へのポインターです。'->' を使用してください。
このようなメッセージが出てきます。
間違えないようにしっかりと覚えておいてください。
では、実際にBattle関数を加えたプログラムを作ってみます。
<sample program 138-02>
#include <stdio.h> typedef struct { int hp; int mp; } Player; void Status(Player player); void Battle(Player *pPlayer); int main(void) { Player player; player.hp = 100; player.mp = 50; Status(player); Battle(&player); Status(player); return 0; } void Status(Player player) { printf("Player's Status\n"); printf("HP = %d\n", player.hp); printf("MP = %d\n", player.mp); } void Battle(Player *pPlayer) { pPlayer->hp -= 50; pPlayer->mp -= 20; } |
<実行結果>
Player's Status HP = 100 MP = 50 Player's Status HP = 50 MP = 30 続行するには何かキーを押してください・・・
構造体にも「値渡し」と「アドレス渡し」があることが分かりました。
「値渡し」よりも「アドレス渡し」の方が効率が良いのですが、この話はまた後でしましょう。