【2026年7月最新】C言語の構造体(struct)完全ガイド|typedef・ポインタ・アロー演算子・配列・関数引数まで徹底解説

【2026年7月最新】C言語の構造体(struct)完全ガイド|typedef・ポインタ・アロー演算子・配列・関数引数まで徹底解説

「構造体って何が便利なの?」「ポインタとアロー演算子の違いが分からない」「関数に構造体を渡したら値が変わらなかった」——C言語を学ぶ際によく発生するつまずきポイントです。

C言語のstruct(構造体)は、複数の異なる型のデータを1つのまとまりとして扱う仕組みです。例えば「名前(文字列)」「年齢(整数)」「身長(小数)」という異なる型のデータを「人物」という1つの構造体で管理できます。実際のプログラム開発では、配列だけでは対応できない複雑なデータを扱う場面で必ず使います。

この記事では、C言語の構造体についてstruct宣言・typedef・ドット演算子・ポインタ・アロー演算子・配列・関数への渡し方・コピーと比較まで、コードサンプル付きで体系的に解説します。

代表菅澤 代表菅澤
構造体はC言語において「オブジェクト指向の走り」とも言える機能です。現代のC言語で書かれるシステムプログラム・組み込み・ゲームエンジンのほぼすべてに構造体が使われています。ポインタと組み合わせたアロー演算子は特に重要で、これを理解すると複雑なデータ構造の実装が一気に楽になります。
AI鬼管理山崎 AI鬼管理山崎
この記事では実際に動くコードを多数掲載しています。特に「値渡しとポインタ渡しの違い」は、C言語学習の最大の難関のひとつです。コードを見ながら「なぜポインタ渡しが必要なのか」を具体的に理解できるよう解説しています。
✔️構造体(struct)の基本概念と配列との違いが分かる
✔️typedefを使った構造体の宣言方法が分かる
✔️ドット演算子(.)でメンバにアクセスする方法が分かる
✔️ポインタとアロー演算子(->)の使い方が理解できる
✔️構造体の配列で複数データを管理する方法が分かる
✔️値渡しとポインタ渡しの違いと適切な使い分けが分かる
✔️Claude CodeでC言語の構造体コードを自動生成する方法が分かる
Claude Code 完全解説セミナー|経営者・会社役員専用 1on1 60分 無料Claude Codeを経営に活かしたい方へ — AI鬼管理
📌 この記事の結論
【2026年7月最新】C言語の構造体(struct)完全ガイド|typedef・ポインタ・アロー演算子・配列・関数引数まで徹底解説
C言語の構造体(struct)を完全解説。typedef/ドット演算子/ポインタ/アロー演算子/配列/関数引数/コピー比較まで、コード例付きで非エンジニア向けに解説。Claude Codeでの自動コード生成方法も紹介。

01 構造体とは――異なる型のデータをひとまとめにする仕組み 配列との違いと構造体が必要になる場面を理解する

C言語の構造体(structure)は、異なる型のデータを1つのまとまりとして管理する仕組みです。配列が「同じ型のデータを複数格納できる」のに対し、構造体は「異なる型のデータを1つのグループにできる」点が大きな違いです。

📚 用語解説

構造体(struct):C言語でint型・char型・float型など異なる型のデータを1つのまとまり(型)として定義する機能。例えば「名前(char)・年齢(int)・身長(float)」を持つ「Person型」を作れます。structキーワードで宣言し、メンバと呼ばれる各フィールドに個別にアクセスします。

比較項目配列(array)構造体(struct)
格納する型全要素が同じ型異なる型が混在可能
要素の識別インデックス(数字)でアクセスメンバ名(名前)でアクセス
主な用途同じ種類のデータを大量に属性の異なるひとまとまりのデータ
int scores[5] (5人分の点数)Person型(名前・年齢・点数)

具体的な例を見てみましょう。学生データを管理するプログラムを作る場合を考えます。

/* 配列だけで管理しようとした場合(型が混在できない) */ char names[3][20]; // 名前(文字列) int ages[3]; // 年齢(整数) float scores[3]; // 点数(小数) /* → 3種類の配列をバラバラに管理しなければならない */ /* 構造体で管理した場合(1つの型でまとめられる) */ struct Student { char name[20]; int age; float score; }; struct Student students[3]; // 3人分のデータを1つの型で
💡構造体が必要になる典型的な場面

