以下の例では、人物に関するデータをひとまとめにして構造体として宣言して
いる。
(この例では、人物の氏名(最大39文字まで)、年齢、身長、体重を扱う)
personは構造体のタグと呼び、{ }の中のname,age,height,weight を構造体のメンバーと呼ぶ。/* 人物データ */ struct person { char name[40]; /* 氏名 */ int age; /* 年齢 */ float height; /* 身長 */ float weight; /* 体重 */ };
イメージとして、箱の中に氏名・年齢・身長・体重が入ったものに personと
いう名前をつけて、一つのデータ型として扱えるようにしたものと考えると分
かりやすい。
構造体を宣言した後、以下のように宣言することで、構造体person型の変数
personA が使えるようになる。
メンバーを参照する際は、.(ドット)演算子を使う。
/* 構造体person型の変数 personAの宣言 */ struct person personA; /* ドット演算子でメンバーを参照 */ strcpy(personA.name, "Mr.A"); personA.age = 24; personA.height = 170.0; personA.weight = 65.5; printf("name=%s age=%d height=%f weight=%f¥n", personA.name, personA.age, personA.height, personA.weight);
また、以下の例では、2次元の点を表現する構造体である。 メンバーとしてx, yを持ち、構造体タグはpoint2dである。
/* 2次元上の点 */ struct point2d { int x; int y; }; struct point2d a, b; /* 構造体 point2d型の変数 a, bの宣言 */ a.x = 0; a.y = 0; /* ドット演算子でメンバーを参照 */ b.x = 640; b.y = 400; printf("a: x=%d y=%d¥n", a.x, a.y); printf("b: x=%d y=%d¥n", b.x, b.y); /* 例えば、関連するデータをひとまとめにして関数の引数として渡せる */ funcA(a, b);
構造体を用いる利点は関連するデータをひとまとめに管理することで、
データの構造が分かりやすくなることである。
以下の サンプルコードのようにして、複素数(complex number)を表現するデータ 型を構造体で宣言することで、データの構造が分かりやすくなり、プログラム が書きやすくなる。(また、他人が書いたコードも理解しやすくなる)
#include <stdio.h> struct complex_number { /* 複素数を表現する構造体 */ double real; /* 実数部 */ double imag; /* 虚数部 */ }; /* 複素数の加算 */ struct complex_number complex_number_add(struct complex_number a, struct complex_number b) { struct complex_number result; result.real = a.real + b.real; result.imag = a.imag + b.imag; return result; } /* 複素数の減算 */ struct complex_number complex_number_sub(struct complex_number a, struct complex_number b) { struct complex_number result; result.real = a.real - b.real; result.imag = a.imag - b.imag; return result; } /* 複素数の乗算 */ struct complex_number complex_number_mul(struct complex_number a, struct complex_number b) { struct complex_number result; result.real = a.real * b.real - a.imag * b.imag; result.imag = a.real * b.imag + a.imag * b.real; return result; } /* 複素数の除算 */ struct complex_number complex_number_div(struct complex_number a, struct complex_number b) { struct complex_number result = { 0.0, 0.0 }; double d; d = b.real * b.real + b.imag * b.imag; if (d == 0.0) { printf("divided by zero¥n"); return result; } result.real = (a.real * b.real + a.imag * b.imag)/d; result.imag = (- a.real * b.imag + a.imag * b.real)/d; return result; } /* 複素数の表示 */ void complex_number_print(struct complex_number a) { if (a.imag < 0) printf("%f-%fi", a.real, a.imag); else printf("%f+%fi", a.real, a.imag); } void calc_test(struct complex_number a, struct complex_number b, char optype) { struct complex_number c; switch (optype) { case '+': c = complex_number_add(a, b); break; case '-': c = complex_number_sub(a, b); break; case '*': c = complex_number_mul(a, b); break; case '/': c = complex_number_div(a, b); break; default: printf("unknown operation type %c¥n", optype); return; break; } complex_number_print(a); printf(" %c ", optype); complex_number_print(b); printf(" = "); complex_number_print(c); printf("¥n"); } int main(void) { struct complex_number a, b; /* 構造体complex_number型の変数の宣言 */ a.real = 3.0; a.imag = 4.0; /* 変数aの値の設定 */ b.real = 1.0; b.imag = 2.0; /* 変数bの値の設定 */ /* 2つの複素数の四則演算結果を表示 */ calc_test(a, b, '+'); calc_test(a, b, '-'); calc_test(a, b, '*'); calc_test(a, b, '/'); return 0; }
また、以下のようにすることで、
構造体の変数の宣言と同時に値の初期化を行なうこともできる。
(宣言時に初期化をしない場合は全て0に設定される)
struct complex_number a = { 3.0, 4.0 }; struct complex_number b = { 1.0, 2.0 };
構造体変数の各メンバーを参照する場合は、ドット演算子"."を使えば よいが、構造体をポインタを介して使う場合に、メンバーを参照するには以下 のようにして、ポインタ変数を間接演算子"*"を用いて構造体を参照す る部分を括弧で括り、それに続いてドット演算子"."を用いて構造体の メンバーを参照する必要がある。
以下のように書いた場合、演算子の優先順位の都合で、先にドット演算子が 評価されるためエラーとなる。 (式の意味としては、"*(pa.real)"と書いた場合と等価になるため、 "pa.real"の部分でエラーとなる)struct complex_number *pa; /* 構造体のポインタ変数 */ ... (*pa).real = 1.0; /* 括弧で囲む */ (*pa).imag = 2.0; /* 括弧で囲む */
*pa.real = 1.0; /* エラー */ *pa.imag = 2.0; /* エラー */
ただしこの場合は、->(アロー)演算子を用いることで簡潔に表現できる。
pa->real = 1.0; /* ->演算子を使用 */ pa->imag = 2.0; /* ->演算子を使用 */
typedef unsigned int size_t; ... size_t fsize;
前述の複素数を表現する構造体complex_number型を使う場合に、 変数宣言などを行なう毎に"struct complex_number"と書いていたものも、 このtypedef宣言を行なうことで、以下のように簡単化できる。
この場合、構造体タグをつけてもつけなくても構わない。typedef struct { double real; double imag; } complex_number; ... complex_number a, b;