shuto_log.aep

自分がやったことなどを備忘録的な感じで残していこうと思います。

(主にC++の)ポインタ入門

C++でポインタを扱う際の超初歩的な話。
先日学んだノートとして。

ポインタとは

  • ざっくり言うとメモリを直接指し示すもの。
  • 一般に「ポインタ」とは下記の概念の総称である。
    • 「ポインタ型」:ポインタを扱うための型。
    • 「ポインタ変数」:ポインタ型の変数のこと。
    • 「ポインタ値」:変数の物理メモリ上のアドレス。

補足知識とポインタの概要

基本的な話として、コンピュータの物理メモリには1Byte毎にアドレスがふられている。扱えるアドレスはCPUのアーキテクチャによって変わるが、一般に32bitのCPUでは32bitで表現される。32bitは16進数で表すと8桁なので、0x00000000〜0xFFFFFFFF。

変数を宣言すると変数の型に応じたサイズの領域が物理メモリ上に確保される
例えばint型は4Byteの型(実際は環境によって異なる)なので、

int i;

とint型の変数を宣言すると、メモリ上のどこかの4Byte分の領域(例えば0x0F387110番地〜0x0F387113番地)が確保され、その先頭のアドレス(0x0f387110)がiと内部的に紐付けられる。

同様にint型の配列を宣言すると、配列の長さ分のメモリが確保される。

そして普通にiの中身を出力させたいときは

int i = 10;
cout << "i = " << i << endl;
//出力 i = 10

と書く(補足:coutはc++の標準出力でProcessingでいうprintと同じ。printlnは存在しなくて、その代わりにendlという改行記号を使う。<<は文字列の結合であってシフト演算子ではないので注意。)が、

int i= 10;
cout << "&i = " << &i << endl;
//出力 &i = 0x0F387110

というふうに&を付けるとiに紐付けられたアドレス(0x0F387110)を出力することが出来る。

ProcessingとかoFではメモリのアドレスは意識することなくプログラムを書けるようになっているが、ポインタはあえてこのアドレスを直接操作する機能である。
もっと具体的に言うと、この&iで返ってくるアドレスの値こそがポインタ変数に格納されるもの(ポインタ値)である。しかし、ただアドレスを格納するだけじゃなくて、そのメモリの中身のデータも直接いじることができるのがポインタの強みである。
とくに配列を使う時はarray[i]みたいにするんじゃなくてポインタを使ってアクセスした方が速かったりする。

ポインタ型の変数の宣言のしかた

話が戻って宣言のしかたについて。ポインタ型はintやdoubleとかと違って一般に独立的に宣言することが出来ない。「intの値を指し示すポインタ型」とか「doubleの値を指し示すポインタ型」という感じで指し示す先が必要
そして、書き方がサイトによって異なっていてややこしいが、以下のようにしてintの値を指し示すポインタを宣言できる。

int *p;
int* p;

どっちも結果は同じでintの値を指し示すpという名前のポインタ変数を宣言している。*pという名前ではないので注意。

また、これが初見殺しで

int *p, i;
int* p, i;

みたいに複数同時に宣言すると、どっちの表記でもintの値を指すpという名前のポインタ変数と、int型のiという名前の変数を宣言している。
なので前者の方が意味的に分かりやすい。

使い方

先ほどこのポインタ変数は*pという名前ではなくpという名前だと言ったが、ここにもトラップが。
ポインタ変数には2種類の参照方法があり、普通にpと呼んだ場合と*pと呼んだ場合で返ってくるものが異なる。

int i = 10;
int *p;
p = &i;
cout << "p = " << p << endl;
//出力 p = 0x05F83DE0
cout << "*p = " << *p << endl;
//出力 *p = 10

上記のように、pで呼んだ際はアドレスが返ってきて、*pで呼ぶとそのアドレスの指し示すメモリの中身を出力する。
また、ポインタを使って直接メモリの中身を変更することも出来る。

int i = 10;
int *p;
p = &i;
*p += 10;
cout << "*p = " << *p << endl;
//出力 *p = 20
cout << "i = " << i << endl;
//出力 i = 20

「*pで参照できるメモリ」と「iの中身が格納されているメモリ」は物理的に同じものなので、当然iの中身も変更される。int a=b;みたいな値渡しに対して、参照渡しという。

とりあえずこのくらい。こういった内容はググればたくさん出てくるからもっときちんと学んでいきたいと思う。