C 構造体

C の配列は、同じ型のデータ項目を格納できる変数を定義できます。構造体は C プログラミングにおけるもう1つのユーザー定義のデータ型であり、異なる型のデータ項目を格納することができます。

構造体内のデータメンバーは、基本データ型(int、float、char など)の場合もあれば、他の構造体型やポインタ型などの場合もあります。

構造体はレコードを表すために使用されます。図書館の本の状況を追跡したい場合、各書籍について次の属性を追跡する必要があるかもしれません:

  • Title
  • Author
  • Subject
  • Book ID

構造体の定義

構造体の定義はキーワードstructと構造体名から構成され、構造体名は必要に応じて自由に定義できます。

struct 文は複数のメンバーを含む新しいデータ型を定義します。struct 文の形式は次のとおりです:

struct tag {
    member-list
    member-list
    member-list  
    ...
} variable-list ;

tagは構造体タグです。

member-listは標準の変数定義であり、例えばint i;またはfloat f;、その他の有効な変数定義です。

variable-list構造変数は構造体の末尾、最後のセミコロンの前に定義され、1つ以上の構造変数を指定できます。以下は Book 構造体を宣言する方法です:

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;  

一般的な場合、tag、member-list、variable-listこの3つの部分のうち少なくとも2つが必要です。以下に例を示します:

//この宣言は、3つのメンバーを持つ構造体を宣言しています。それぞれ整数型のa、文字型のb、倍精度浮動小数点型のcです。
//同時に構造体変数s1も宣言しています
//この構造体にはタグが指定されていません
struct
{
    int a;
    char b;
    double c;
} s1;

//この宣言は、3つのメンバーを持つ構造体を宣言しています。それぞれ整数型のa、文字型のb、倍精度浮動小数点型のcです。
//構造体のタグはSIMPLEという名前で、変数は宣言されていません
struct SIMPLE
{
    int a;
    char b;
    double c;
};
//SIMPLEタグの構造体を使用して、変数t1、t2、t3を別途宣言しています
struct SIMPLE t1, t2[20], *t3;

//typedefを使用して新しい型を作成することもできます
typedef struct
{
    int a;
    char b;
    double c;
} Simple2;
//これでSimple2を型として新しい構造体変数を宣言できます
Simple2 u1, u2[20], *u3;

上記の宣言では、1番目と2番目の宣言は、メンバーリストが同じであっても、コンパイラによって完全に異なる型として扱われます。t3=&s1 とすることは非合法です。

構造体のメンバーは他の構造体を含むことができ、また自分自身の構造体型を指すポインタを含むこともできます。通常、このようなポインタは、リンクリストやツリーなどのより高度なデータ構造を実装するために使用されます。

//この構造体の宣言には他の構造体が含まれています
struct COMPLEX
{
    char string[100];
    struct SIMPLE a;
};

//この構造体の宣言には自分自身の型を指すポインタが含まれています
struct NODE
{
    char string[100];
    struct NODE *next_node;
};

2つの構造体が互いに含み合う場合、一方の構造体を不完全宣言する必要があります。次のようになります:

struct B;    //構造体Bの不完全宣言を行います

//構造体Aには構造体Bを指すポインタが含まれます
struct A
{
    struct B *partner;
    //other members;
};

//構造体Bには構造体Aを指すポインタが含まれます。Aの宣言後、Bも続けて宣言されます
struct B
{
    struct A *partner;
    //other members;
};

構造体変数の初期化

他の型の変数と同様に、構造体変数は定義時に初期値を指定できます。

実例

#include <stdio.h>

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book = {"C 言語", "サンプル", "プログラミング言語", 123456};

int main()
{
    printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n", book.title, book.author, book.subject, book.book_id);
}

実行出力結果は次のとおりです:

title : C 语言
author: サンプル
subject: 编程语言
book_id: 123456

構造体メンバーへのアクセス

構造体のメンバーにアクセスするには、メンバーアクセス演算子(.)を使用します。メンバーアクセス演算子は、構造体変数名とアクセスしたい構造体メンバーとの間にあるピリオドです。structキーワードを使用して構造体型の変数を定義できます。次の例は構造体の使い方を示しています:

実例

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( )
{
   struct Books Book1;        /* Book1 を宣言、型は Books */
   struct Books Book2;        /* Book2 を宣言、型は Books */
 
   /* Book1 の詳細 */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali");
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* Book2 の詳細 */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* Book1 の情報を出力 */
   printf( "Book 1 title : %s\n", Book1.title);
   printf( "Book 1 author : %s\n", Book1.author);
   printf( "Book 1 subject : %s\n", Book1.subject);
   printf( "Book 1 book_id : %d\n", Book1.book_id);

   /* Book2 の情報を出力 */
   printf( "Book 2 title : %s\n", Book2.title);
   printf( "Book 2 author : %s\n", Book2.author);
   printf( "Book 2 subject : %s\n", Book2.subject);
   printf( "Book 2 book_id : %d\n", Book2.book_id);

   return 0;
}

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

