学生向けプログラミング入門

学生向けにプログラミングを解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails

C++プログラミング入門その17 ポインタ(pointer)を使用したプログラム(2020年3月更新)

<<前  [TOP]  次>>


Visual Studioで新規プロジェクトを作り、次のcppファイルを作成して下さい。


【PointerTest1.cpp】

#include <iostream>
#include <stdlib.h>

int main() {

	int a, *pa;
	float x, *px;

	a = 9; x = 2.5;
	pa = &a;
	px = &x;

	std::cout << "変数a のアドレスは、" << pa << "です。" << std::endl;
	std::cout << "変数x のアドレスは、" << px << "です。" << std::endl;

	pa++;
	px++;

	std::cout << "変数a の次のアドレスは、" << pa << "です。" << std::endl;
	std::cout << "変数x の次のアドレスは、" << px << "です。" << std::endl;
}



コンピュータでは変数の値はすべて「メモリ」に格納されています。
C++ではメモリの位置を直接表す「ポインタ」という機能が用意されています。


この格納されているメモリの位置を表すのが「アドレス」と呼ばれるものです。


変数の値が格納されているメモリのアドレスを知るには、アドレス演算子の「&」を使います。

& 変数名

アドレスは16進数で表示されます。


例えば

int a=5;

として

cout << &a << endl;

とすれば変数 a のアドレスを表示することができます。


このようにアドレスを使ってメモリ上の「位置」を表すことができます。


次に「ポインタ」について説明します。


ポインタはアドレスを格納するための特殊な変数のことです。
まずポインタの宣言の仕方について見ていきましょう。

型名 *ポインタ名;


例: int *pa;

この例の意味は「int型の変数のアドレスを格納できるポインタ変数 pa」となります。


使い方は次のようになります。
1.ポインタを宣言します。「int *pa;」
2.変数aのアドレスをpaに格納します。「pa = &a;」


このアドレスはインクリメントやデクリメントすることで次のアドレスやすぐ前のアドレスを知ることもできます。
もちろん「pa+1」などとしても同じです。


サンプルプログラムをビルドして実行してみましょう。


PointerTest1.cpp実行結果
PointerTest1.cpp実行結果


Visual Studioで新規プロジェクトを作り、次のcppファイルを作成して下さい。


【PointerTest2.cpp】

#include <iostream>
#include <stdlib.h>

int main() {

	const char *s="abcde";
	const char *p;

	for(p=s; *p!='\0'; p++){

		s++;
	}

	p=s-1;
	std::cout << "最後の文字は " << *p << std::endl; 

}



文字型(char型)のポインタ変数がどの様に扱われるかを説明します。


文字型のポインタを使えば文字列を表すことができます。
文字列とは「こんにちは」や「this」などといった文字の集まりのことで、コンピュータでは「文字」とは区別されます。


文字はシングルクォーテーション(’’)で囲んでいたのに対し、文字列はダブルクォーテーション(””)で囲み宣言します。

const char *s="abcde";

これにより文字型のポインタ変数s に文字列「abcde」が格納されました。
「const」を指定することによりポインタ変数の書き換えを禁止しています。
文字列をポインタ変数に格納する場合、「const」を指定せずに書き換えを許可してしまうとコンパイル時に「error C2440: '初期化中': 'const char [6]' から 'char *' に変換できません。」というようなエラーが出ます。


このまま「std::cout << *s << std::endl;」としたら「a」としか出力されません。
何故そのようになるのでしょうか。


文字型のポインタ変数 s にはアドレスが入っています。
文字列を代入する場合、ポインタ変数には一番最初の文字のアドレスのみが格納されます。


「std::cout << *s << std::endl;」の 「*s」の意味は、アドレスが示す変数を表示するという意味なので「a」のみがが出力されるわけです。


「std::cout << s << std::endl;」の様にすれば文字「a」が入っているアドレスを16進数で表示できます。


では残りの「bcde」はどこへ行ったのでしょうか。
実は「b」は「a」の次のアドレスに、「c」は「b」の次のアドレスに格納されているのです。


ですから、s+1としてから「std::cout << *s << std::endl;」を実行すれば「b」が出力されます。


