ダブルポインタ
ダブルポインタ完全版。。
目的・状況 | 関数の例 | 呼び出し側の例 | ダブルポインタ必要? | 詳細な理由 |
---|---|---|---|---|
データを読み取るだけ | void print_line(char *line) |
print_line(line); |
❌ | 中身を読むだけならポインタ1つで十分。 |
データの中身を変更(書き込み) | void fill_line(char *line) |
fill_line(line); (事前に malloc 済) |
❌ | 指す先のメモリが確保済みなら、内容だけ変更すればいいので一重でOK。 |
呼び出し元のポインタに malloc で新しいメモリを割り当てたい | void make_line(char **line) |
make_line(&line); |
✅ | ポインタそのものを書き換えたいなら、住所(アドレス)を渡す必要がある=ダブルポインタ。 |
関数内で malloc して返す | char *create_line(void) |
line = create_line(); |
❌ | ポインタを返すことで、呼び出し元が自由に受け取って代入する形式。 |
複数の行を扱う(2次元配列) | void print_lines(char **lines) |
print_lines(lines); |
❌ | 配列の先頭ポインタを渡しているだけ。構造は char *lines[] と同じ。 |
複数の行を malloc して呼び出し元に渡したい | void make_lines(char ***lines) |
make_lines(&lines); |
✅ | 呼び出し元の char **lines に対して新しいアドレスを代入するため、3重構造になり char *** が必要。 |
構造体ポインタの中に新しいノードを作って代入したい | void make_node(t_list **node) |
make_node(&new_node); |
✅ |
*node = malloc(...) のように、呼び出し元のノードポインタを変更する場合はダブルポインタ。 |
構造体ポインタの中身だけを書き換えたい | void fill_node(t_list *node) |
fill_node(node); (malloc 済) |
❌ | ポインタの先の中身だけ変更するなら一重でOK。 |
また、ダブルポインタがわからないのは初期化の理解が浅いからだと気づいた。
「初期化のタイミング」が、ダブルポインタ vs return型の分かれ目だった(びっくり)。
これから「関数が malloc して返す場合の初期化」について、解説する。
✅ Q. char *line; を初期化しないで宣言しておいて、最後に line = make_line(); していいの?
👉 答え:Yes、OKです!
なぜか?
char *line; とだけ書いたとき、line は「未初期化ポインタ」になる
だけどそのあとに line = make_line(); と確実に代入するなら、問題なし
C言語では、未使用のまま操作したらアウトだけど、代入されてから使えばOK
🔍 整理:return型 malloc のときの初期化のタイミング
✅ 典型的なパターン
char *line; // ← まだ中身はゴミ(未初期化)
line = make_line(); // ← ここで初めて「有効なメモリ」を指すようになる
📌 このパターンでは、初期化は代入のタイミングで完了する
(その前に line を使ったらアウト。printf("%s\n", line); などは絶対ダメ)
❌ 初期化前に使ってしまう例(危険)
char *line;
printf("%s\n", line); // ← line はまだゴミ!未定義動作(UB)⚠️
🧠 じゃあ、なぜダブルポインタでは初期化する必要があるの?
✅ ダブルポインタの場合、関数の中で malloc するのが前提
char *line = NULL; // ← 安全のため NULL に初期化しておく(← 重要)
make_line(&line); // ← 関数の中で malloc & 代入される
line は関数の外にあるポインタなので、何も指してないと怖い
NULL で初期化しておくと、free(line); しても安全(malloc 前なら何も起こらない)
Discussion