広告スペース

第26回 構造体(struct)

C言語のstruct(構造体)の定義・メンバアクセス・配列との組合せを解説。

構造体とは

これまでは int, double, char などの変数をバラバラに宣言していました。しかし実際のデータは「名前・年齢・身長」のように複数の情報がセットになっていることが多いです。
構造体(struct) は、複数の異なる型の変数をひとまとめにして新しい型を作る仕組みです。
バラバラだと...
char name[20];
int age;
double height;
人が増えたら name1, name2... と変数が爆発
構造体なら
struct Person {
  char name[20];
  int age;
  double height;
};
1つの Person にすべてまとまる

構造体の定義と使い方

構造体は 2ステップ で使います。① 型を定義(設計図を作る) → ② 変数を宣言(実体を作る)。
// ① 構造体の型を定義 (設計図)
struct Student {
  char name[20];
  int score;
};

// ② 変数を宣言して使う
struct Student s1;
strcpy(s1.name, "田中");  // ドット(.)でアクセス
s1.score = 85;

// 宣言と同時に初期化も可能
struct Student s2 = {"佐藤", 92};
メンバへのアクセスは「ドット演算子(.)」を使います。s1.score は「s1 の中の score」という意味。

構造体のメモリ配置

構造体のメンバはメモリ上に宣言した順番で連続して並びます
💾 struct Student s1; のメモリ配置
name[20] が 20 バイト、score が 4 バイト → 合計 24 バイト以上を 1 人分で使います(パディングが入る場合もあります)。

構造体の配列

構造体を配列にすると、同じ形式のデータを何件でもまとめて管理できます。これが構造体の真骨頂です。
struct Student class[3] = {
  {"田中", 85},
  {"佐藤", 92},
  {"鈴木", 78}
};

// 全員の成績を表示
for(int i = 0; i < 3; i++){
  printf("%s: %d点\n", class[i].name, class[i].score);
}
配列のインデックス + ドット演算子class[i].score のようにアクセスします。「i番目の学生の成績」が直感的に読めますね。

構造体を関数に渡す

構造体は関数に値渡し(コピー)もできますが、大きな構造体ではコピーのコストが大きいため、ポインタ渡しが一般的です。
// 値渡し (コピーされる)
void printStudent(struct Student s){
  printf("%s: %d点\n", s.name, s.score);
}

// ポインタ渡し (元データを参照)
void addBonus(struct Student *sp, int bonus){
  sp->score += bonus; // (*sp).score と同じ
}

addBonus(&s1, 5); // s1.scoreが5点加算される
アロー演算子(->) はポインタ経由でメンバにアクセスする専用の書き方です。sp->score(*sp).score と同じ意味。

typedef ― 型に別名をつける

typedef を使うと、型に分かりやすい別名をつけられます。特に構造体で頻繁に使います。

基本の使い方

// unsigned int に別名をつける
typedef unsigned int uint;
uint score = 100;  // unsigned int score = 100; と同じ

構造体と typedef(最重要)

// typedefなし → 毎回 struct をつける
struct Point { int x, y; };
struct Point p1 = {3, 7};  // struct が必要

// typedefあり → struct を省略できる
typedef struct { int x, y; } Point;
Point p1 = {3, 7};           // すっきり書ける
実務では typedef 付きの構造体が主流です。 コードが短くなり、可読性が上がります。

列挙型 (enum) ― 名前付き定数のグループ

enum を使うと、関連する整数定数に名前をつけてグループ化できます。マジックナンバーの排除に役立ちます。
enum Color { RED, GREEN, BLUE };  // RED=0, GREEN=1, BLUE=2

enum Color c = GREEN;
printf("%d\n", c);  // 1

値を指定する

enum Month {
    JAN = 1, FEB, MAR, APR, MAY, JUN,
    JUL, AUG, SEP, OCT, NOV, DEC
}; // FEB=2, MAR=3, ... DEC=12(自動的に+1)

enum + switch の組み合わせ

enum Direction { UP, DOWN, LEFT, RIGHT };

enum Direction dir = UP;
switch (dir) {
    case UP:    printf("上\n");  break;
    case DOWN:  printf("下\n");  break;
    case LEFT:  printf("左\n");  break;
    case RIGHT: printf("右\n");  break;
}
#define との違い: #define RED 0 でも同じことはできますが、enum は型として扱えるため、コンパイラが型チェックを助けてくれます。
方法型チェックスコープデバッガ表示
#define RED 0なしファイル全体数値のみ
enum { RED }あり制御可能名前で表示

自分で書いてみよう ― 構造体

3人の学生データを構造体配列に入れ、平均点を計算するプログラムです。
struct.c
出力
「実行」を押してください...
広告スペース

関連する講座

発展編
第25回 ポインタの基礎
C言語のポインタをメモリ可視化で理解。アドレスと間接参照を図解。
繰り返し・配列・文字列
第18回 配列
C言語の配列の宣言・初期化・アクセス方法。メモリ配置も図解。
発展編
第27回 ファイル入出力
C言語のファイル操作。fopen, fprintf, fscanf, fcloseの使い方を解説。
← 前の講座
第25回 ポインタの基礎
次の講座 →
第27回 ファイル入出力

確認クイズ

この講座の理解度をチェックしましょう!

Q1. 構造体のメンバにアクセスする演算子は?

->(アロー)のみ
.(ドット)のみ
. と -> の両方(場合による)

変数から直接アクセスする場合は .(ドット)、ポインタ経由の場合は ->(アロー)を使います。

Q2. 構造体を関数に渡すとどうなる?

参照渡しされる
値のコピーが渡される
エラーになる

C言語では構造体は値渡し(コピー)されます。大きな構造体はポインタで渡す方が効率的です。

Q3. typedef struct の役割は?

構造体を動的に確保する
構造体型に別名を付ける
構造体のサイズを変更する

typedef は型に別名を付ける機能で、struct Student s; を Student s; と短く書けるようになります。

この記事をシェア
X(Twitter)でシェア Facebookでシェア LINEで送る はてブ

この講座の理解を深めるおすすめ書籍

サイトで動きを理解し、書籍で演習量を補うと効果的です

📘
苦しんで覚えるC言語
MMGames 著
初心者向けの定番入門書。丁寧な解説で基礎を固められます。
Amazonで見る
📗
新・明解C言語 入門編
柴田望洋 著
図解が豊富で、演習問題も充実。大学の教科書としても採用多数。
Amazonで見る
📙
プログラミング言語C 第2版
B.W.カーニハン, D.M.リッチー 著
通称K&R。C言語の原典。基礎を終えた後のステップアップに最適。
Amazonで見る

※ 上記リンクはアフィリエイトリンクです。購入によりサイト運営を支援いただけます。