C言語のネストされた構造体(入れ子構造体)とは?基本からアクセス方法まで解説
構造体内の構造体(ネストされた構造体)とは?
C言語では、ある構造体(structure)の中に別の構造体を含めることができます。このような「構造体の中にさらに構造体が入っている」形式を、ネストされた構造体(入れ子構造体)と呼びます。
ネスト構造を活用すると、関連性の高いデータをひとつのグループとしてまとめられるため、データの整理がしやすくなり、プログラムの可読性や保守性も向上します。
基本となる構造体の例
まず、従業員情報を扱うシンプルな構造体を見てみましょう。
struct emp{
int eno;
char ename[30];
float sal;
float da;
float hra;
float ea;
}e;
この構造体には、従業員番号(eno)、氏名(ename)、基本給与(sal)に加えて、da(手当)、hra(家賃手当)、ea(その他手当)といった複数の手当項目が並んでいます。これらの手当関連の項目は、すべて「allowance(手当)」というカテゴリに分類できます。
メンバーをサブ構造体としてグループ化する
そこで、手当に関連する項目をひとつのサブ構造体にまとめると、次のように宣言できます。
struct emp{
int eno;
char ename[30];
float sal;
struct allowance{
float da;
float hra;
float ea;
}a;
}e;
このように記述することで、データ構造が論理的に整理され、コードから設計意図が読み取りやすくなります。
ネストされた構造体のメンバーへのアクセス方法
ネストされた構造体の最も内側にあるメンバーにアクセスするには、ドット演算子(.)を使い、一番外側の構造体変数から順に内側へと変数名をつなげて指定します。
たとえば、上記の例で手当「da」の値にアクセスする場合は、次のように書きます。
e.a.da = 5000.50;
ネストされた構造体のサンプルプログラム
次のプログラムは、ネストされた構造体(構造体内の構造体)の使い方を示したものです。外側の「Person(人物)」構造体の中に、内側の「Address(住所)」構造体を定義しています。
#include <stdio.h>
// 外側の構造体と内側の構造体を宣言
struct Person{ // メイン構造体
char Name[500];
int Age;
char Gender;
char temp; // バッファクリア用
struct Address{ // ネストされた構造体
char Apartment[500];
char Street[500];
char City[100];
char State[100];
int Zipcode;
}a[20]; // ネストされた構造体変数
}p[20]; // メイン構造体変数
void main(){
int i; // forループ用の変数
// ユーザー入力の読み込み(2人分のデータを受け付ける)
for(i=1;i<3;i++){
printf("Enter the Name of person %d : ",i);
gets(p[i].Name);
printf("Enter the Age of person %d : ",i);
scanf("%d",&p[i].Age);
scanf("%c",&p[i].temp); // バッファのクリア
printf("Enter the Gender of person %d : ",i);
scanf("%c",&p[i].Gender);
scanf("%c",&p[i].temp); // バッファのクリア
printf("Enter the City of person %d : ",i);
gets(p[i].a[i].City);
printf("Enter the State of person %d : ",i);
gets(p[i].a[i].State);
printf("Enter the Zip Code of person %d : ",i);
scanf("%d",&p[i].a[i].Zipcode);
scanf("%c",&p[i].temp); // バッファのクリア
}
// 結果の出力
for(i=1;i<3;i++){
printf("The Name of person %d is : %s\n",i,p[i].Name);
printf("The Age of person %d is : %d\n",i,p[i].Age);
printf("The Gender of person %d is : %c\n",i,p[i].Gender);
printf("The City of person %d is : %s\n",i,p[i].a[i].City);
printf("The State of person %d is : %s\n",i,p[i].a[i].State);
printf("The Zip code of person %d is : %d\n",i,p[i].a[i].Zipcode);
}
}
実行結果の出力例
Enter the Name of person 1 : Enter the Age of person 1 : Enter the Gender of person 1 : Enter the City of person 1 : Enter the State of person 1 : Enter the Zip Code of person 1 : Enter the Name of person 2 : Enter the Age of person 2 : Enter the Gender of person 2 : Enter the City of person 2 : Enter the State of person 2 : Enter the Zip Code of person 2 : The Name of person 1 is : The Age of person 1 is : 0 The Gender of person 1 is : The City of person 1 is : The State of person 1 is : The Zip code of person 1 is : 0 The Name of person 2 is : The Age of person 2 is : 0 The Gender of person 2 is : The City of person 2 is : The State of person 2 is : The Zip code of person 2 is : 0
補足:現代のC言語開発での注意点
なお、上記のコードは学習用の古典的な書き方です。実際の開発では、以下の点に注意しましょう。
- gets() の使用は避ける: gets() はバッファオーバーフローの危険があるため、現在のC標準規格では廃止されています。代わりに fgets() を使用してください。
- main 関数の戻り値: 標準規格では main 関数は int 型を返すことが推奨されています(int main(void))。
- 構造体定義の分離: 内側の構造体を外側とは別に定義し、メンバーとしてその型の変数を持たせる書き方も広く使われています。
まとめ
ネストされた構造体を使うと、関連するデータを階層的にグループ化でき、プログラムの構造が明確になります。メンバーへのアクセスは、ドット演算子を外側から内側へ順につなげるだけで簡単に行えます。住所や日付など、複数の要素から成るデータを扱う際には、ぜひ活用してみてください。
-
C言語のシフト演算とは?左シフト・右シフト・補数の基本をわかりやすく解説
問題 C言語を使用して、ある数値に対する左シフト・右シフト・補数(ビット反転)を求める簡単なプログラムを作成するには、どのようにすればよいのでしょうか。 解決方法 左シフト(<<) 変数の値を1ビットだけ左へシフトすると、その値は2倍になります。「a × 2」を計算したのと同じ結果です。 例:a = 10 の場合、a << 1 = 20 右シフト(>>) 変数の値を1ビットだけ右へシフトすると、その値は元の半分になります。「a ÷ 2」の整数除算と同じ結果です。 例:a = 10 の場合、a >> 1 = 5 サンプルプログラム 以下は、シ
-
C言語の基本データ型を徹底解説!int・char・floatの種類とサイズ一覧
C言語の基本データ型とは? C言語のコンパイラがサポートする基本データ型は、大きく分けて次の4つです。 整数型(Integer) 文字型(Character) 浮動小数点型(Floating-point) 倍精度浮動小数点型(Double precision floating point) プログラムで扱う値の種類(整数・文字・実数など)に応じて適切な型を選ぶことは、正確で効率的なコードを書くための第一歩です。なお、各データ型のサイズや表現できる値の範囲は、使用するコンパイラや実行環境によって異なる場合がある点に注意してください。 整数型(Integral Data Type) 整数型は