0
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ポインタの理解のためのアドレスの考え方

Posted at

##前書き
本稿は初学者から、ポインタの理解があいまいで困っている人に向けた文章である。
玄人、ポインタの理解はもう大丈夫という人には退屈であろうし、突っ込みたくなる点が多々あると思われるのでUターンしてほしい。(筆者は臆病なのでそういうの怖いのだ。)
理解していただけたら次へどぞ

##アドレスの理解
例えば、「以下のような変数のアドレスを表してほしい」と言われたときにパッと書けるだろうか?

/*定義*/
//char型の変数c
char c;

答えは以下のようになる。

/*char型の変数cのアドレス*/
 &c

なんだそれだけのこと答えさせたかったのかと思うだろう。もちろんそれだけのことだ。
char型のcという変数のアドレスを表したいときには&cと書けばよいのだ。

では、任意にアドレスを設定できないのだろうか?

##アドレスを変数で表す意味
アドレスはメモリ中での住所である。
たとえるなら、&cの場所にcさんの持つ変数の内容が住んでいる。

現実では、住所は他人が__勝手に変えたりしたら危ない__。東京都の住所がすべて北海道の住所と置き換わってしまったら大変なことになる。
これがメモリの中でも起こっている。勝手に住所を変な場所に指定されてしまったら困るのだ。

そんなわけで、__変数のアドレスはあらかじめ&(変数名)のように形が決まっている__のである。これなら書いてる間におかしな住所になることもない。

##アドレスとポインタの関係性
ここからがポインタの重要性にかかわる話だと思う。

アドレスを示す方法が分かったが、アドレスをそのまま持ち運ぶのはいささかアンパサンド書くのがめんどくさい。
アドレスを格納するための変数を定義したほうがよさそうだ。
 ここでポインタが登場する。

/*定義*/
//char型の変数c
//char型のポインタ変数c_p
char c;
char *c_p;

/*操作*/
//ポインタ変数c_pに変数cのアドレスを格納
c_p = &c;

先ほど定義したchar型の変数cに加えて、char型のポインタ変数c_pを定義した。また、c_pの値としてcのアドレスを格納させている。これで&cと書かなくてもc_pと書けばcのアドレスを示すことができる。

ここで覚えていてほしい。あくまで__ポインタ変数自体は変数のアドレスを格納するための変数__なのだ。

ひょっとすると、既習の人の中ではこのあたりで

「*c_pとc_pの違いってなんだ?」

と疑問に思った人もいたのではないだろうか。

それこそがポインタの落とし穴なのだ。

先ほど、メモリのアドレスの場所には変数の持つ値が住んでいると書いた。つまり、メモリがわかれば住んでいる人がわかるのだ。

なら、アドレスだけで内容を扱うことができるようにしよう!

これがポインタの本質であり、落とし穴の最大のポイントだ。
ポインタ変数自体はアドレスを格納するが、その値も触れる機能を付け足したという点が混乱をもたらした。

__アドレスの内容__を扱うために、__ポインタ変数__と__ポインタ変数のさす内容__の違いを明確に書かなくてはいけない。
以下に示すように、アドレスとその中身を__明確に(??)__分けたのだ。

/*定義*/
//char型の変数c
//char型のポインタ変数c_p
char c;
char *c_p;

/*操作*/
//ポインタ変数c_pに変数cのアドレスを格納
c_p = &c;
//??????
*c_p = 'A';

printf("%c", c);

前半は先ほどと変わらない。

が、そのあと。*c_p = 'A'としている。
これは先ほど言った通り、__アドレスのさす先の変数の内容__を書き換える操作をしているのだ。
これが一番ややこしい。

つまり、__ポインタ変数の定義に用いたアスタリスク__が、ポインタ変数のさすアドレスの内容を使うときにも用いられている。
これでは混乱するのも無理はない。

ちなみに先ほどのコードの出力結果は、以下のようになるだろう。

A

なぜなら、*c_pはc_pの指すアドレスの内容を表している。つまり、cのことだ。

*c_p = 'A';
//と書くことは
c = 'A';

と書くこととほとんど意味が変わらない。

##ここまでのまとめ

  1. 変数のアドレスは__&(変数名)__で表す。
  2. ポインタ変数の定義は以下のように表す。
(型名) *(任意のポインタ変数の名前);

3.__ポインタ変数の指すアドレスの内容__を指すときは以下のように表す。

 *(任意のポインタ変数の名前);

##感想
あまり、初学者の意見をくみ取った記事の書き方ができているとは思えないが、今回はいったんここで止めようと思う。
疑問を持った時はできるだけコメントなどで聞いてほしい。
答えうる範囲で答えていきたい。意義や疑問、修正点もぜひいただければと思う。

今後配列とアドレス、ポインタの関係もかけたらと思う(と言って自分の首を絞める)

0
4
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
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?