構造体(structure)は互いに関連する2つ以上の変数で構成される複合型。構造体の持つ変数をメンバと呼び、それぞれのメンバは異なる型でも構わない。
構造体を定義するときの一般的な形式は次のとおり。
struct タグ名 { 型 メンバ1; 型 メンバ2; 型 メンバ3; ... 型 メンバN; } 変数リスト;
タグ名は構造体につける名前だ。いってみれば型名のようなもの。
変数リストは、定義したい変数のリスト。
タグ名と変数リストは、どちらかは省略できる。タグ名を省略すると、名前のない構造体の変数を定義することになる。一方、変数リストを省略すると、タグ名のついて構造体だけの定義となって、実際に変数を使うときにはあとから改めて宣言する必要がある。
普通はタグ名だけつけていおいて、変数はあとで宣言するのがいいんではないかな。次の例では catalog というタグ名の構造体を定義して、あとからその変数を宣言している。
struct catalog { char name[40]; char title[40]; char pub[40]; unsigned date; unsigned char ed; }; struct catalog var1, var2, var3;
構造体を配列にすることもできる。
struct catalog cat[100];
配列の個々の構造体にアクセスするには、配列名に添字をつける。
cat[4]
構造体のメンバにアクセスするには、ドット演算子を使う。これは、メンバを参照するときもメンバに代入するときも同じ。構造体が配列になっている場合も同じ。
var1.date = 1776; cat[50].ed = 2;
構造体を関数に渡すこともできるし、関数の戻り値とすることもできる。
また、両方の方が同じなら、構造体の変数(インスタンス)を別の変数にそのまま代入することもできる。
これはちょっと試してみよう。
#include int main(void) { struct s_type { int a; float f; } var1, var2; var1.a = 10; var1.f = 100.23; printf("var1: %d %f\n", var1.a, var1.f); var2 = var1; printf("var2: %d %f\n", var2.a, var2.f); var2.a = 5; var2.f = 10.56; printf("var1: %d %f\n", var1.a, var1.f); printf("var2: %d %f\n", var2.a, var2.f); return 0; }
構造体 var1 と var2 を宣言して var1 のメンバに値を代入したあと、var1 をそのまま var2 に代入する。それから var2 のメンバの値を変更してみる。
takatoh@nightschool $ ./sample_10_1a var1: 10 100.230003 var2: 10 100.230003 var1: 10 100.230003 var2: 5 10.560000
最初の2行は var2 に var1 を代入した直後の出力。当然同じ値になっている。
次の2行は、var2 のメンバを変更したあとの出力。var2 のメンバは変更されているのに対して、var1 のメンバは変更されていない。てことは、構造体の代入では値がコピーされるってことでいいのかな。
構造体のサイズを調べるときには sizeof を使う。各メンバのサイズの合計を計算しようとしてはいけない。環境によっては構造体のサイズがメンバのサイズの合計と同じにならないからだ。
#include struct s_type { int i; char ch; int *p; double d; } s; int main(void) { printf("size of s_type is %ld bytes.\n", sizeof(struct s_type)); return 0; }
takatoh@nightschool $ ./sample_10_1b size of s_type is 24 bytes.