C言語では、ひとまとまりのデータを 構造体 (structure) を使って表現する。
構造体はキーワード struct を使って指定する。
(例)
人の名前、年齢、身長、体重、住所を扱う構造体 tagPerson の定義。
struct tagPerson { char name[256]; short age; float height; float weight; char address[256]; };
struct の後の tagPerson の部分を構造体のタグ名 (tag name)と言う。
また、構造体の中の変数をメンバ変数 (member variable)と言う。
構造体 tagPerson 型の変数の定義。
struct tagPerson h1;
初期値を設定する場合は、波括弧 { } の中に宣言順にメンバ変数の初期値をコンマで区切って並べればよい。
struct tagPerson h2 = {"山田 太郎", 18, 180.0F, 70.5F, "不定"};
構造体 tagPerson 型の変数の利用
構造体のメンバには
でアクセスできる。
strcpy( h1.name, "福岡 工大" ); h1.age = 22; printf( "名前: %s 年齢:%d 身長:%.1f 体重:%.1f 住所:%s\n", h2.name, h2.age, h2.height, h2.weight, h2.address );
構造体型の変数のアドレスをポインタ変数として利用できる。
構造体のポインタからメンバにアクセスするには
または
という記法を使う。
※ 注意 ※
という括弧をつけない書き方は
と同等になるので、エラーになる。
※ ※
(例)
struct tagPerson *p; p = &h1; printf( "名前 %s の年齢は %d\n", p->name, p->age );
構造体をキーワード typedef を使って型定義すると、型名として使用できるようになる。
(例)
先の例の構造体 tagPersonを、構造体タグ名をつけずに、typedef によって Person という型として定義する。
typedef struct { char name[256]; short age; float height; float weight; char address[256]; } Person;
この場合、Personという型で変数を指定できる。ポインタ変数も同様に利用できる。
Person h3; Person *pp; strcpy( h3.name, "小川 遥" ); strcpy( h3.address, "日本" ); h3.age = 21; h3.height = 170.0F; h3.weight = 59.5F; pp = &h3; printf( "名前: %s 年齢:%d 身長:%.1f 体重:%.1f 住所:%s\n", pp->name, pp->age, pp->height, pp->weight, pp->address );
構造体の変数は関数にそのままパラメータとして渡すことができる。ただし、その際コピーが作られるため大きなサイズの構造体ではメモリ効率が悪くなる場合がある。
また、アドレス演算子 &
によってポインタを求めて関数に渡すこともできる。こちらの方が一般的な手法と言える。
(例)
先の Person 型のポインタをパラメータとして受け取る関数 getBMI
double getBMI(const Person *p) { double hm = p->height / 100; return p->weight / (hm * hm); }
上の関数の呼び出し例
double bmi = getBMI( &h3 );
ポインタ変数 pp を使って
double bmi2 = getBMI( pp );
としてもよい。
構造体の配列は、intやdoubleの配列と同様に定義できる。型定義を使った場合も同様である。
struct tagPerson ar1[10]; /* ar1[0] ~ ar1[9] までの10個の要素を持つ配列 */ Person ar2[15]; /* ar2[0] ~ ar2[14] までの15個の要素を持つ配列 */
C言語では、配列とポインタに以下の関係が成立する。
配列名[インデックス] ≡ *(配列名 + インデックス) ≡ *(インデックス + 配列名) ≡ インデックス[配列名]
a[3] ≡ *(a + 3) ≡ *(3 + a) ≡ 3[a]
アドレス演算子 &
については、
&配列名[インデックス] ≡ 配列名 + インデックス
&a[0] ≡ a
&a[4] ≡ a + 4
同じ配列の中の要素を指す2つのポインタ同士の減算によって、2つのポインタが指している要素のインデックスの差を求められる。(正確には、標準ヘッダ <stddef.h> で定義されている ptrdiff_t という符号付き整数型でインデックスの差が求められる)
Person ar3[100]; Person *pr1 = &ar3[5]; /* ar3 + 5 と同じ */ Person *pr2 = ar3 + 12; /* &ar3[12] と同じ */ Person *pr3 = &ar3[23]; /* ar3 + 23 と同じ */ ‥‥‥ // C99 以降の書き方 printf( "%td\n", pr2 - pr1 ); /* 12 - 5 = 7 なので 7 を表示 */ printf( "%td\n", pr2 - pr3 ); /* 12 - 23 = -11 なので -11 を表示 */ /* C99 より前の書き方例 */ printf( "%d\n", (int)(pr2 - pr1) ); /* 12 - 5 = 7 なので 7 を表示 */ printf( "%d\n", (int)(pr2 - pr3) ); /* 12 - 23 = -11 なので -11 を表示 */