CやC++において重要なポインタについてのメモ。
ポインタについて
ポインタを理解するために、変数やメモリの仕組みから順を追って説明します。
変数のアドレス
すべての変数はメモリに記憶される。その記憶されたメモリの位置を16進数で表したものがアドレス。変数のアドレスはアドレス演算子 & でアクセスできる。
- サンプルコード
-
[code]
#include
using namespace std;int main(int argc, const char * argv[])
{
int val = 10;cout << "変数valの値 : " << val << "\n"; cout << "変数valのアドレス : " << &val << "\n"; return 0; } [/code]
- 結果
-
[code]
変数valの値 : 10
変数valのアドレス : 0x7fff5fbff86c
[/code]※アドレスの値は環境により異なります。
ポインタの宣言とアドレスの格納
上記のアドレスを格納する変数が「ポインタ」。ポインタは型の後に*(アスタリスク)を使用し宣言する。
アスタリスクの位置はポインタ名の直前でも構わないが、後述する関節演算子と区別するため、ここでは int* とする。
- サンプルコード
-
[code]
#include
using namespace std;int main(int argc, const char * argv[])
{
int val = 10;
int* pVal = &val; // int *pVal = &val;でも構わないcout << "変数valの値 : " << val << "\n"; cout << "変数valのアドレス : " << &val << "\n"; cout << "ポインタpAの値 : " << pVal << "\n"; return 0; } [/code]
- 結果
-
[code]
変数valの値 : 10
変数valのアドレス : 0x7fff5fbff87c
ポインタpValの値 : 0x7fff5fbff87c
[/code]
ポインタから変数の値にアクセスする
ポインタに変数のアドレスが格納されると、ポインタに 関節演算子 * を使用することで変数の値にアクセスすることができる。
- サンプルコード
-
[code]
#include
using namespace std;int main(int argc, const char * argv[])
{
int val = 10;
int* pVal = &val; // int *pVal = &val;でも同じcout << "変数valの値 : " << val << "\n"; cout << "変数valのアドレス : " << &val << "\n"; cout << "ポインタpValの値 : " << pVal << "\n"; cout << "*pValの値 : " << *pVal << "\n"; return 0; } [/code]
- 結果
-
[code]
変数valの値 : 10
変数valのアドレス : 0x7fff5fbff87c
ポインタpValの値 : 0x7fff5fbff87c
*pValの値 : 10
[/code]※int* 型の pVal というポインタを作成し、ポインタ pVal の値には *pVal でアクセスしていると考える。
ポインタから変数の値を変更する
関節演算子 * を使用しポインタに値を代入すれば、参照先の変数の値を変更することができる。
- サンプルコード
-
[code]
#include
using namespace std;int main(int argc, const char * argv[])
{
int val = 10;
int* pVal = &val;cout << "変数valの値 : " << val << "\n"; *pVal = 100; cout << "変数valの値 : " << val << "\n"; return 0; } [/code]
- 結果
-
[code]
変数valの値 : 10
変数valの値 : 100
[/code]
サンプルコードの変数とポインタの関係
val | 変数val |
&val | 変数valのアドレス | pVal | ポインタ(変数valのアドレスが格納されている) | *pVal | ポインタが指している変数(=変数valの値) |
補足説明
- int型のポインタ val を宣言するときは int* pVal; もしくは int *pVal; となる。このときの *(アスタリスク)はポインタの宣言を意味する記号であって、関節演算子を意味するものではない。
まとめ
C や C++ を基礎から勉強しないまま Objective-C でコーディングしていたため、変数名の前に*が付いているとポインタだと思っていましたが、この考えは正確には間違いでした。
[code]
int* pVal; // もしくは int *pVal;
pVal = &val;
[/code]
最近まで、なぜポインタ宣言のルールが統一されていないのかがずっと疑問でした。
「int型のポインタを宣言する」と考えれば int* pVal; となります。
ポインタの用途を考えれば、格納されているアドレスの16進数は人間にとって意味はなく、「同じアドレスを持つの変数の値を変更させる」使い方がポインタの役割と考えれば、宣言時にはポインタ使用時と同じ表記である int *pVal; を使用する方がスマートに感じます。
コーディングする人の考え方によって、どちらも間違っていないのですが、ポインタにアドレスを代入する際は関節演算子*を使用しないので、これがポインタをわかりにくくさせる原因の一つでした。
たった一文字の記号が左にあるか右にあるかで、その人の性格がでてしまうものなんですね。