C言語の構造体(struct)入門|宣言・初期化・アクセス方法をサンプルコードで解説
構造体(structure)とは、異なるデータ型を持つ複数の変数を、ひとつの名前でまとめて扱えるようにしたデータ構造です。関連する情報(たとえば本のページ数・著者名・価格など)をひとまとめに管理できるため、C言語プログラミングにおいて非常に重要な概念となっています。
構造体の宣言と初期化
構造体を宣言する一般的な書式は以下の通りです。
struct tagname {
datatype member1;
datatype member2;
...
datatype member n;
};各要素の意味は次の通りです。
- struct … 構造体を定義するためのキーワード
- tagname … 構造体につける名前(タグ名)
- member1, member2, ... … 構造体を構成する各データ項目(メンバ)
記述例
struct book {
int pages; /* ページ数 */
char author[30]; /* 著者名 */
float price; /* 価格 */
};この例では、「book」という名前の構造体に、int型・char型・float型という異なる型のメンバが含まれています。
構造体変数の宣言方法
構造体変数を宣言するには、主に以下の3つの方法があります。
方法1:宣言時に変数を同時に定義する
struct book {
int pages;
char author[30];
float price;
} b;方法2:タグ名なしで変数を定義する
struct {
int pages;
char author[30];
float price;
} b;※この場合、同じ構造を後から再利用できない点に注意してください。
方法3:先に型を定義し、後から変数を宣言する
struct book {
int pages;
char author[30];
float price;
};
struct book b;実務では、再利用性が高い「方法3」が最も一般的に使われています。
構造体の初期化とメンバへのアクセス
- 構造体変数とメンバをつなぐには、メンバ演算子(ドット演算子「.」)を使用します。
- 初期化の方法は複数あり、目的に応じて使い分けられます。
方法1:宣言と同時に初期化する
struct book {
int pages;
char author[30];
float price;
} b = {100, "balu", 325.75};方法2:タグ名を使って別途初期化する
struct book {
int pages;
char author[30];
float price;
};
struct book b = {100, "balu", 325.75};方法3:メンバ演算子を使って個別に代入する
#include <string.h>
struct book {
int pages;
char author[30];
float price;
};
struct book b;
b.pages = 100;
strcpy(b.author, "balu"); /* 文字列配列にはstrcpyを使用 */
b.price = 325.75;※文字配列への代入は「=」では行えないため、string.h の strcpy 関数を使います。
方法4:scanf関数を使ってユーザー入力から設定する
struct book {
int pages;
char author[30];
float price;
};
struct book b;
scanf("%d", &b.pages);
scanf("%s", b.author);
scanf("%f", &b.price);これらの構造体の中身は、main関数内で次のように出力できます。
main() {
struct book b;
clrscr();
printf("ページ数・著者名・価格を入力してください\n");
scanf("%d%s%f", &b.pages, b.author, &b.price);
printf("本の詳細\n");
printf("pages = %d, author = %s, price = %f",
b.pages, b.author, b.price);
getch();
}※ scanf の文字列読み込み時のみ、配列名自体が先頭アドレスを表すため「&」は不要です。
応用例:ポインタを使った自己参照構造体
次の例は、自分自身と同じ型へのポインタ(prev / next)を持つ自己参照構造体のサンプルです。双方向リンクリストなどの基礎となる重要なテクニックです。
#include <stdio.h>
struct aaa {
struct aaa *prev;
int i;
struct aaa *next;
};
main() {
struct aaa abc, def, ghi, jkl;
int x = 100;
abc.i = 0; abc.prev = &jkl; abc.next = &def;
def.i = 1; def.prev = &abc; def.next = &ghi;
ghi.i = 2; ghi.prev = &def; ghi.next = &jkl;
jkl.i = 3; jkl.prev = &ghi; jkl.next = &abc;
x = abc.next->next->prev->next->i;
printf("%d", x);
}実行結果
2
このプログラムでは、4つの構造体変数が prev と next ポインタで循環的に連結されています。abc.next->next->prev->next->i を順にたどると、abc → def → ghi → def → ghi となり、最終的に ghi のメンバ i の値である 2 が出力されます。ポインタとドット演算子(.)、アロー演算子(->)の使い分けを理解する良い練習例といえるでしょう。
-
構造体の概念で理解するC言語のビットフィールド|定義方法と範囲の計算を徹底解説
ビットフィールドとはビットフィールドとは、変数が占めるメモリのサイズをビット単位で指定できるC言語の機能です。通常は構造体(struct)の中で定義されます。ビットフィールドの基本:1バイト=8ビット記述例struct info { int x : 2; };この例では、メンバxは2ビットを占有します。ビットフィールド使用時の注意点ビットフィールドの範囲外の値を代入することはできません(その場合の動作は保証されません)。sizeof演算子やアドレス演算子(&)をビットフィールドに適用できないため、scanf関数で値を入力することもできません。ビットフィールドに指定できるデータ型
-
C言語でfwrite()/fread()を使って構造体をファイルに読み書きする方法
C言語では、標準ライブラリのfwrite()関数とfread()関数を使うことで、構造体(struct)のデータをそのままファイルへ書き込んだり、ファイルから読み込んだりできます。これらの関数はデータをバイナリ形式で扱うため、構造体内の値を効率よく入出力できるのが大きな特徴です。 fwrite() の構文 fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 各引数の意味は次の通りです。 ptr … 書き込む要素が格納された配列へのポインタ size … 書き込む各要素のサイズ(バイト単位) nmemb … 書き込