ポインタについて

C言語初級カテゴリのロゴ画像C言語初級
スポンサーリンク

結論から言うと、ポインタ変数を使うと別の変数の内容を参照できます。
さらに大きな結論を言うなら、C言語を勉強するならポインタまで勉強しないと損です。

C言語を勉強しているとポインタという言葉に出くわします。
ポインタは、C言語を自由に扱う上で欠かせない要素です。憶えておくとプログラムからデータを扱うときにより効率的なプログラムが組めるようになります。
スポンサーリンク

ポインタを使った簡単なプログラム

次のサンプルを見て下さい。

pointer.c

/* pointer.c: ポインタについて */
#include <stdio.h>
int main(void)
{
	char x = 10;
	char *p;
	
	printf("x = %d\n", x);
	p = &x;
	printf("*p = %d\n", *p);
	
	return 0;
}

実行結果

x = 10
*p = 10

解説
C言語の変数には、整数型(int, short, long)、実数型(float, double)、文字型(char)と6種類ありますが、もう一つ別の型が存在します。

ポインタ型変数の定義方法は、変数名の前に「*」(アスタリスク)をつけるだけです。
上記サンプルでは6行目で定義しているのがポインタ型変数です。

char *p;

定義方法は、もう一つあって、

char* p;

としてもOKです。

変数型の後に*をつけるか、変数名の前に*をつけるかの違い。
本記事では、変数名の前に*をつけさせて頂きます。

この場合、変数pはchar型変数のメモリ上の番地を保存できる変数pという意味になります。良く分かりませんよね(笑)わたしも最初は全く分かりませんでした。
平たく言うと、ポインタ型変数は、メモリ上の番地しか保存できない変数ということです。
数値や文字などが保存できる変数とは考え方が違います。

実際にメモリ上の番地を表示させてみる

先ほどから番地番地と連呼しているので、実際どんな番地なのかを表示させてみます。

address.c

/* address.c: 番地を表示させてみる */
#include<stdio.h>

int main(void)
{
	char a, b;

	printf("変数aの番地: %p\n", &a);
	printf("変数bの番地: %p\n", &b);
	
	return 0;
}

実行結果

変数aの番地: 0019FF4B
変数bの番地: 0019FF4A

変数の番地&aなどの情報は、printfの書式指定文字%pを使うことで表示出来ます。
この場合、16進数で表示されます。上記例だと16進数0019FF4Aを10進数に直すと1703754番地といった感じですね。

char型は、1バイト幅の変数なので、きちんと1番地違いでアドレスが振られていることが分かります。(最初に宣言した変数aの方の番地番号がなぜか後になっていますね。理由はわたしには分かりません!)

ポインタ変数宣言時の注意点

ポインタ変数の型を決める場合は、ポインタ変数に代入する変数型を合わせる必要があります。

int x;
int *p;

と宣言した場合、変数pは、int型の変数のメモリ上の番地を格納する変数という意味になり、

p = &x;

は可能ですが、

int x;
double *p;

とした場合、変数pは、double型の変数のメモリ上の番地を格納する変数という意味になり、
p = &x;はコンパイル時に警告が出ます。型が一致しないからです。

ポインタ変数に何が代入出来るのか?

例えば変数xを宣言した際のメモリ上の番地が1000番地だったとします。
C言語では、「&」記号(アンパサント記号)を変数の前につけることで宣言した変数のメモリ上の番地を表現することが出来ます。

&x

は1000番地という意味です。

9行目でp = &x;としています。
変数pは、ポインタ型変数です。
ポインタ型変数は、整数や文字を代入できる変数ではありません。あくまでメモリ上の番地情報しか代入できません。
先ほどの例で変数xの番地を1000番地としました。

ですからp = &x;を実行後の変数pは、1000番地という情報が代入されたことになります。

ここまでのイメージを数枚の画像で示します。
コンピュータの5大装置の1つである主記憶装置(通常RAMと呼ばれる)のイメージが頭にないと少し理解しにくいのでまず初めに通常の変数が宣言されたときのイメージを示します。

ポインタ理解の為のイメージ図

メモリ(主記憶装置)の状態

ポインタについてのイメージ画像
主記憶装置(以下メモリと記述)には、データの保存ができます。取り出しやすいように番号が振ってあります。
これを番地と呼んでいます。(図の番地番号はあくまで仮のイメージです)

メモリには空いている箇所があり、通常はアプリを起動したときこの空き番地の箇所にアプリプログラムがコピーされます。
変数を宣言したときもこの空き番地が利用されます。(どの番地にするかはOSが自動でやってくれます)
図では1000番地を変数xの領域として設定しています。宣言しただけでは内容は何が入っているか分かりません。
以前の状態がそのまま残っている可能性もあります。

C言語では変数宣言後に自分から初期値設定を行わない限りは、何が入っているか分かりません。

試しに次のプログラムを実行してみると分かります。

int x;
printf(“x = %d\n”, x);

変な数値が表示されると思います。-100かもしれないし、25678かもしれません。
C言語は、最近のプログラミング言語と違って変数の初期値を0クリアしてくれません。(C言語を学ぶと自然とメモリを意識するようになるのはこのためです

変数に代入する時のメモリ(主記憶装置)の状態

次に変数に値を代入したときのイメージです。
ポインタについてのイメージ画像

x = 10;

とした場合、先ほどの変数xの1000番地に10が保存されるのですが、10は10進数です。
メモリ上は、あくまで2進数として保存されます。
図のchar型であれば、8ビットで数値を表現するため

00001010

という2進数が1000番地の内容として保存されることになります。

ポインタ変数の宣言と代入した際のメモリ(主記憶装置)の状態

最後にポインタ変数のイメージです。

ポインタについてのイメージ画像

int *p;

とした場合、メモリの空き部分にポインタ変数pの領域が確保されます。(便宜上変数xの次の番地にしました)
しつこいようですが、変数pはポインタ型変数のため、番地情報しか保存できません。

p = &x;

として変数xの番地を保存しています。
pには、1000番地という情報が保存されたことになります。

ポインタ変数は、他の変数の内容を参照できる!

ポインタ変数の面白い所はここからです。
ポインタ変数は、その変数に代入されている番地の内容を取り出すことも出来ます。
p = &x; とした場合、pには、変数xの番地である1000番地という情報が保存されています。

*p

とすることで、1000番地の内容、すなわち変数xの内容を取り出すことが出来るのです。
したがって、

printf(“*p = %d\n”, *p);

変数xの内容である10が表示されることになります。
あたかもポインタ変数pを通じて変数xを遠隔操作している感じです。
これがポインタ変数の機能です。

ポインタまとめ

ポインタ変数には、他の変数のメモリ上の番地情報を代入できる
ポインタ変数を通して、他の変数の内容を参照できる

宣言方法
ポインタ変数を宣言するには、「*」を変数型名の後か変数名の前につける
例)int* x; 又は int *x;

代入方法

int x = 100;
int *p;

と宣言されている場合

p = &x;

として変数xのメモリ上の番地を代入できる

参照方法
p = &x; と代入がされていれば、

*pで変数xの内容を参照できる。

例)
printf(“x = %d\n”, *p);

補足

scanf関数でもポインタの記述は見られます。

int x;
scanf("%d", &x);

上記&xの部分などです。

変数xの番地が指し示す位置にキーボードから入力した内容を代入しなさいということになります。

コメント