12.構造体12.1.構造体とは「intやcharなどの基本データ型を好きなように組み合わせて、新しいデータ型として扱うもの」を「構造体」と呼びます。構造体はひとつの名前だけで関連したいくつもの変数を一度にあつかうことができます。通常それらの間には密接な関係があり、構造体はそれらをひとつの名のもとに組織化するという働きをします。 例えば生徒の「学生番号」「名前」「学年」を管理したい場合、それぞれを別々に管理するよりも以下のような構造体を作成する方がすっきりとします。 struct student{
char id[20];
char name[20];
int gakunen;
};
12.2.構造体変数の宣言・初期化構造体を使用する場合、「構造体そのものの宣言」と「変数の宣言」の2つに分かれます。 構造体そのものの宣言は前節の通りです。構造体変数の宣言は以下の通りになります。 struct student seito; 「struct (構造体名) (変数名);」の形式で宣言します。 宣言時に値を設定する事を「変数の初期化」と呼びますが、構造体の場合は以下の2通りの方法があります。 struct student seito={"20000403","Yojigen Taro",1};
struct student{
char id[20];
char name[20];
int gakunen;
}seito={"20000403","Yojigen Taro",1};
中括弧を使用して構造体のメンバ(構造体を構成する変数)全てに、値を設定しています。この方法を使用できるのは初期化のときだけで、それ以降に値を設定するには別の方法を使用しなければなりません。 12.3.メンバの参照・代入構造体のメンバにアクセスするには「メンバ演算子」を使用します。これには2種類あり、構造体の実体が変数かポインタによって変わります。構造体が変数の場合は「.」(「ドット演算子」と一般的に呼ばれている)を使用します。以下は、student構造体変数seitoのnameメンバの値を出力するサンプルです。 struct student seito={"20000403","Yojigen Taro",1};
puts(seito.name);
「(構造体変数名).(メンバ名)」で、そのメンバにアクセスする事ができます。代入も同じように行います。
seito.gakunen=2;
printf("%d\n",seito.gakunen);
構造体の実体がポインタの場合は「->」(「アロー演算子」と一般的に呼ばれている)を使用します。 ポインタの扱いについては基本データ型のポインタの扱いと同じになります。 struct student seito={"20000403","Yojigen Taro",1};
struct student *sp=&seito;
puts(sp->name);
sp->gakunen=2;
printf("%d\n",sp->gakunen);
中括弧を使用しての代入は初期化以外の時に使用できませんが、構造体から構造体への代入はいつでも可能です。例えば以下の場合、構造体変数seitoの各メンバの値は構造体変数seito2にコピーされます。 struct student seito={"20000403","Yojigen Taro",1};
struct student seito2=seito;
(実習課題)以下のプログラムを作成しなさい。
12.4.自己参照構造体構造体を構成するメンバは基本データ型の変数だけでなく、構造体も可能です。以下の例では、syohin構造体にkakaku構造体の変数が使用されています。 struct kakaku{ /* 価格構造体 */
int genka; /* 原価 */
int baika; /* 売価 */
};
struct syohin{ /* 商品構造体 */
char *name; /* 商品名 */
struct kakaku syohin_kakaku; /* 商品価格 */
};
この構造体の入れ子には1つ制約があり、自分と同じ構造体の変数を含める事はできないことになっています。「構造体Aの中に構造体Aの変数があり、その中に構造体Aの変数があり...」と無限ループに陥ってしまうためです。しかし自分と同じ構造体へのポインタを含める事はできます。これは「自己参照構造体」と呼ばれ、さまざまなデータ構造を実現する事ができる、非常に強力な機能です。 ここではリスト構造を実現する事を考えます。リストとは下図のような数珠繋ぎのデータ構造で、添字でアクセスできる配列とは異なり、先頭から順にしかアクセス(順次アクセス)できません。しかし配列とは異なり、データの途中挿入や削除が容易にできるという利点を持っています。 ここでは社員の「名前」と「年齢」データをリスト構造で管理する事を考えます。構造体のメンバとなるのは、「名前」「年齢」およびリスト構造を実現するための「次のデータを指し示すポインタ」ということになります。以下のようになります。 struct employee{
char name[256];
int age;
struct employee *next;
};
この構造体を用いて下図のデータ構造を実現してみます。 struct employee employee1={"四次元太郎",27,null};
struct employee employee2={"四次元花子",25,null};
employee1.next=&employee2;
struct employee employee3={"四次元一",27,null};
employee2.next=&employee3;
employee1のnextにemployee2のアドレスを、employee2のnextにemployee3のアドレスを代入しています。 リスト構造はポインタの付け替えだけで、容易にデータの挿入・削除ができるのが特徴です。挿入の場合は下図のようにします。新しいデータ6を2と3の間に挿入する場合、2のnextが6を指すようにし、6のnextが3を指すように変えます。 ![]() 削除の場合は下図のようにします。3を削除する場合、2のnextが4を指すようにするだけで実現できます。 (実習課題)以下のプログラムを作成しなさい。
|
![]()
![]()
|