8月25日 3時間目
メモリとポインタの話(続き)
ソースコードにおいて、数値や文字列を直接に記述した定数のこと
変数の対義語であり、変更されないことが確約された記述
C++の仕様では以下のようなものがある
まとめ
という表記法である!(文法ってことよ)
昨日と、前に何回か話した変数に別名を付ける話
こんなコードを書いてみます。
やっていることは。
int a = 5;
//aのメモリ領域(4バイト)を用意し、5で初期化
int *p = nullptr;
//ポインタ変数pを用意し、nullptrで初期化
p = &a;
//pにaのアドレスを代入
①int a;の宣言により、どこか空いているところのメモリアドレスがシステムから提供されそのアドレスに、int = 4byte分のメモリ領域を確保する メモリアドレスは1byteごとに割り振られているので、今0x00001235~0x00001238までの4byte=32bitが確保されている。
name| value | address name| value | address
|________|0x00001234 |________|0x0000123B
a |????????|0x00001235 |________|0x0000123C
|????????|0x00001236 |________|0x0000123D
|????????|0x00001237 |________|0x0000123E
|????????|0x00001238 |________|0x0000123F
|________|0x00001239 |________|0x00001240
|________|0x0000123A |________|0x00001241
②int *p=nullptr;により、たまたま空いていた0x0000123D~0x00001240がメモリアドレス保存用にシステムから提供され、nullptr(数値でいう0、どこのアドレスでもない場所を指すという意味)で初期化される。
nullptrは数値でいう0(=何もないという意味)と同じといったが概念的な話で(とは言えデバッガで値みると0x00000000って書いてるんだよねぇ)、コンパイラやシステムによって0ではなくどこも差していないポインタと解釈されている。
name| value | address name| value | address
|________|0x00001234 |________|0x0000123B
a |????????|0x00001235 |________|0x0000123C
|????????|0x00001236 p |00000000|0x0000123D
|????????|0x00001237 |00000000|0x0000123E
|????????|0x00001238 |00000000|0x0000123F
|________|0x00001239 |00000000|0x00001240
|________|0x0000123A |________|0x00001241
記述の仕方:
宣言が直感的じゃないので混乱するけれども、
型* 変数名 = nullptr;
で、どこかのアドレスを格納するための変数 変数名が用意される
その次にどこも差さないことを明示する呪文としてnullptrが代入される。
(昔は0とかNULLとかを使ってたけど、なんかおかしいよねって気づいた人がいてこうなった。。。)
*はアスタリスク、アスタ、コメとかホシとか読んだりします。
宣言によって自動的にメモリを取ってくれるタイプの変数=普通の変数に対して、
*&変数名*と&を付けることによって変数のある場所の開始アドレスを取得できる。
*&*はアンド、アンパサンドとかよむ
ポインタ変数p(宣言するときは*pのくせに変数として使うときはpである(仕様))
にアドレスを代入してみる
p = &a;
&a => 0x00001235
name| value | address name| value | address
|________|0x00001234 |________|0x0000123B
a |????????|0x00001235 |________|0x0000123C
|????????|0x00001236 p |00000000|0x0000123D
|????????|0x00001237 |00000000|0x0000123E
|????????|0x00001238 |00000000|0x0000123F
|________|0x00001239 |00001235|0x00001240
|________|0x0000123A |________|0x00001241
ところで、現在変数 a は初期化されていないため値が確定しいない。
このままでは値の参照はできない。
(std::cout « a « std::endl; とかすると値が入ってないのでエラーになる)
a = 105; //0x00000069 0...01101001
&a => 0x00001235
name| value | address name| value | address
|________|0x00001234 |________|0x0000123B
a |00000000|0x00001235 |________|0x0000123C
|00000000|0x00001236 p |00000000|0x0000123D
|00000000|0x00001237 |00000000|0x0000123E
|01101001|0x00001238 |00000000|0x0000123F
|________|0x00001239 |00001235|0x00001240
|________|0x0000123A |________|0x00001241
aに値が代入され、参照できるようになった。
ポインタ変数は変数などがある領域の開始アドレスが格納されているが、そのアドレスの中にある2進数の値が何なのかを参照するためには、
*変数名、この場合は *p と書く。
そうすると、p = 0x0…01235 = &a なので、
*p = ( 0x0…01235のアドレスに格納されている値)= aの値 = 0x0…..01101001
となり、指定されたアドレスにある値を参照することができる。