バナナでもわかる話

計量経済学・統計学が専門の大学院生です。統計学・経済学・投資理論・マーケティング等々に関する勉強・解説ブログ。ときどき趣味も。極力数式は使わずイメージで説明出来るよう心掛けていますが、時々暴走します。

C言語のポインタとは何かを簡単にまとめておく

前お知らせした通り、C++練習中です。

スポンサーリンク


他のプログラミング言語とC言語の大きな違いは「ポインタ」という概念があることらしく、私自身もそうですが、「ポインタ」で躓く人がとても多いとのことで、初心者ながらに理解したことをまとめておきます。
ちなみに次の本を参考にしてます。

メモリ

まず、ポインタを理解する前に"メモリ"を理解する必要があります。
どうやらメモリとはコンピュータの中に一時的に保存できる場所のことを指すようです。

例えばX=5みたいなものをコンピュータ上で考えた場合には、
Xが5ですという情報は当然パソコンのどこかに保存されているはずですよね。

その保存先をメモリと呼びます。


メモリの住所

で、X=5をメモリのどこかに保存したとしましょう。ただメモリ自体は保存する場所がたくさんあって、何か印が無いと区別がつきません。
そのため、各メモリには場所を示す目印がついています。

地図上の住所みたいなものを想像してもらえるとわかりやすいかもしれません。
タカシ君の家に行きたいけど、場所がわからない。そこで住所を頼りにたどり着きましたってことは、まあよくありますよね。

メモリにもしっかり住所があります。


X = 5 と保存したとして、Xの保存先を確認するにはどうしたらよいでしょう。その際に用いるのが&です。

C++でコードを書いてみます。

#include "pch.h"
#include <iostream>
using namespace std;

int main()
{
	int X;
	X = 5;
	cout <<"Xが保存されているメモリの場所は"<< &X <<"です。"<< endl;
}

出力はこんな感じ

Xが保存されているメモリの場所は0114F7C0です。

メモリの場所を確認することが出来ました。



ポインタ

それでは本題に入ります。ポインタとは、このメモリの場所(住所)を保存しておくもののことを指します。

どうやって書くかというと、Xがint型だったので、intで指定し、ポインタであることを示すために「*」をつけます。そしてポインタの名前を適当に決めてやり、そこに&Xを代入するという形をとります。

こんな感じ。

#include "pch.h"
#include <iostream>
using namespace std;

int main()
{
	int X;
	X = 5;
	int * px;
	px = &X;
	cout <<"Xが保存されているメモリの場所は"<< px <<"です。"<< endl;
}

出力はこんな感じ

Xが保存されているメモリの場所は00EFFBA0です。

さっきと場所が変わっているじゃないか!っていうのは、すみません。再度コードを実行しなおしたため、場所が変わっています。



ちなみにメモリの場所はポインタでないと入れることが出来ません。試しに次のようにしてやると

	int Y;
	Y = &X;

エラーを吐きます。

エラー (アクティブ)	E0513	型 "int *" の値を型 "int" のエンティティに割り当てることはできません


んで、次がちょっとややこしいのですが、さっきのコードの下の部分をもう一度確認していただきたいのですが、こんな風になっていたはずです。

	cout <<"Xが保存されているメモリの場所は"<< px <<"です。"<< endl;

「ん?&Xが放り込まれたのはpxではなく *px じゃないのか?」

と思う方もいらっしゃるかと思います。実は、*pxにはそのメモリの住所に入っている変数、つまりX = 5が入っています。
念のため次のようにして実行すると

#include "pch.h"
#include <iostream>
using namespace std;

int main()
{
	int X;
	X = 5;
	int * px;
	px = &X;
	cout <<"Xが保存されているメモリの場所は"<< px <<"です。"<< endl;
	cout << "*pxは" << *px << "です。" << endl;
	cout << "X=" << X << endl;
}

出力はこんな感じ。

Xが保存されているメモリの場所は00D3FA74です。
*pxは5です。
X=5

まとめると、ポインタは変数の住所を取り込んで、その住所から変数も読み込むことができる

まず、ポインタを使う時は、他の変数と区別してポインタであることを示すために「*」付きで読み込む
次に変数の住所をポインタに入れる時は、*無しで入れる。
そして、中の変数を読み込みたい時は*付きポインタでいける。

って感じですね。


ポインタの利用

まず、ポインタを使ってXに値を代入することが出来ます。

#include "pch.h"
#include <iostream>
using namespace std;

int main()
{
	int X;
	X = 5;
	int * px;
	px = &X;
	*px = 10;
	cout <<"Xが保存されているメモリの場所は"<< px <<"です。"<< endl;
	cout << "*pxは" << *px << "です。" << endl;
	cout << "X=" << X << endl;
}

出力結果

Xが保存されているメモリの場所は010FFC28です。
*pxは10です。
X=10

保存されているメモリを操れるというところがポインタの強みです。
例えば、*aというポインタに小数を突っ込んだとして、そこから4×2メモリずれたところに別のポインタ*bを置くことにします。
この時、次のように打つことで上のようなメモリの確保を行うことが出来ます。

#include "pch.h"
#include <iostream>
using namespace std;

int main()
{
	float X;
	X = 0.5;
	float *a ;
//aにXの住所を代入
	a = &X;
//ポインタの指定と住所の代入を同時にやってる。aは住所で、aから4*2だけズラしています。
	float *b = a + 4 * 2;
	cout << a << endl;
	cout << b << endl;
//aとbの住所の差は8なので、そこを差し引きすれば同じものが出てくるはず。
	cout << b - 4* 2;

}

出力はこんな感じ
うまくいってますね。

00AFF860
00AFF880
00AFF860