Book 1 title : C Programming
Book 1 author : Nuha Ali
Book 1 subject : C Programming Tutorial
Book 1 book_id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Zara Ali
Book 2 subject : Telecom Billing Tutorial
Book 2 book_id : 6495700

関数パラメータとしての構造体

構造体を関数パラメータとして渡すことができます。渡し方は他の型の変数やポインタと同様です。上記の例の方法で構造体変数にアクセスできます:

実例

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};

/* 関数宣言 */
void printBook( struct Books book );
int main( )
{
   struct Books Book1;        /* Book1 を宣言、型は Books */
   struct Books Book2;        /* Book2 を宣言、型は Books */
 
   /* Book1 の詳細 */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali");
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* Book2 の詳細 */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* Book1 の情報を出力 */
   printBook( Book1 );

   /* Book2 の情報を出力 */
   printBook( Book2 );

   return 0;
}
void printBook( struct Books book )
{
   printf( "Book title : %s\n", book.title);
   printf( "Book author : %s\n", book.author);
   printf( "Book subject : %s\n", book.subject);
   printf( "Book book_id : %d\n", book.book_id);
}

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700

構造体を指すポインタ

構造体を指すポインタを定義できます。方法は他の型の変数を指すポインタの定義と似ています。次のようになります:

struct Books *struct_pointer;

ここで、上記で定義したポインタ変数に構造体変数のアドレスを格納できます。構造体変数のアドレスを調べるには、& 演算子を構造体名の前に置きます。次のようになります:

struct_pointer = &Book1;

構造体を指すポインタを使用して構造体のメンバーにアクセスするには、-> 演算子を使用する必要があります。次のようになります:

struct_pointer->title;

構造体ポインタを使用して上記の例を書き直してみましょう。これにより、構造体ポインタの概念を理解するのに役立ちます:

実例

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};

/* 関数宣言 */
void printBook( struct Books *book );
int main( )
{
   struct Books Book1;        /* Book1 を宣言、型は Books */
   struct Books Book2;        /* Book2 を宣言、型は Books */
 
   /* Book1 の詳細 */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali");
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* Book2 の詳細 */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* Book1 のアドレスを渡して Book1 の情報を出力 */
   printBook( &Book1 );

   /* Book2 のアドレスを渡して Book2 の情報を出力 */
   printBook( &Book2 );

   return 0;
}
void printBook( struct Books *book )
{
   printf( "Book title : %s\n", book->title);
   printf( "Book author : %s\n", book->author);
   printf( "Book subject : %s\n", book->subject);
   printf( "Book book_id : %d\n", book->book_id);
}

上記のコードがコンパイルおよび実行されると、次の結果が生成されます:

Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700

構造体サイズの計算

C 言語では、sizeof演算子を使用して構造体のサイズを計算できます。sizeof戻り値は、指定された型または変数のバイトサイズです。

構造体の場合、sizeof構造体の総バイト数が返されます。これにはすべてのメンバー変数のサイズと、場合によってはパディングバイトが含まれます。

次の例は、構造体のサイズを計算する方法を示しています:

実例

#include <stdio.h>

struct Person {
    char name[20];
    int age;
    float height;
};

int main() {
    struct Person person;
    printf("構造体 Person のサイズ: %zu バイト\n", sizeof(person));
    return 0;
}

上記の例では、Personという名前の構造体を定義しました。この構造体には、文字配列name、整数age、および浮動小数点数が含まれています。height。

にmain関数内で、Person型の変数personを宣言し、次にsizeof演算子を使用してperson構造体のサイズを取得しました。

最後に、printf関数を使用して構造体のサイズを出力しました。出力結果は次のとおりです:

结构体 Person 大小为: 28 字节

注意構造体のサイズは、コンパイラの最適化やアライメント規則の影響を受ける可能性があります。コンパイラは、メモリアクセス効率を向上させるために、構造体のメンバー変数を整列するための追加のパディングバイトを構造体に挿入することがあります。そのため、構造体の実際のサイズはメンバー変数のサイズの合計よりも大きくなる場合があります。構造体のメモリレイアウトとアライメント方法を正確に把握する必要がある場合は、offsetofマクロや__attribute__((packed))属性などを使用して、構造体のサイズとアライメント方式をさらに制御および照会できます。

その他の拡張