前のレッスンで、メモリのロッカーには1つずつ番地が振られていると学びました。ここでは、その番地がいつ・どうやって決まるのかを見ていきます。
番地は変数を作った瞬間に決まる
int a = 10; と書くと、コンパイラとOSが協力して「この変数はここに置く」という場所を決めます。プログラマは番地を指定しません。空いているロッカーを係の人が割り当ててくれる、と考えてください。
決まった番地は、そのプログラムが動いているあいだ変わりません。ただし次に実行したときは別の番地になることがよくあります。番地の値そのものを覚えることに意味はなく、大事なのは「どの変数がどこにいて、誰と隣り合っているか」という関係のほうです。
変数の番地は「先頭のロッカー」の番地
int は4バイト、つまりロッカー4個ぶんを使います。では a の番地はどれを指すのでしょうか。答えはいちばん小さい番地(先頭のロッカー)です。
たとえば a が 0x1000 番地から始まるなら、a は 0x1000・0x1001・0x1002・0x1003 の4個を占領し、a の番地は 0x1000 です。そして次に作られる int b は、その先の 0x1004 に置かれることが多くなります。
int a = 10; // 0x1000 から4バイト
int b = 20; // 0x1004 から4バイト
char c = 'X'; // 0x1008 から1バイト隣り合う int の番地の差が4になるのは、int が4バイトだからです。番地の差=そのぶんのバイト数という感覚は、この先ずっと使います。
ただし、変数がこの順に隣り合って並ぶ保証はありません。コンパイラは速度のために順番を入れ替えたり、すきま(パディング)を入れたりします。確実なのは配列だけで、配列の要素は必ず隙間なく連続して並びます。ふつうの変数どうしの位置関係は「たいていこうなる」程度に受け取ってください。
変数が積まれていく様子を見る
言葉だけでは掴みにくいので、メモリの図で実際に積まれていく様子を見てみましょう。「1行すすめる」で1行ずつ進みます。
この教材の図では、番地を 0x1000 から始まる読みやすい値で書きます。本物の番地は 0x7ffd5a20 のようにもっと長く、動かすたびに変わります。本物の桁数を並べても読みにくいだけで、学ぶうえで大事なのは「どれとどれが同じ番地か」「となりとどれだけ離れているか」だけだからです。ヒープ側の箱の番地は 0x8000 から始まります。
関数が終わると番地は返される
メモリの図の最後で、main が終わると変数の箱がまとめて消えたはずです。使い終わったロッカーは「空き」に戻り、次に誰かが使えるようになります。中身が消毒されるわけではなく、次の人が上書きするまで古いデータが残っているという点も覚えておいてください。この性質が、のちのちバグの温床になります。
まとめ
番地は変数を作った瞬間に割り当てられ、実行のたびに変わりえます。変数の番地は先頭バイトの番地を指し、隣の変数との差はサイズと一致します。番地は「覚えるもの」ではなく「調べて使うもの」です。