構造体は、プログラマが作れる構造を持たせた新しいデータ型といえます。
これによって、複数の情報を1つの変数で管理できるようになります。
具体的に、「名前と点数(整数)」のようなデータをそれぞれ2つ管理したい場合を考えてみましょう。
これまでの構造体を使わない方法では、
それらを記憶する変数を、次のように4つ用意する必要があります。
char name1[10]; /* 1件目の名前記憶用 */ int idata1; /* 1件目の点数記憶用 */ char name2[10]; /* 2件目の名前記憶用 */ int idata2; /* 2件目の点数記憶用 */
このような場合、「名前と点数(整数)」をまとめて、1つの変数で管理させる構造体を使うと次の ように2つの変数で済みます。
struct data_t {
char name[10]; /* 名前 */
int idata; /* 点数(整数) */
};
struct data_t d1; /* 1件目の名前と点数 */
struct data_t d2; /* 2件目の名前と点数 */
上記において、d1 と d2 のそれぞれは、nameとidataの構造を持っている変数です。
そして、d1 と d2 それぞれは struct data_tのデータ型です。
このstruct data_t型は、
の範囲で作っています。
この { と }; の範囲で、nameとidataの名前を持つような構造を作っている部分を、
構造体の定義と呼びます。
ここで、name とidata は、構造体のメンバと呼びます。
そして、 data_t は、構造体を識別するための名前で、
構造体タグ名と呼びます。
構造体タグ名は、変数名を作る規則と同じで、名前を付けます。
( の範囲で構造を設計していることになります。最後にセミコロンが必要です。)
上記例において、変数 d1 と d2は、「名前と点数(整数)」をまとめた全体を表現しています。
そして、仮に d1 = d2; を実行させれば、d2に記憶される「名前と点数(整数)」の
構造全体の情報が、d1 へコピーされます。
(実引数から仮引数へのセットもコピー処理になります。これらが可能なのは、同じ構造体の変数だけです)
しかし、d1 や d2に対して直接に比較や算術演算は使えません。C言語が基本的扱えるデータ型まで、
. 『ドットの記号』の構造体メンバ演算子で、メンバを指定する必要があります。
例えば、この例では d1のidataが80以上かを判定したい場合は、 d1.idata >= 80 という式になります。
d1.idata の表現は、構造体定義において idataをint型で作っているからです。
同様にこの例において、 d1.name の表現は、char * 型になります。
配列で作っているので、 d1.name = 値;のようには、配列名を変更する表現はエラーです。
d1.name[1] = 値;や *(d1.name+1) = 値;の表現は可能ですが、nameメンバの
配列要素数が10個なので、9を超える表現をすると、期待した領域を超えたアクセスになってしまいます(正しく実行できません)。
同様に、構造体全体をキー入力したり、画面出力できる標準関数はありません。『 . 』の構造体メンバ演算子で、
各メンバを個別に指定して入出力する形態になります。
以下で、名前と点数を2件分入力して、表示する実行例とプログラム例を示します。
名前入力>suzuki 点数入力>80 名前入力>yamada 点数入力>85 suzuki 点数:80 yamada 点数:85
#include <stdio.h>
struct data_t {
char name[10]; /* 名前 */
int idata; /* 点数(整数) */
} a, b; /* 構造体定義直後で、変数 a と bを用意 */
main()
{
printf("名前入力>");
scanf("%s" , a.name);
printf("\t点数入力>" );
scanf("%d", & a.idata);
printf("名前入力>");
scanf("%s" , b.name);
printf("\t点数入力>" );
scanf("%d", & b.idata);
printf("%s 点数:%d\n", a.name , a.idata);
printf("%s 点数:%d\n", b.name , b.idata);
}
上記のように、構造体を定義しながら、
変数を用意することが可能です。
(この場合は、構造体タグ名を省略することができます。省略した時は、他の位置で同じ種類の変数は作れません。)
構造体のスコープ(struct data_t を使った変数宣言などができる範囲)は、変数宣言と同じで、
定義位置によってローカルやグローバルのスコープになります。
なお、構造体のメンバのネーミングは、構造体が異なれば同じ名前を何回使っても構いません。
また、変数と同じ名前になっても構わない規則になっています。