①複数の属性を持つデータを管理したい(社員・商品・ゲームキャラクター)②データをまとめて関数に渡したい③リンクリスト・ツリーなどのデータ構造を実装したい——これらの場面が構造体の出番です。C言語ではclassが使えないため、「クラスの代わり」として構造体を活用します。

02 struct宣言とtypedefの使い方 2つの宣言スタイルと使い分けのポイント

構造体を使うには、まずstructキーワードで構造体型を定義(宣言)します。C言語では2つのスタイルがあります。struct名前 {...}形式と、typedefを使ったエイリアス形式です。

2-1. 基本のstruct宣言

/* struct宣言の基本形式 */ struct Person { char name[50]; /* 名前(最大49文字)*/ int age; /* 年齢 */ float height; /* 身長(cm)*/ }; int main() { /* 変数宣言には「struct Person」と書く必要がある */ struct Person p1; struct Person p2; return 0; }

2-2. typedefを使ったスタイル(推奨)

typedefを使うと、struct Personを単にPersonと書けるようになります。コードが読みやすくなるため、実務ではtypedefを使ったスタイルが一般的です。

/* typedefで型名のエイリアスを定義 */ typedef struct { char name[50]; int age; float height; } Person; /* ← 末尾に型名を書く */ int main() { /* "struct"を省略して宣言できる */ Person p1; Person p2; return 0; }

📚 用語解説

typedef(タイプデフ):既存の型に別名(エイリアス)を付けるC言語のキーワード。「typedef 既存の型名 新しい型名;」の形で使います。structと組み合わせると「struct Person」を「Person」だけで書けるようになります。コードの可読性向上とタイピング量削減に効果的です。

スタイル変数宣言方法特徴推奨場面
struct宣言struct Person p;struct名が明示的に分かるC89以前・小規模コード
typedef使用Person p;短く読みやすいC99以降・実務開発(推奨)
typedef+struct名Person p;(struct Personも使用可)両方使える柔軟性再帰的な構造体が必要な時
⚠️typedefと構造体名を同じにしてはいけない場面

再帰的な構造体(自分自身を指すポインタを持つリンクリストなど)では、typedef定義が完了する前に型名を使う必要があります。その場合は「typedef struct Node { struct Node *next; } Node;」のようにtag名(struct Node)とtypedef名(Node)の両方を定義します。

03 メンバへのアクセス(ドット演算子)と初期化 構造体変数のメンバを読み書きする方法

構造体を宣言した後は、ドット演算子(.)を使ってメンバにアクセスします。「構造体変数名.メンバ名」の形式で値を読み書きできます。

#include <stdio.h> #include <string.h> typedef struct { char name[50]; int age; float height; } Person; int main() { Person p; /* ドット演算子でメンバに値を代入 */ strcpy(p.name, "菅澤孝平"); p.age = 24; p.height = 175.5f; /* ドット演算子でメンバを読み取る */ printf("名前: %s\n", p.name); printf("年齢: %d\n", p.age); printf("身長: %.1f cm\n", p.height); return 0; }

3-2. 宣言時に一括初期化する

/* 宣言と同時に初期化(C言語の指示子初期化:C99以降) */ Person p1 = { .name = "山崎", .age = 30, .height = 168.0f }; /* 旧来の順序指定初期化(C89) */ Person p2 = {"田中", 25, 172.0f}; /* ゼロ初期化(全メンバを0/NULL/0.0に) */ Person p3 = {0}; /* または memset で初期化 */ memset(&p3, 0, sizeof(Person));
💡文字列メンバへの代入はstrcpyを使う

char配列メンバに文字列を代入するとき、「p.name = "山田";」のように直接代入はできません。「strcpy(p.name, "山田");」を使います。宣言時の初期化(= {...})では直接文字列リテラルを指定できますが、後からの代入はstrcpy(またはsnprintf)が必要です。

Claude Code 完全解説セミナー|経営者・会社役員専用 1on1 60分 無料Claude Codeを経営に活かしたい方へ — AI鬼管理

