0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ポインタや構造体に関してまとめ

0
Posted at

🚀 C言語:ポインタから構造体・連結リストまでの完全まとめ

1. ポインタの階層構造(マトリョーシカ)

C言語のポインタは、データの「階層(次元)」が増えるたびに * の数が増えていきます。全体をいくつかのグループ(群)で束ねていく階層構造として捉えるのが正解です。

階層 概念・役割 宣言の例 メモリの実態イメージ
単体 データそのもの int score = 10; 1つの数値や文字の箱
1階層 (*) A群(データの集まり) int *p = &score; 通常の変数のアドレスを指すポインタ(1次元)
2階層 (**) B群(A群をまとめる) int **pp = &p; ポインタ変数のアドレスを指すポインタ(2次元)
3階層 (***) C群(B群をまとめる) int ***ppp = &pp; ダブルポインタのアドレスを指すポインタ(3次元)

2. 「ポインタ配列」と「ダブルポインタ」の決定的な違い

どちらも複数のポインタを扱うために使われますが、特定の場所(メモリ領域)を指すか指さないかという柔軟性に決定的な違いがあります。

📊 性能・特徴の比較

比較項目 ポインタ配列 (Type *arr[N]) ポインタへのポインタ (Type **pp)
本質 配列(メモリ領域そのもの) 変数(ポインタ)(アドレスを格納する器)
特定の場所 指す(固定)。作った時点でサイズが決まる。 指さない(自由)。最初はどこも指していない。
柔軟性 ❌ 後から要素数を増やしたり減らしたりできない。 ⭕ malloc/reallocでサイズを自由に変更可能。
主な用途 文字列の配列(長さの異なる文字列の管理) 関数の引数でポインタを書き換える、動的2次元配列

3. 構造体(struct)の基本

構造体は、配列と違って**「種類の異なる複数の型」**を1つのグループとしてまとめて管理する仕組みです。

  • .(ドット演算子): 構造体の実体(変数)から中身にアクセスする。
  • ->(アロー演算子): 構造体を指すポインタ経由で中身にアクセスする。
    • ptr->age は (*ptr).age をスマートに書いたもの。

4. 複数データの管理:「構造体配列」vs「連結リスト」

複数の構造体データをまとめて管理する方法には、一長一短(トレードオフ)があります。

📊 メモリ構造と性能の比較

比較項目 構造体配列 (Student class) 連結リスト (struct Node *head)
メモリ配置 メモリ上に連続して一列に並ぶ メモリ上のバラバラの場所に散らばる
データの追加・削除 ❌ 苦手(途中に割り込むと後ろを全部ずらす) ⭕ 大得意(ポインタの矢印を付け替えるだけ)
特定データへのアクセス ⭕ 超高速(100番目に一発でジャンプできる) ❌ 遅い(先頭から100回矢印をたどる必要がある)
メモリの無駄 ❌ 出やすい(使わない枠も最初に確保する) ⭕ ゼロ(増えた瞬間だけピンポイントで確保)

5. 連結リストの実装と重要ルール

🛠️ データを末尾に自動追加する関数例

先頭のポインタ(head)自体を関数内で書き換える可能性があるため、引数には**ポインタのポインタ(**head_ref)**を使用します。

struct Node {
    char name[50];
    struct Node *next; // 次の部屋を指す魔法の矢印
};

void append(struct Node **head_ref, const char *new_name) {
    // 1. 新しい部屋を malloc で作る
    struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
    strcpy(new_node->name, new_name);
    new_node->next = NULL;

    // 2. リストが空なら、この部屋を先頭にする
    if (*head_ref == NULL) {
        *head_ref = new_node;
        return;
    }

    // 3. 最後の部屋(next が NULL の部屋)を探す
    struct Node *last = *head_ref;
    while (last->next != NULL) {
        last = last->next;
    }

    // 4. 最後の部屋の後ろに新しい部屋を繋ぐ
    last->next = new_node;
}

⚠️ メモリ解放(free)の鉄則:「逆マトリョーシカ」

動的に確保したメモリを解放するときは、必ず内側(奥のデータ)から外側へ順番に消さなければなりません。

  • 理由: 外側(住所録や先頭ポインタ)を先に free してしまうと、奥にあるデータの場所を知る手段(参照方法)が完全に消滅し、二度と解放できないゴミ(メモリリーク)になるため。
  • 対策: 連結リストを消すときは、必ず「次の場所」を一時的なポインタに避難させてから、現在の部屋を free します。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?