【2026年7月最新】C言語の構造体(struct)完全ガイド|typedef・ポインタ・アロー演算子・配列・関数引数まで徹底解説
この記事の内容
「構造体って何が便利なの?」「ポインタとアロー演算子の違いが分からない」「関数に構造体を渡したら値が変わらなかった」——C言語を学ぶ際によく発生するつまずきポイントです。
C言語のstruct(構造体)は、複数の異なる型のデータを1つのまとまりとして扱う仕組みです。例えば「名前(文字列)」「年齢(整数)」「身長(小数)」という異なる型のデータを「人物」という1つの構造体で管理できます。実際のプログラム開発では、配列だけでは対応できない複雑なデータを扱う場面で必ず使います。
この記事では、C言語の構造体についてstruct宣言・typedef・ドット演算子・ポインタ・アロー演算子・配列・関数への渡し方・コピーと比較まで、コードサンプル付きで体系的に解説します。
01 STRUCT BASICS 構造体とは――異なる型のデータをひとまとめにする仕組み 配列との違いと構造体が必要になる場面を理解する
C言語の構造体(structure)は、異なる型のデータを1つのまとまりとして管理する仕組みです。配列が「同じ型のデータを複数格納できる」のに対し、構造体は「異なる型のデータを1つのグループにできる」点が大きな違いです。
📚 用語解説
構造体(struct):C言語でint型・char型・float型など異なる型のデータを1つのまとまり(型)として定義する機能。例えば「名前(char)・年齢(int)・身長(float)」を持つ「Person型」を作れます。structキーワードで宣言し、メンバと呼ばれる各フィールドに個別にアクセスします。
| 比較項目 | 配列(array) | 構造体(struct) |
|---|---|---|
| 格納する型 | 全要素が同じ型 | 異なる型が混在可能 |
| 要素の識別 | インデックス(数字)でアクセス | メンバ名(名前)でアクセス |
| 主な用途 | 同じ種類のデータを大量に | 属性の異なるひとまとまりのデータ |
| 例 | int scores[5] (5人分の点数) | Person型(名前・年齢・点数) |
具体的な例を見てみましょう。学生データを管理するプログラムを作る場合を考えます。
①複数の属性を持つデータを管理したい(社員・商品・ゲームキャラクター)②データをまとめて関数に渡したい③リンクリスト・ツリーなどのデータ構造を実装したい——これらの場面が構造体の出番です。C言語ではclassが使えないため、「クラスの代わり」として構造体を活用します。
02 STRUCT DECLARATION struct宣言とtypedefの使い方 2つの宣言スタイルと使い分けのポイント
構造体を使うには、まずstructキーワードで構造体型を定義(宣言)します。C言語では2つのスタイルがあります。struct名前 {...}形式と、typedefを使ったエイリアス形式です。
2-1. 基本のstruct宣言
2-2. typedefを使ったスタイル(推奨)
typedefを使うと、struct Personを単にPersonと書けるようになります。コードが読みやすくなるため、実務ではtypedefを使ったスタイルが一般的です。
📚 用語解説
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 struct Node { struct Node *next; } Node;」のようにtag名(struct Node)とtypedef名(Node)の両方を定義します。
03 DOT OPERATOR メンバへのアクセス(ドット演算子)と初期化 構造体変数のメンバを読み書きする方法
構造体を宣言した後は、ドット演算子(.)を使ってメンバにアクセスします。「構造体変数名.メンバ名」の形式で値を読み書きできます。
3-2. 宣言時に一括初期化する
char配列メンバに文字列を代入するとき、「p.name = "山田";」のように直接代入はできません。「strcpy(p.name, "山田");」を使います。宣言時の初期化(= {...})では直接文字列リテラルを指定できますが、後からの代入はstrcpy(またはsnprintf)が必要です。
04 POINTER & ARROW 構造体ポインタとアロー演算子(->) ポインタ経由で構造体メンバにアクセスする方法
C言語の学習でつまずきやすいのが「構造体ポインタ」と「アロー演算子(->)」の組み合わせです。構造体へのポインタを使うとき、ドット演算子(.)の代わりにアロー演算子(->)を使います。
📚 用語解説
アロー演算子(->):構造体へのポインタからメンバにアクセスするための演算子。「(*ptr).member」と書く代わりに「ptr->member」と書ける省略記法です。マイナス記号とより大なり記号の組み合わせで「矢印(->)」に見えることからアロー演算子と呼ばれます。
Person型のデータが
メモリに確保
&pでpのアドレスを
格納
pのnameメンバに
直接アクセス
元の変数pも
同時に変化
4-2. mallocで動的に構造体を生成する場合
📚 用語解説
sizeof演算子:変数や型のメモリサイズ(バイト数)を返すC言語の演算子。「sizeof(Person)」とすると構造体Personのバイトサイズが得られます。mallocで動的メモリを確保するときや、構造体のサイズを計算するときに必ず使います。int型は通常4バイト、double型は8バイトなど、型によってサイズが異なるためsizeofを使うとポータブルなコードになります。
mallocで動的確保した構造体は、使い終わったら必ずfree()でメモリを解放してください。解放しないとメモリリーク(使用済みメモリが解放されずに残り続ける問題)が発生し、長時間動作するプログラムでメモリ不足の原因になります。
05 STRUCT ARRAY 構造体の配列――複数データをまとめて管理する 複数の人物・商品データを構造体配列で効率的に扱う
構造体変数を配列として宣言することで、同じ型の構造体を複数まとめて管理できます。「10名分の社員データ」「100個の商品データ」など、同じ属性を持つ複数のデータを扱うときに使います。
構造体配列はポインタでも操作できます。「Student *ptr = students;」とすると、ptr[0]、ptr[1]のようにインデックスアクセス、またはptr->name(最初の要素)のようにアロー演算子が使えます。ptr++でポインタを次の要素に進めることもできます。
06 FUNCTION ARGS 構造体を関数に渡す(値渡しとポインタ渡し) 関数の外で変更を反映させたい場合はポインタ渡しが必須
構造体を関数に渡す方法は2種類あります。値渡し(構造体のコピーを渡す)とポインタ渡し(構造体のアドレスを渡す)です。関数内で行った変更を呼び出し元に反映させたい場合は、必ずポインタ渡しを使います。
| 渡し方 | 引数の型 | 変更の反映 | メモリのコピー | 使いどころ |
|---|---|---|---|---|
| 値渡し | Person p | 反映されない | 構造体全体がコピーされる(重い) | 読み取り専用・小さい構造体 |
| ポインタ渡し | Person *p | 反映される | ポインタ(8バイト程度)のみ(軽い) | 変更が必要・大きい構造体 |
| const付きポインタ渡し | const Person *p | 反映されない(コンパイルエラー) | ポインタのみ(軽い) | 大きい構造体を効率よく読み取るだけ |
07 COPY & COMPARE 構造体のコピーと比較の正しい方法 一括コピーと memcmp 問題の正しい対処
7-1. 構造体のコピー
同じ型の構造体変数同士は、=演算子で全メンバを一括コピーできます。char配列を含む構造体でも、=演算子で問題なくコピーされます。
7-2. 構造体の比較(==演算子は使えない)
構造体同士を==演算子で比較することはできません。各メンバを1つずつ比較するか、memcmp()を使う方法があります。ただし、memcmpには構造体のパディング(メモリの詰め物)の問題があるため、メンバごとの比較が安全です。
📚 用語解説
パディング(padding):C言語の構造体において、メモリアライメント(データの適切なメモリ位置への配置)のためにコンパイラが自動的に挿入する余分なバイト。「char age; int score;」のような構造体では、ageとscoreの間に3バイトのパディングが挿入されることがあります。このパディングバイトの値は不定のため、memcmpで比較すると同じデータなのに「不一致」と判定されることがあります。
08 CLAUDE CODE C Claude CodeでC言語構造体コードを自動生成する 「こんな構造体を作って」と日本語で指示するだけでコードが完成
C言語の構造体は概念が理解できても、実際のコードに落とし込むときにミスが発生しやすい領域です。Claude Codeを使えば、日本語で要件を伝えるだけで構造体定義・初期化・関数・エラー処理まで含む完全なコードを自動生成できます。
特に便利なのが複雑なデータ構造の実装です。リンクリスト・二分木・スタック・キューなど、ポインタを多用するデータ構造の実装はC言語学習者の大きな壁ですが、Claude Codeなら「リンクリストで社員データを管理するプログラムを書いて」と指示するだけで完全なコードが生成されます。
弊社(株式会社GENAI)では、社内開発で発生するC言語コードの生成・デバッグ・最適化にClaude Codeを活用しています。「なぜこのコードでセグメンテーション違反が起きるか」という質問にも正確に答え、修正コードを提示してくれます。
Claude Codeを使ったC言語開発のメリットは、コードの生成だけでなく「なぜそのコードが正しいのか」の説明も同時に得られる点です。構造体・ポインタ・メモリ管理といったC言語の難しい概念を、自分のコードを例に学べます。
C言語の構造体・ポインタを使った開発はClaude Code×AI鬼管理で加速
構造体・ポインタ・メモリ管理など複雑な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するよう注意してください。
Claude Codeで業務自動化を90日で叩き込む
経営者向けの伴走型パーソナルトレーニング
Claude Code を業務に落とし込む
専門研修コース一覧
受講者本人の業務を題材に、「使いこなせる」状態になるまで伴走する研修プログラム。1対1特化型・ハンズオン・法人講座の3コースを展開中。業務特化・実装まで踏み込むタイプのClaude Code研修です。
研修コース一覧を見る →AI鬼管理へのお問い合わせ
この記事を読んで気になった方へ。
AI鬼管理の専門スタッフが、御社に最適な
業務自動化プランを無料でご提案します。