04 構造体ポインタとアロー演算子(->) ポインタ経由で構造体メンバにアクセスする方法

C言語の学習でつまずきやすいのが「構造体ポインタ」と「アロー演算子(->)」の組み合わせです。構造体へのポインタを使うとき、ドット演算子(.)の代わりにアロー演算子(->を使います。

📚 用語解説

アロー演算子(->):構造体へのポインタからメンバにアクセスするための演算子。「(*ptr).member」と書く代わりに「ptr->member」と書ける省略記法です。マイナス記号とより大なり記号の組み合わせで「矢印(->)」に見えることからアロー演算子と呼ばれます。

#include <stdio.h> #include <string.h> typedef struct { char name[50]; int age; } Person; int main() { Person p = {"山崎", 30}; Person *ptr = &p; /* pのアドレスをポインタに格納 */ /* 方法1: (*ptr).member(デリファレンス+ドット) */ printf("%s\n", (*ptr).name); /* 方法2: ptr->member(アロー演算子)← こちらが一般的 */ printf("%s\n", ptr->name); printf("%d\n", ptr->age); /* アロー演算子で値を変更する */ ptr->age = 31; printf("更新後: %d\n", p.age); /* p.ageも31に変わる */ return 0; }
変数 p
Person型のデータが
メモリに確保
ポインタ ptr
&pでpのアドレスを
格納
ptr->name
pのnameメンバに
直接アクセス
値の読み書き
元の変数pも
同時に変化

4-2. mallocで動的に構造体を生成する場合

#include <stdlib.h>

📚 用語解説

sizeof演算子:変数や型のメモリサイズ(バイト数)を返すC言語の演算子。「sizeof(Person)」とすると構造体Personのバイトサイズが得られます。mallocで動的メモリを確保するときや、構造体のサイズを計算するときに必ず使います。int型は通常4バイト、double型は8バイトなど、型によってサイズが異なるためsizeofを使うとポータブルなコードになります。

int main() { /* ヒープ上に構造体を動的確保 */ Person *ptr = (Person *)malloc(sizeof(Person)); if (ptr == NULL) { fprintf(stderr, "メモリ確保失敗\n"); return 1; } /* アロー演算子でメンバに代入 */ strcpy(ptr->name, "動的確保"); ptr->age = 20; printf("%s: %d歳\n", ptr->name, ptr->age); free(ptr); /* 使い終わったら必ず解放 */ return 0; }
⚠️mallcで確保した構造体はfree()を忘れずに

mallocで動的確保した構造体は、使い終わったら必ずfree()でメモリを解放してください。解放しないとメモリリーク(使用済みメモリが解放されずに残り続ける問題)が発生し、長時間動作するプログラムでメモリ不足の原因になります。

05 構造体の配列――複数データをまとめて管理する 複数の人物・商品データを構造体配列で効率的に扱う

構造体変数を配列として宣言することで、同じ型の構造体を複数まとめて管理できます。「10名分の社員データ」「100個の商品データ」など、同じ属性を持つ複数のデータを扱うときに使います。

#include <stdio.h> #include <string.h> typedef struct { char name[50]; int age; float score; } Student; int main() { /* 構造体の配列を宣言(3名分) */ Student students[3] = { {"菅澤", 24, 95.5f}, {"山崎", 30, 88.0f}, {"田中", 22, 72.5f}, }; /* forループで全員のデータを表示 */ for (int i = 0; i < 3; i++) { printf("[%d] %s: %d歳, %.1f点\n", i+1, students[i].name, students[i].age, students[i].score); } /* 1人目のスコアを更新 */ students[0].score = 98.0f; return 0; }
💡ポインタで構造体配列を扱う方法

構造体配列はポインタでも操作できます。「Student *ptr = students;」とすると、ptr[0]、ptr[1]のようにインデックスアクセス、またはptr->name(最初の要素)のようにアロー演算子が使えます。ptr++でポインタを次の要素に進めることもできます。

06 構造体を関数に渡す(値渡しとポインタ渡し) 関数の外で変更を反映させたい場合はポインタ渡しが必須

構造体を関数に渡す方法は2種類あります。値渡し(構造体のコピーを渡す)とポインタ渡し(構造体のアドレスを渡す)です。関数内で行った変更を呼び出し元に反映させたい場合は、必ずポインタ渡しを使います。

渡し方引数の型変更の反映メモリのコピー使いどころ
値渡しPerson p反映されない構造体全体がコピーされる(重い)読み取り専用・小さい構造体
ポインタ渡しPerson *p反映されるポインタ(8バイト程度)のみ(軽い)変更が必要・大きい構造体
const付きポインタ渡しconst Person *p反映されない(コンパイルエラー)ポインタのみ(軽い)大きい構造体を効率よく読み取るだけ
#include <stdio.h> typedef struct { char name[50]; int age; } Person; /* 値渡し:関数内の変更は呼び出し元に反映されない */ void birthday_value(Person p) { p.age++; /* コピーを変更するだけ */ printf("関数内: %d歳\n", p.age); } /* ポインタ渡し:関数内の変更が呼び出し元にも反映される */ void birthday_pointer(Person *p) { p->age++; /* 元データを直接変更 */ printf("関数内: %d歳\n", p->age); } int main() { Person p = {"山崎", 30}; birthday_value(p); printf("値渡し後: %d歳\n", p.age); /* → 30(変わらない)*/ birthday_pointer(&p); printf("ポインタ渡し後: %d歳\n", p.age); /* → 31(変わる)*/ return 0; }
代表菅澤 代表菅澤
「関数内で変更したのに呼び出し元が変わらない」というバグの9割は値渡しとポインタ渡しの混同です。C言語では全ての引数がデフォルトで値渡し(コピー)です。変更を反映させたい場合は意識的に「&変数名」でアドレスを渡し、関数側で「*p」や「->」でアクセスする必要があります。
Claude Code 完全解説セミナー|経営者・会社役員専用 1on1 60分 無料Claude Codeを経営に活かしたい方へ — AI鬼管理

07 構造体のコピーと比較の正しい方法 一括コピーと memcmp 問題の正しい対処

7-1. 構造体のコピー

同じ型の構造体変数同士は、=演算子で全メンバを一括コピーできます。char配列を含む構造体でも、=演算子で問題なくコピーされます。

Person src = {"菅澤", 24}; Person dst; /* =演算子で全メンバをコピー(char配列も含む) */ dst = src; printf("%s: %d歳\n", dst.name, dst.age); /* → 菅澤: 24歳 */

7-2. 構造体の比較(==演算子は使えない)

構造体同士を==演算子で比較することはできません。各メンバを1つずつ比較するか、memcmp()を使う方法があります。ただし、memcmpには構造体のパディング(メモリの詰め物)の問題があるため、メンバごとの比較が安全です。

#include <string.h> /* NG: ==演算子は使えない(コンパイルエラー) */ /* if (p1 == p2) → エラー */ /* OK: メンバを1つずつ比較(推奨) */ int person_equal(const Person *a, const Person *b) { return (strcmp(a->name, b->name) == 0) && (a->age == b->age); } /* 注意: memcmpはパディングバイトが不定のため非推奨 */ /* if (memcmp(&p1, &p2, sizeof(Person)) == 0) → パディング問題あり */

📚 用語解説

パディング(padding):C言語の構造体において、メモリアライメント(データの適切なメモリ位置への配置)のためにコンパイラが自動的に挿入する余分なバイト。「char age; int score;」のような構造体では、ageとscoreの間に3バイトのパディングが挿入されることがあります。このパディングバイトの値は不定のため、memcmpで比較すると同じデータなのに「不一致」と判定されることがあります。

08 Claude CodeでC言語構造体コードを自動生成する 「こんな構造体を作って」と日本語で指示するだけでコードが完成

C言語の構造体は概念が理解できても、実際のコードに落とし込むときにミスが発生しやすい領域です。Claude Codeを使えば、日本語で要件を伝えるだけで構造体定義・初期化・関数・エラー処理まで含む完全なコードを自動生成できます。

✔️「商品管理システムの構造体を作って。name・price・stockを持ち、在庫を更新する関数も書いて」
✔️「この構造体をリンクリストに変えて。nextポインタを追加して挿入・削除・検索関数を実装して」
✔️「valueとポインタ渡しの違いが分かるサンプルコードを書いて。コメントで説明も入れて」
✔️「この構造体配列をqsortで名前順にソートするコードを書いて」
✔️「mallocで動的に構造体を確保してfreeまで一連の処理を書いて」

特に便利なのが複雑なデータ構造の実装です。リンクリスト・二分木・スタック・キューなど、ポインタを多用するデータ構造の実装はC言語学習者の大きな壁ですが、Claude Codeなら「リンクリストで社員データを管理するプログラムを書いて」と指示するだけで完全なコードが生成されます。

弊社(株式会社GENAI)では、社内開発で発生するC言語コードの生成・デバッグ・最適化にClaude Codeを活用しています。「なぜこのコードでセグメンテーション違反が起きるか」という質問にも正確に答え、修正コードを提示してくれます。

AI鬼管理山崎 AI鬼管理山崎
構造体を使ったプログラムで「セグメンテーション違反」「バスエラー」といった実行時エラーが出た場合は、ポインタの初期化忘れ・配列の範囲外アクセス・mallocのfree忘れが多いです。コードをClaude Codeに貼り付けて「このエラーの原因を教えて」と聞くと、ほぼ一発で原因を特定してくれます。

Claude Codeを使ったC言語開発のメリットは、コードの生成だけでなく「なぜそのコードが正しいのか」の説明も同時に得られる点です。構造体・ポインタ・メモリ管理といったC言語の難しい概念を、自分のコードを例に学べます。

✔️構造体(struct)は異なる型のデータを1つにまとめる仕組み。配列と組み合わせて複数データを管理できる
✔️typedefでstruct名をエイリアス化すると「struct Person」を「Person」と短く書ける
✔️ドット演算子(.)で構造体変数のメンバにアクセス。char配列の代入はstrcpyを使う
✔️アロー演算子(->)は構造体ポインタからメンバにアクセスするための演算子((*ptr).member の略)
✔️関数への渡し方:変更を反映させたい場合はポインタ渡し(&変数)、読み取りのみなら値渡し可
✔️構造体のコピーは=演算子でOK。比較はメンバを1つずつ(memcmpはパディング問題あり)
✔️Claude Codeで構造体定義・ポインタ操作・データ構造実装を自動生成・デバッグできる

C言語の構造体・ポインタを使った開発はClaude Code×AI鬼管理で加速

構造体・ポインタ・メモリ管理など複雑なC言語コードの生成・デバッグにClaude Codeを活用する方法を、弊社の実績を交えてご紹介します。

代表菅澤 代表菅澤
C言語の難しさの核心はポインタとメモリ管理です。Claude Codeはこの部分のサポートが特に強力で、「なぜセグメンテーション違反が起きるか」「どこでメモリリークしているか」を即座に特定します。無料相談から始めてみてください。

NEXT STEP

この記事の内容を、あなたのビジネスで
実践してみませんか?

AI活用を自社で回せるようになりたい方へ

AI鬼管理

Claude Code・Cowork導入支援から業務設計・社内浸透まで実践ベースで伴走。「自社で回せる組織」を90日で作る経営者向けトレーニング。

よくある質問

Q. C言語の構造体とクラス(C++)の違いは何ですか?

A. C言語の構造体(struct)は基本的にデータの集まりで、メンバ変数を持ちますが、メンバ関数(メソッド)・アクセス制御(public/private)・継承はありません。C++のclassと比べると機能が限定的ですが、軽量でシンプルです。C言語で「メソッド」に相当する機能を実現したい場合は、構造体のポインタを第1引数に取る関数として定義するのが一般的なパターンです。

Q. struct宣言とtypedefはどちらを使うべきですか?

A. 現代のC言語(C99以降)ではtypedefを使うスタイルが一般的です。「typedef struct { ... } TypeName;」と書くことで「struct TypeName」の代わりに「TypeName」と短く書けます。ただし自己参照が必要な構造体(リンクリストのnextポインタなど)では「typedef struct Node { struct Node *next; } Node;」のようにtag名も必要です。

Q. ドット演算子(.)とアロー演算子(->)はどう使い分けますか?

A. 変数名から直接アクセスするとき(Person p; → p.name)はドット演算子、ポインタ経由でアクセスするとき(Person *ptr; → ptr->name)はアロー演算子を使います。「アロー演算子=ポインタのとき」と覚えれば迷いません。「ptr->name」は「(*ptr).name」の省略形です。

Q. 関数に構造体を渡すとき値渡しとポインタ渡しの違いは?

A. 値渡し(関数引数に「Person p」)では構造体全体がコピーされ、関数内での変更は呼び出し元に反映されません。ポインタ渡し(「Person *p」)ではアドレスのみが渡され、「p->メンバ」で元データを直接変更できます。「関数の外でも変更を反映させたい」ときは必ずポインタ渡しを使います。また大きな構造体を読み取るだけの場合も「const Person *p」のconst付きポインタ渡しが効率的です。

Q. 構造体のコピーは=演算子でできますか?

A. できます。「dst = src;」とすると構造体の全メンバがコピーされます。char配列メンバも含めて正しくコピーされます。ただしポインタメンバがある場合は「浅いコピー(シャローコピー)」になり、ポインタ先のデータは共有されます。ポインタ先まで独立してコピーしたい場合は深いコピー(ディープコピー)の実装が必要です。

Q. 構造体の比較に==演算子は使えますか?

A. 使えません。C言語では構造体同士を==で比較するとコンパイルエラーになります。比較するにはメンバを1つずつ比較する関数を自分で定義するのが安全です。memcmp()も使えますが、構造体には「パディング(メモリの詰め物)」があり、同じ値でもmemcmpが「不一致」と返すことがあるため非推奨です。

Q. 動的に確保した構造体はどう解放しますか?

A. mallocで確保した構造体は、使用後に必ず「free(ptr);」で解放します。解放したポインタは「ptr = NULL;」でNULLにしておくと、二重解放(double free)を防げます。構造体がポインタメンバを持つ場合は、構造体本体を解放する前にポインタメンバの先も先にfreeするよう注意してください。

AIAI鬼管理

AI鬼管理へのお問い合わせ

この記事を読んで気になった方へ。
AI鬼管理の専門スタッフが、御社に最適な
業務自動化プランを無料でご提案します。

会社名を入力してください
業種を選択してください
お名前を入力してください
正しいメールアドレスを入力してください

1つ以上選択してください
1つ以上選択してください
月額コストを選択してください

約1時間のオンライン面談(Google Meet)です

空き枠を取得中...
面談日時を選択してください

予約確定後、Google Calendarの招待メールをお届けします。
しつこい営業は一切ございません。

監修 最終更新日: 2026年7月18日
菅澤孝平
菅澤 孝平 株式会社GENAI 代表取締役
  • AI業務自動化サービス「AI鬼管理」を運営 — Claude Code を活用し、経営者の業務を「AIエージェントに任せる仕組み」へ転換するパーソナルトレーニングを 伴走構築 で提供。日報・採用・問い合わせ対応・経費精算・議事録・データ集計・営業リスト等の定型業務を、AIに代行させる体制を経営者と一緒に作り込む
  • Claude Code 実装ノウハウを 経営者・法人クライアント に直接指導。生成AIを「便利ツール」ではなく 「業務を任せる存在」 として運用する手法を体系化
  • 「やらせ切る管理」メソッドの開発者。シンゲキ株式会社(2021年設立・鬼管理専門塾運営)にて累計3,000名以上の学習者を志望校合格に導いた管理メソッドを、AI × 経営者支援 に転用
  • 著書『3カ月で志望大学に合格できる鬼管理』(幻冬舎)、『親の過干渉こそ、最強の大学受験対策である。』(講談社)
  • メディア出演: REAL VALUE / カンニング竹山のイチバン研究所 / ええじゃないかBiz 他
  • 明治大学政治経済学部卒
現在は AI鬼管理(Claude Code活用の伴走型パーソナルトレーニング)を主事業とし、経営者と二人三脚で「AIに業務を任せる仕組み」を実装。「実行を強制する環境」を AI で構築する手法を、自社の実運用知見をもとに発信している。