見出し画像

【C言語プログラミング8】1000円ガチャとポインタ

C言語で最強に難しいとされるのが、このポインタと言うやつです。私もポインタを最初に習った時は理解できませんでした。余りにも理解不能過ぎて、ポインタの事だけが書かれた本を一冊読んだ覚えがあります。ただ、今となっては何も難しいと思わないので、極力分かり易く説明したいと思います。

そもそもポインタとは

ポインタとは変数(メモリ)のアドレスを入れることの出来る変数のことです。今までの記事で、変数はメモリ上に配置され、メモリにはアドレスと呼ばれる番号が振られていると説明しました。あの話は実はここに繋がっていたのです。繰り返しになりますが、ポインタとはアドレスを入れることの出来る変数です。たったこれだけの話。

ポインタの宣言

ポインタも変数なので宣言してから使います。通常変数とポインタ変数の宣言の違いは以下の通りです。

char *pointer; // ポインタ変数
char sample;   // 通常変数

変数の前に*(アスタリスク)を付けると、これはポインタ変数ですよと言う意味になります。このように宣言した場合、メモリのイメージは以下のようになります。

ポインタ

ポインタ変数は大抵4バイトになります。何故ならばポインタ変数にはアドレスが入るからです。アドレスは馬鹿デッカイ値になりますので、4バイト必要なのです。

ポインタの例え話

お笑い芸人のサンドウィッチマンがやってる番組で1000円のガチャガチャ引いて元取れるか?みたいなのありますよね。あのガチャガチャを例にポインタを説明しようと思います。

1000円でガチャガチャすると、まずカプセルが出てきます。パカッと開けると番号札が出てきます。その番号のロッカーを開けると景品がゲットできます。この話とポインタを繋げると以下のような関係性になります。

ガチャガチャのカプセル   :   ポインタ変数
番号札                                   :   変数のアドレス
ロッカー          :   変数
景品                                       :   変数の値

ポインタ変数(カプセル)には、変数のアドレス(番号札)が入っていて、アドレスを辿れば変数(ロッカー)に行き着き、変数の値(景品)を見ることが出来る。理解できたでしょうか?分からなければ、ゆっくり読み返して下さい。分かったら次に進みましょう。

ポインタ変数の使用方法

ポインタ変数を実際に使ったコードの例は以下のようになります。

char *pointer;
char sample = 100;  // sample変換には100が入っている
 
pointer = &sample;  // ポインタ変数にsampleと言う変数のアドレスを入れる
*pointer = 0;       // ポインタ変数の中身であるアドレスに0を入れる

コードの説明をしますと、sample変数(ロッカー)100(景品)が入っています。上の方に示したメモリイメージ図を参照して下さい。sample変数はメモリの20番地に配置されていますね。つまり、20番地の中身は100だと言うことです。そして、pointer変数にsample変数のアドレスを入れています。pointer = &sample;これがその意味になります。変数の前に&を付けると、その変数のアドレスが取得できます。つまり、pointer変数(カプセル)にはsample変数のアドレスである20番地(番号札)が入ります。

そして、最後に*pointer = 0; とありますが、これはポインタ変数が指し示すアドレス、つまり20番地に0を入れているのです。20番地に0を入れると言うことは、ロッカーに0を入れることになるので、sample変数に0を入れることになります。つまり、sample = 0;としたのと同じです。理解出来ましたか?

C言語の仕様として、ポインタを扱う時のアスタリスクがややこしいんです。ポインタ変数を宣言する時もアスタリスクだし、ポインタ変数に入っているアドレスに対してデータを読み書きする場合もアスタリスクです。

仮に誤って以下のように記述するとどう言う意味になるか分かりますか?

pointer = 0;

これはロッカーの番号が0だよ。と言う意味になってしまいます。20番ロッカーに0を入れることにはなりません。ポインタ変数の中に入っているアドレス(ロッカー)にアクセスしたい場合は、*pointer = 0;のように必ずアスタリスクを付けましょう。

実際にポインタの中身を覗いてみる

Visual Studioを使うと、プログラムを1行1行ゆっくりと実行することができます。もちろん、変数の中身が今どうなっているのか、メモリの状態がどうなっているのかを覗き見することも出来ます。実際に上で示したサンプルプログラムを実行してみます。

Visual Studioでサンプルプログラムをビルドし、F10キーを押すと以下のような状態になります。左端に黄色い矢印が表示されていますが、これは「今からこの行を実行します」という意味です。もう一度F10キーを押すと矢印が一行下に移動します。この操作のことをステップ実行と言います。

ステップ実行1

同じ操作をして6行目まで実行したら以下のような表示になります。画面左下にウィンドウが出て来て、ローカルタブを選択すると、ローカル変数が見えます。*pointerとsampleが見えていますね。sampleの値が100になっていることが分かると思います。pointerには未だ何も入れていないので、ゴミが入っています。0xccccccccですね。10進数だと3,435,973,836です。

画像7

更にF10を押すと以下のようになります。

ステップ実行2

pointerにsample変数のアドレスが入りましたね。今回のsample変数のアドレスは0x005cfb73らしいです。では、実際にsample変数が配置されているメモリのアドレス0x005cfb73番地を確認して見ましょう。ツールバーのデバッグ ⇒ ウィンドウ ⇒ メモリ ⇒ メモリ(1)をクリックすると以下の画面になります。

ステップ実行2

メモリ1というウィンドウが表示され、16進数の値がズラッと並んでいますね。これがメモリの中身です。赤矢印にsample変数のアドレスである0x005cfb73と入力すると、その番地までジャンプしてくれます。

さて、0x005cfb73番地の中身はどうなってますか?0x64ですね。10進数だと100です。0x64の右に目を移すと、0x730xfb0x5c0x00と並んでいますね。見覚えありませんか?そうです、0x005cfb73ですね。値が逆から並んでいるように見えるのは、4バイトデータを1バイト区切りで見るとこう見えるからです(リトルエンディアンの場合)。と言うことはpointer変数は0x005cfb7c番地から配置されていることになります。最初に示したメモリイメージ図とは違いましたね、実際はこうでした。

画像7

最後にもう一度F10を押し、*pointer = 0;を実行します。メモリの0x005cfb73は0になりましたね。さらに、左下のウィンドウのsample変数の中身も0になっています。当然ですね、sampleは0x005cfb73番地に配置されていて、0x005cfb73番地に0を入れているのですから、sampleの中身は0になります。

ステップ実行4

まとめ

ポインタの基本的な説明は以上です。どうでしょう?理解できましたかね?これがC言語最難関のポインタです。ガチャガチャを例にするのは聞いたことないですが、イメージは合っているはずです。メモリとアドレスと変数の関係については、前からずっと触れて来ているので、それを理解している方なら案外すんなり行けたかも知れませんね。今回の内容がパーフェクトに消化できれば、もう勝ったようなもの。一気にCの世界が開けます。

そして、理解できた方が思うのは、「で?なんでこんな回りくどいことすんねん?」でしょうね。sampleに0入れたきゃ、sample = 0;でええがな。仰る通り。今回のはあくまでも説明用のサンプルですから。本来、こんなことがしたいんじゃない。次から実践編に入ります。

この記事が気に入ったらサポートをしてみませんか?