C言語入門|*記号で混乱しないための基本ルール

ポインタ学習で迷子にならないために

正直に言うと、ここまで来て
「なんとなくわかった気はするけど、まだ頭の中がごちゃごちゃしてる」
という人、多いんじゃないでしょうか。

特にややこしいのが、あの *(アスタリスク)記号 です。

  • 型名にも付く
  • 変数の前にも付く
  • 同じ見た目なのに役割が違う

今回は、この章の締めとして
*記号に振り回されないための考え方の軸 を、しっかり整理していきましょう。

まず最重要ルール:*には「2つの顔」がある

ポインタの話題で出てくる *記号には、
まったく別物の2種類 が存在します。

次のコードを見てください。

int* addrA;           // ➀
printf("%d\n", *addrA); // ➁

見た目は似ていますが、➀と②は役割が完全に違います

① 型名の一部としての*

まずこちら。

int* addrA;

この * は 演算子ではありません

項目内容
正体型名の一部
意味int型を指すポインタ型
単体での意味なし

ここで大切なのは、

int は1つの不可分な型名*

だということです。

  • int と * が別々に意味を持つわけではない
  • int* 全体で「ポインタ型」という名前

この行では、まだ何も操作はしていません。
ただ 変数の性質を決めているだけ です。

② 間接演算子としての*

次にこちら。

*addrA

今度の * は、はっきりとした 演算子 です。

項目内容
正体間接演算子
入力ポインタ変数
動作指している番地の内容を読み書き
結果値(または代入先)に化ける

つまり、

  • addrA が持っているアドレスを使い。
  • その番地にある値を操作する。

という 実行時の動作 を表しています。

ここまでを一度、表で整理しよう

見た目役割分類
int* addrA型名の一部宣言
*addrA間接演算子操作

この区別がついた瞬間、
ポインタに対するストレスは一気に減ります。

「わかるとスッキリ」する瞬間

ここまで聞いて、

あっ、
同じ記号に見えてただけで
役割は別物だったんだ

と思えたなら、大正解です。

多くの混乱は、
この2つを無意識に混ぜて考えてしまうこと
から起きています。

次の落とし穴:伝統的な書き方

ここで、もう一つ注意点があります。

C言語では、次のような書き方も昔から使われてきました。

int *addrA;

これは さきほどの宣言と意味は同じ です。

書き方意味
int* addrAint*型の変数
int *addrAint*型の変数

動作上の違いはありません。

……が、
初心者にとっては、かなりの混乱ポイント になります。

なぜ混乱するのか

理由は、複数変数の宣言と組み合わさったときに現れます。

まず、普通の変数宣言を見てみましょう。

int a, b;

これは、

変数
aint
bint

という、直感どおりの宣言です。

ポインタで同じ感覚を使うと…?

次に、ポインタで同じように書いてみます。

int* a, b;

ぱっと見では、

a も b もポインタ?

と思ってしまいがちですが、
実際の意味は違います

変数
aint*
bint

b は ポインタではありません

正しく2つのポインタを宣言するには

歴史的な仕様の都合により、
正しくは次のように書く必要があります。

int *a, *b;

これでようやく、

変数
aint*
bint*

になります。

でも、これがさらに混乱を招く

この書き方の問題点は、

  • 本来一体であるはずの int* が
  • 見た目上、分断されてしまう

ことです。

そのため、

  • 型と変数の関係が見えにくい。
  • 学習者が「*は変数に付く」と誤解しやすい。

というデメリットがあります。

このサイトでの基本方針

以上の理由から、このサイトの記事では次の方針を取ります。

方針理由
int* は型名として一体で書く意味が明確
1文で複数の変数を宣言しない誤解を防ぐ

つまり、こうです。

int* a;
int* b;

少し行数は増えますが、
読みやすさと安全性は段違い です。

最後に:*を見たら、まず自問しよう

コードの中で * を見かけたら、
次の質問を自分に投げかけてください。

質問YESなら
型名の中にある?宣言
変数の前にある?間接演算子

このチェックを習慣にするだけで、
*記号は 敵ではなく、味方 になります。

ここまで来れば、
もう *記号に怯える必要はありません

次はいよいよ、
この理解を使って 実践的なポインタ操作 に進んでいきましょう。