C言語の構造体(struct)は、ばらばらの型のデータを意味のある1まとまりとして扱える仕組みです。
例えば座標のxとy、日付の年・月・日、学生の名前と成績などをひとかたまりにできます。
この記事では、構造体の基本概念と定義方法、使うメリット、よくある例を初心者向けに丁寧に解説します。
メンバーアクセスや初期化などの詳細は別記事で扱います。
構造体(struct)とは
複数の型を1つにまとめる仕組み
構造体は異なる型の値を「項目名(メンバー名)」付きで束ねるユーザー定義の型です。
C言語ではstruct
というキーワードで定義します。
例えば、2D座標(x, y)を整数で表すには次のように定義します。
ここでは定義だけを示し、使い方の詳細は後述や別記事で扱います。
// 2D座標をまとめる構造体の定義例
struct Point {
int x; // x座標(整数)
int y; // y座標(整数)
}; // ← 最後にセミコロンが必要
この定義により、「x」と「y」が常に対で扱われるので、プログラム中の意図が明確になります。
構造体のイメージ
- 「x」「y」というラベル付きの箱が横に並んだ1つの箱のようなものです。
- メモリ上では連続した領域にメンバーが配置されますが、アライメント(境界合わせ)のために隙間が入ることがあります。
どんな場面で使うか
複数の値が「まとまって意味を成す」ときに向いています。
たとえば以下のような情報です。
文章中の例として理解してみてください。
- 位置や大きさの情報(座標、長方形の幅と高さ)
- 日時や期間(年・月・日、開始時刻と終了時刻)
- エンティティの属性(学生の名前・学籍番号・GPA、商品の名前・価格・在庫数)
- 色成分(R・G・B)、ネットワークアドレス(IP・ポート) など
複数の値が一体となって「ひとつの概念」を表すときは構造体が最適です。
配列との違いと使い分け
配列は「同じ型の要素」を並べる仕組みです。
一方、構造体は「異なる型のメンバー」をまとめます。
ここが最も重要な違いです。
配列は同じ型だけ、構造体は異なる型をまとめられるという点をまず覚えておきましょう。
以下に、配列と構造体の使いどころの違いを表にまとめます。
項目 | 配列(array) | 構造体(struct) |
---|---|---|
まとめる対象 | 同じ型の要素 | 異なる型のメンバー |
典型例 | 整数のリスト、文字列(char配列) | 座標(xとy)、日付(年・月・日) |
アクセス方法 | 添字(0,1,2,…) | 名前(x, y, year, month, day) |
意味づけ | 並び順中心 | 名前中心で意味が明確 |
拡張 | 要素数を変える | メンバーを追加できる |
イメージ | 同じ箱をズラッと並べる | 異なる箱をまとめる |
使い分けの目安としては、「同じものがたくさん」なら配列、「違う属性をひとまとめ」なら構造体と考えると整理しやすいです。
さらに「構造体の配列」にすれば、同じ種類の複数のレコード(たとえば学生の一覧)も自然に表現できます。
構造体の定義の基本
structの書き方
構造体はstruct
キーワードで定義し、中にメンバーを列挙します。
// 構造体の一般的な書式
struct 型名 { // ここを「タグ名」と呼ぶことがあります
型 メンバー名1; // メンバー(フィールド)
型 メンバー名2;
// ...
}; // ← 定義の最後は必ずセミコロン
例として、本のタイトルとページ数をまとめる構造体を定義します。
// 本の情報を表す構造体
struct Book {
char title[64]; // タイトル(文字配列)
int pages; // ページ数(整数)
}; // ← セミコロンを忘れるとコンパイルエラーになります
定義の末尾のセミコロンは必須です。
初心者が最初に躓きやすいポイントなので注意しましょう。
タグ名とメンバー名
構造体のタグ名はstruct Book
の「Book」の部分です。
これは型を識別するための名前です。
メンバー名は構造体の中で定義したtitle
やpages
のことです。
struct Book {
char title[64];
int pages;
};
// 構造体変数の宣言例
struct Book b1; // これでb1という「struct Book」型の変数が作られます
タグ名はプログラム全体での型の「顔」になるので、意味の分かる名前を付けると読みやすくなります。
Cの文化では、Point
やStudent
のように先頭大文字の英単語で書かれることがよくあります。
文字列をメンバーに持つときにchar*
とchar 配列
のどちらにするかは設計次第です。
初心者のうちはchar 配列
にしておくとメモリ管理が簡単です。
定義を置く場所の目安
構造体の定義は、「その型をどこから使いたいか」で置き場所を考えます。
- 複数ファイルから使う型なら、ヘッダファイル(.h)に定義してインクルードする。
- そのファイルでだけ使うなら、ソースファイル(.c)の先頭(関数の外)に置く。
- 一時的に関数内だけで使う型は、関数の中で定義しても構いません。
ヘッダに置く例:
// point.h
#ifndef POINT_H
#define POINT_H
// どこからでも使えるようにヘッダに定義
struct Point {
int x;
int y;
};
#endif // POINT_H
関数内に限定する例(スコープはその関数内だけ):
void make_something(void) {
// この関数でしか使わない一時的な型
struct LocalConfig {
int enable;
int level;
};
struct LocalConfig cfg;
cfg.enable = 1;
cfg.level = 3;
// ここでcfgを使う処理を書く…
}
ヘッダは宣言、ソースは実装という役割分担を意識すると見通しが良くなります。
構造体を使うメリット
読みやすさと保守性の向上
複数の値がまとまることで、「何を渡して何を返しているのか」が明確になります。
xとyをバラバラに扱うより、struct Point
を1つ扱うほうが意図が伝わりやすいです。
将来、メンバーが増えたときも呼び出し側の修正が少なくて済みます。
意味のある型で表現できる
構造体は、プログラムのドメイン知識(現実世界の概念)をそのまま型に刻み込む手段です。
int x, int y
よりstruct Point
のほうが「座標」であることが明確になります。
型名がプログラムのドキュメントとして機能するので、チーム開発でも理解が揃いやすくなります。
拡張しやすい設計になる
構造体にメンバーを追加すれば、関連する情報を自然に拡張できます。
たとえば学生にメールアドレスを追加したくなった場合、構造体に1行加えるだけで表現できます。
// 拡張前
struct Student {
char name[32];
int id;
double gpa;
};
// 拡張後(メールアドレスを追加)
struct Student {
char name[32];
int id;
double gpa;
char email[64]; // 新しいメンバー
};
意味がまとまっているからこそ、拡張も自然にまとまるのが構造体の利点です。
よくある構造体の例
ここからは、初心者が最初に触れることの多い構造体の具体例を示します。
いずれも小さなプログラムで作成と出力を確認します。
メンバーへの代入や表示には.
(ドット)を使いますが、アクセス方法の詳しい解説や初期化の書き方は別記事で扱います。
2D座標
2D座標(x, y)をまとめる構造体の例です。
#include <stdio.h> // printfを使うため
// 2D座標を表す構造体の定義
struct Point {
int x; // x座標
int y; // y座標
};
int main(void) {
struct Point p; // 構造体変数pを宣言
p.x = 10; // メンバーへの代入
p.y = 20;
printf("Point: (%d, %d)\n", p.x, p.y); // 表示
return 0;
}
Point: (10, 20)
「x」「y」が常にセットで扱えるので、関数に渡すときも受け取るときも混同を防げます。
日付
年・月・日を1つにまとめた例です。
整数の並びではなくyear
、month
、day
と名前が付くことで意味が明確になります。
#include <stdio.h>
// 日付を表す構造体
struct Date {
int year; // 年
int month; // 月(1〜12)
int day; // 日(1〜31)
};
int main(void) {
struct Date today;
today.year = 2025;
today.month = 10;
today.day = 11;
printf("%04d-%02d-%02d\n", today.year, today.month, today.day);
return 0;
}
2025-10-11
どの値が何を表すかが自明になるため、ミスを減らせます。
学生情報
名前や学籍番号、GPAなどをひとまとめにした例です。
文字列はchar 配列
で持たせ、snprintf
で代入しています。
#include <stdio.h>
#include <string.h>
// 学生情報を表す構造体
struct Student {
char name[32]; // 学生の名前(終端文字'#include <stdio.h>
#include <string.h>
// 学生情報を表す構造体
struct Student {
char name[32]; // 学生の名前(終端文字'\0'を含めるための領域)
int id; // 学籍番号
double gpa; // GPA(成績指標)
};
int main(void) {
struct Student s;
// 文字配列への文字列代入。安全のためsnprintfを使用
snprintf(s.name, sizeof s.name, "%s", "Suzuki Taro");
s.id = 12345;
s.gpa = 3.8;
printf("name=%s, id=%d, gpa=%.1f\n", s.name, s.id, s.gpa);
return 0;
}
'を含めるための領域)
int id; // 学籍番号
double gpa; // GPA(成績指標)
};
int main(void) {
struct Student s;
// 文字配列への文字列代入。安全のためsnprintfを使用
snprintf(s.name, sizeof s.name, "%s", "Suzuki Taro");
s.id = 12345;
s.gpa = 3.8;
printf("name=%s, id=%d, gpa=%.1f\n", s.name, s.id, s.gpa);
return 0;
}
name=Suzuki Taro, id=12345, gpa=3.8
「学生」という意味を型として表現でき、後からメールアドレスや所属などを追加しても自然に拡張できます。
まとめ
構造体(struct)は、複数の異なる型を意味のある1つの型として定義できる仕組みです。
配列が同一型を並べるのに対し、構造体は異なる型を名前付きでまとめられるため、コードの意図を正確に伝えられます。
読みやすさや保守性が向上し、拡張にも強い設計になります。
まずは「座標」「日付」「学生情報」など身近な概念から練習し、構造体の定義に慣れてください。
メンバーへのアクセス方法、初期化、ポインタ、関数への受け渡し、typedefなどの詳細は別の記事でじっくり解説します。