第十九話 ポインタ演算
「ポインタで足し算とかできるんですか?」
俺が尋ねると、立花先輩は頷いた。
「そう。ポインタ変数っていっても、中の値はただのアドレス値でしょ? だったら、その値を足したり引いたり出来ても不思議じゃないじゃない」
「うーむ。そう言われると……」
「ただ、ちょっと普通の変数と違うのは、1足したら、アドレスが1バイト進むとは限らないのよ。ポインタ変数の型のバイト分、進むわけ」
「なっ!?」
「うーん。これはプログラムで検証してみると、わかりやすいかなー」
先輩はメモ帳にコードを書き始めた。
/* ポインタ演算の検証 addpointer.c */
#include<stdio.h>
int main(void)
{
int a[3], *pa; /* こういう風に同時に宣言もできるよ。 */
a[0] = 1;
a[1] = 3;
a[2] = 5;
pa = &a[0]; /* 配列に限り、pa = aでもok */
printf(“a[0]のアドレス : %p ¥n“,&a[0]);
printf(“a[1]のアドレス : %p ¥n“,&a[1]);
printf(“a[2]のアドレス : %p ¥n¥n“,&a[2]);
printf(“paの値 : %p ¥n“,pa);
pa++; // ポインタ演算
printf(“paの値(1足した後) : %p ¥n“,pa);
printf(“paの指しているアドレスの値 : %d ¥n“,*pa);
return 0;
}
「それでは実行するよー。配列aには、1、3、5が入っているけど、ポインタのアドレスの動きをよく見てね」
先輩はプログラムをコンパイルすると実行した。
C:¥sample>addpointer
a[0]のアドレス : 0022FF10
a[1]のアドレス : 0022FF14
a[2]のアドレス : 0022FF18
paの値 : 0022FF10
paの値(1足した後) : 0022FF14
paの指しているアドレスの値 : 3
C:¥sample>_
「4進んでますね……」と西原さん。
「そういう事ね。このポインタはint型だから、4バイト分進むわけ」
「うーむ。変な機能だな……」
「でも、こうすると、次の配列インデックス、この場合はa[1]のアドレス値に自動的にセットされるから便利でしょ。もし1バイトずつしか移動出来なかったら、次の配列の値を知る為に、プログラマがわざわざ4足したりして計算しないといけないじゃない」
「あ、そういうことか」
「しかも、このプログラムを実行するコンピューターのintの型が4バイトとは限らないから、さらにややこしくなるし」
「なるほど、それじゃ、この機能も必要ですね」と西原さんも頷く。
「ただ、こういうポインタって、バグの元になるから、扱いには充分に気をつけてよ。Cだとポインタの指しているアドレスが間違ったら、簡単にプログラム暴走するからー」
「ポインタは悪名高いですものね……」と西原さん。「Javaだと最初から使えないようにしているし、私が勉強しているC#だと、コンパイラに特別なオプション/UNSAFEを入れないと使うことが出来なくなっているし」
「ほとんど最高封印の禁呪扱い。でも、ポインタそのものは、悪い機能じゃないわ。ちゃんと使える能力のあるプログラマが少ないだけ。イツキくんと西原さんは、大丈夫よ。恐れることなく使っていって」
「そ、そうなのですか?」
「そう。ポインタは怖い、怖い、って恐れていたら、Cをマスターする事は永遠に無理よ。失敗を恐れてたら、永遠に先には進めない。きっと、何度となくポインタのメモリーバグでイツキくんは痛い目に遭うだろうけど、そのたびにポインタの使い方──ううん、メモリーアドレスの使い方に熟達していく。それが、プログラマにとっての経験っていう財産になるのよ」
「はい」
先輩が真剣に俺に何かを伝えようとしている事がわかって、俺も真剣な表情で頷く。
ポインタ、か。
「これからデータ構造の話とかもしていくけど、こういうのを作るのにポインタは不可欠だからね。よーく復習しておきなさいよ。じゃ、今日は遅いから、これくらいにしておくわ」
時計を見ると、結構遅い時間になっていた。
俺は立ち上がった。先輩はPCの電源を落としている。
「先輩、今日は、かなりコンピューターについて勉強しましたよ」
「ふふっ。明日は、これらの知識を使って、いよいよゲーム作りに入ってもらうわよ」
「イツキくん、頑張ってね!」と西原さんからも言われる。
ぷ、プレッシャーが。
「うっ。……か、簡単なのにしていいですか?」
「ぷぷっ。もう。さっそく恐れている」
「くすくす」
俺の言葉に先輩と西原さんは笑った。