C言語では文字列の終わりを表す印として「¥0」という目印を最後に書き込む決まりになっています。
「char *s="abcde";」としても実際は「abcde¥0」になっているのです。


このサンプルプログラムはそのことを利用して最後の文字のみを出力します。


for文で文字が¥0になるまでアドレスsをインクリメントしていきループさせます。
そして「*s='¥0'」になったらループを抜けます。


ここでアドレスsは最後の文字「¥0」を指していますので、もう一つ用意していた空のポインタ変数pに「p=s-1」として一つ前のアドレスを代入します。
この一つ前のアドレスはもちろん「e」のことですから「std::cout << *p << std::endl;」の結果は「e」となります。


サンプルプログラムをビルドして実行してみましょう。
最後の文字は e と画面に出力されます。


PointerTest2.cpp実行結果
PointerTest2.cpp実行結果


Visual Studioで新規プロジェクトを作り、次のcppファイルを作成して下さい。


【PointerTest3.cpp】

#include <iostream>

int main() {

	int a = 5;
	int b = 10;
	int *pa;

	pa = &a;

	std::cout << "変数a の値は" << a << "です。" << std::endl;
	std::cout << "ポインタpaの値は" << pa << "です。" << std::endl;
	std::cout << "*paの値は" << *pa << "です。" << std::endl;

	pa = &b;

	std::cout << "変数b の値は" << b << "です。" << std::endl;
	std::cout << "ポインタpaの値は" << pa << "に変更されました。" << std::endl;
	std::cout << "*paの値は" << *pa << "です。" << std::endl;
}



このプログラムでは、アドレスのみを代入し直していますが、ポインタ変数の値も変わっているのがわかると思います。
この関係はポインタの基本となりますので覚えておいてください。


PointerTest3.cpp実行結果
PointerTest3.cpp実行結果


Visual Studioで新規プロジェクトを作り、次のcppファイルを作成して下さい。


【PointerTest4.cpp】

#include <iostream>

int main() {

	int a;
	int *pa;

	a = 5;
	pa = &a;

	std::cout << "変数a の値は" << a << "です。" << std::endl;

	*pa = 50;

	std::cout << "*paに50を代入しました。" << std::endl;
	std::cout << "変数a の値は" << a << "です。" << std::endl;
}



このプログラムでは「間接参照演算子*」を使ってポインタが示す変数に値を代入しています。
このような仕組みが役立つのはもっと先のことですが、このようなことが出来るということを覚えておいてください。


PointerTest4.cpp実行結果
PointerTest4.cpp実行結果


Visual Studioで新規プロジェクトを作り、次のcppファイルを作成して下さい。


【PointerTest5.cpp】

#include <iostream>
#include <stdlib.h>

int main() {

	const char *s="C++ benkyouchuu";
	const char *p;
	const char *n;

	n=s;

	for(p=s; *p!='\0'; p++){

		s++;

	}

	for (p=s; n!=p; p--) {

		std::cout << *(p-1);
	}
	std::cout << std::endl;

} 



「C++ benkyouchuu」という文字列をポインタで逆順に出力するようにしたプログラムです。


まず*sと*pと*nの3つのchar型ポインタ変数を用意し、*sに「C++ benkyouchuu」という文字列を格納しておきます。
アドレス s は最初、この文字列の先頭「C」を指しています。
空のアドレス n に この先頭のアドレス s を格納しておきます。


その後for文で最後の文字「¥0」までアドレスを進ませます。
次のfor文で、空のアドレスpに 文字列の最後尾のアドレス s を格納し、「std::cout << *(p-1);」として画面に出力していきます。
一つのループがまわるたびに「p--;」としてアドレスpから1を引いていきます。
1を引くとpは一つ前の文字を指すようになります。
nには文字列の先頭のアドレスが入っていますので「n!=p(nとpがイコールでないとき)」はtrueとなりループしますがイコールになったとき、つまりpのアドレスが文字列の先頭のアドレスと同じになったときにループが終了しプログラムも終了します。


PointerTest5.cpp実行結果
PointerTest5.cpp実行結果


<<前  [TOP]  次>>