
C言語で構造体を扱う方法を確認していきます。 構造体を使うことで、自分が作りたいオリジナルの型のようなものを作成し、 いくつかの変数をまとめて一つの変数で管理すること等が可能になります。
早速ですが、キャラクタの名前、レベル、体力を1つの構造体で管理してみましょう。 下の用に定義することができます。
struct CharacterStatus {
char const *name;
int level;
int hitpoint;
};
structという新しいキーワードが出てきています。 struct は日本語に直訳すると「構造」という意味です。 下のように書くことができます。
struct 構造体の名前 { 構造体の中身の構成 };
構造対の中身の構成は、例では 3 つ(名前、レベル、体力)でしたが、他にも自由に追加できます。
オブジェクト指向プログラミング C言語の構造体を使うことで、オブジェクト指向プログラミングの考えを部分的に 取り入れやすくなります。 例えば Java 言語の クラス に近い感覚で情報を扱うことも可能です。 ただし、オブジェクト指向プログラミングをそもそも言語機能として取り込んではいないため、 コードは若干、読みづらいものになりがちです。
構造体の宣言、定義、初期化、データの読み出しの流れを確認していきます。
#include <stdio.h>
struct GameCharacter;
struct GameCharacter {
char const *name;
int level;
int hitpoint;
};
void printCharacterStatus(struct GameCharacter *c) {
printf("============\n");
printf("名前:%s\n", c->name);
printf("レベル:%d\n", c->level);
printf("HP:%d\n", c->hitpoint);
}
int main(){
struct GameCharacter planc;
planc.name = "planc";
planc.level = 1;
planc.hitpoint = 5;
struct GameCharacter enemy;
enemy.name = "Charotte";
enemy.level = 2;
enemy.hitpoint = 8;
printCharacterStatus( &planc );
printCharacterStatus( &enemy );
}
先ほどの例と同じ構造体、GameCharacter を使っていきます。
実行すると下の結果になりました。
============
名前:planc
レベル:1
HP:5
============
名前:Charotte
レベル:2
HP:8
今回は構造体 GameCharacter はあちこちで使いまわすことを考え、 main 関数のなかではなく、ソースコードの冒頭のグローバル領域の場所でプロトタイプ宣言しています。
struct GameCharacter;
関数のプロトタイプ宣言と同じで、いろいろなソースコードから参照して使えるようにするため、 通常、ヘッダーファイルの中で宣言を書いておき、 実際の定義(中身の構造など)は拡張子 .C の中に書いておきます。
今回も説明のためにプロトタイプ宣言していますが、この行は無くてもコンパイラはちゃんと動きます。
続いて、3~7行目で構造体の定義をしています。
struct GameCharacter {
char const *name;
int level;
int hitpoint;
};
具体的に、どのような値を持っているかを定義していきます。
続いて、 main 関数を見ていきましょう。
int main(){
struct GameCharacter planc;
planc.name = "planc";
planc.level = 1;
planc.hitpoint = 5;
struct GameCharacter enemy;
enemy.name = "Charotte";
enemy.level = 1;
enemy.hitpoint = 5;
16 行目で、構造体を使った変数 planc を定義しています。 構造体を使うには、以下のように記述します。
struct 構造体の名前 変数の名前;
int 型や char型などと同じように、複数の変数を一度に宣言することもできます。
struct GameCharacter planc, enemy;
続いて、17 行目からは構造体の変数の中身を初期化しています。
planc.name = "planc";
planc.level = 1;
planc.hitpoint = 5;
変数 planc の構造体の中身、 name 、level、hitpoint にアクセスして、それぞれ初期化しています。
構造体の変数の中身にアクセスするときは下のように書きます。
構造体の変数名.アクセスしたい要素名
ですので、変数 planc の構造体の level に値 1 を代入したい場合、
「planc.level = 1
」と書けば OK です。
変数 planc、enemy の定義と初期化が終わったのち、 自前の関数 printCharacterStatusを呼び出しています。
printCharacterStatus( &planc );
printCharacterStatus( &enemy );
printCharacterStatus は構造体 GameCharacter のアドレスを受け取り、 中身(キャラクターのステータス)を表示する関数です。
では、printCharacterStatus 関数の中身を見てみましょう。
void printCharacterStatus(struct GameCharacter *c) {
printf("============\n");
printf("名前:%s\n", c->name);
printf("レベル:%d\n", c->level);
printf("HP:%d\n", c->hitpoint);
}
printCharacterStatus 関数は構造体 GameCharacter のポインタを引数で受け取るように 定義されています。
受け取ったポインタ変数 c へのアドレスを基準に、名前やレベル、ヒットポイントなどの 構造体の中身のアドレスへアクセスが出来ます。
具体的には、下のように書くことで、構造体の中身のアドレスへアクセスできます。
構造体のポインタ変数->アクセスしたい要素名
一般に「->」の記号は右矢印みたいに見えるので、 アロー演算子(Arrow Operator) と呼ばれることが多いです。
例えば、構造体 GameCharacter のポインタ変数 c の構造体の中身、name には 「c->name」でアクセスすることができます。
printf("名前:%s\n", c->name);
構造体を使うとき、いちいち、struct 構造体名 変数名;
と書くのはちょっとめんどくさいので、
例えば、typedef ディレクティブを使って別名を定義することで、もうすこし簡潔に書くことができます。
#include <stdio.h>
struct GameCharacter {
char const *name;
int level;
int hitpoint;
};
typedef struct GameCharacter gc;
int main(){
gc planc;
planc.name = "ぷらんく";
planc.level = 5;
planc.hitpoint = 100;
}
このようにtypedef struct GameCharacter gc;
と書いておくことで、
以降、「struct GameCharacter」の代わりに 「gc」と記述することができます。
また、構造体の定義と typedef を一つにまとめて、下の用に書くことができます。
typedef struct GameCharacter {
char const *name;
int level;
int hitpoint;
} gc;
このとき、構造体本体の名前は省略することができます。
typedef struct {
char const *name;
int level;
int hitpoint;
} gc;
typedef で「struct{~}」を「gc」で記載できるように型を定義、ということをしています。
構造体の変数の定義と初期化は同時に行うことができます。
#include <stdio.h>
typedef struct GameCharacter {
char const *name;
int level;
int hitpoint;
} gc;
void printCharacterStatus(gc *c) {
printf("============\n");
printf("名前:%s\n", c->name);
printf("レベル:%d\n", c->level);
printf("HP:%d\n", c->hitpoint);
}
int main(){
gc planc = {"planc", 1, 5};
gc enemy = {"Charotte", 2, 8};
printCharacterStatus( &planc );
printCharacterStatus( &enemy );
}
16 行目、17行目で、変数 planc、enemy の宣言と初期化を同時に行っています。 gc(つまり struct GameCharacter のことです)の中身を、"{"、" }"の中の要素で 順番に初期化できます。
gc planc = {"planc", 1, 5};
このコードは下と同じ結果になります。
gc planc; // 変数の宣言
planc.name = "planc"; // 変数の初期化
planc.level = 1; // 変数の初期化
planc.hitpoint = 5; // 変数の初期化
これでだいぶコードがスッキリしました!
コメント、ありがとうございます。
ごめんなさい。エラーでうまく送信できませんでした。ご迷惑をおかけします。しばらくおいてから再度送信を試していただくか、以下から DM などでご連絡頂ければと思います。
Twitter:@NodachiSoft_jpお名前:以下の内容でコメントを送信します。よろしければ、「送信」を押してください。修正する場合は「戻る」を押してください
お名前: