>>この記事には書き直した新しいページがあります。<<
<<前 [TOP] 次>>
Visual Studioで新規プロジェクトを作り、次のcppファイルを作成して下さい。
【PointerTest1.cpp】
#include <iostream> #include <stdlib.h> void 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などとしても同じです。
サンプルプログラムをビルドしてデバッグしてみましょう。
Visual Studioで新規プロジェクトを作り、次のcppファイルを作成して下さい。
【PointerTest2.cpp】
#include <iostream> #include <stdlib.h> void main() { char *s="abcde"; char *p; for(p=s; *p!='\0'; p++){ s++; } p=s-1; std::cout << "最後の文字は " << *p << std::endl; }
まず、文字型(char型)のポインタ変数がどの様に扱われるかを説明します。
文字型のポインタを使えば、文字列を表すことができます。
文字列とは、「こんにちは」や「this」などといった、文字の集まりのことで、コンピュータでは「文字」とは区別されます。
文字は、シングルクォーテーション(’’)で囲んでいたのに対し、文字列はダブルクォーテーション(””)で囲み宣言します。
char *s="abcde";
これにより、文字型のポインタ変数s に文字列「abcde」が格納されました。
では、このまま 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 と画面に出力されます。
Visual Studioで新規プロジェクトを作り、次のcppファイルを作成して下さい。
【PointerTest3.cpp】
#include <iostream> void 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; }
このプログラムでは、アドレスのみを代入し直していますが、ポインタ変数の値も変わっているのが解ると思います。
この関係はポインタの基本となりますので覚えておいてください。
Visual Studioで新規プロジェクトを作り、次のcppファイルを作成して下さい。
【PointerTest4.cpp】
#include <iostream> void 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; }
このプログラムでは、間接参照演算子* を使って、ポインタが示す変数に値を代入しています。
このような仕組みが役立つのはもっと先のことですが、このようなことが出来るということを覚えておいてください。
Visual Studioで新規プロジェクトを作り、次のcppファイルを作成して下さい。
【PointerTest5.cpp】
#include <iostream> #include <stdlib.h> void main() { char *s="C++ benkyouchuu"; char *p; 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のアドレスが文字列の先頭のアドレスと同じになったときにループが終了し、プログラムも終了します。
<<前 [TOP] 次>>