ポインタというのは、参照先があって初めて参照できます。しかし、あるポインタが参照できるか、できないかが、実際に参照してみるまで分からないというのは困りものです。かといって、いちいちフラグ(第49章参照)用の変数を別に作るのも面倒です。今回は、そういう話です。
以下が、今回の要点です。
では、いってみましょう。
ポインタは必ず参照先を指定してから参照しなければなりません。しかし、実際にはポインタを宣言してすぐに参照先を指定するような場合ばかりではありません。
参照先をまだ指定していない段階でこのポインタが使われる恐れがあるときは、そのポインタが使えるかどうかを判別して、分岐処理を行う必要があるでしょう。
しかし、初期化していない変数には何が入っているか分かりません。たまたま参照できるようなアドレスが入っている場合もあるので、実際に参照してみてエラーが出るかどうかで判定することもできません。
かといって、「こんなアドレスはないだろうなぁ」という適当な値で初期化しても、もしかしたらそういうアドレスがある可能性もあり、確実ではないです。
そこで、「どんなオブジェクトや関数のアドレスと比較しても等しくならないことが保証されているアドレス」というものが存在します。そのようなアドレスを示すポインタをヌルポインタと呼びます。プログラム上得られうる全ての有効なアドレスと等しくならないわけですね。このヌルポインタで初期化しておけば、ヌルポインタかどうかの判定で、ポインタの使用・未使用が判別できるわけです。
ヌルポインタの値はソース上では 0 です。しかし、実際の値が0であるという保証はありません。
例)char* p = 0;
つまり、0 とは単にヌルポインタを表す記号な訳です。
例えば、次のような文があったとします。
char* pNull = 0;
さて、pNull が 0 で初期化されています。ヌルポインタの値はソース上では 0 です。つまり、pNull はヌルポインタになりました。アドレスが pNull と等しくなるようなオブジェクトは存在しないわけです。
しかし、pNull に入っている値も0であるとは限りません。これは、環境に依存します。
ちなみに、大体の環境ではアドレスも0になるでしょう。しかし、0にならない環境もあるということは、きちんと頭に入れておく必要があります。実は、型が違えばアドレスの値が変わるような環境もあるそうです。それを踏まえた上で、「対象とする環境では必ず0になるから、0であるとしてプログラムを組もう」というのは、許されることかもしれません。普通にWindowsプログラムをする分には、気にすることはないでしょう。
C/C++言語はどんな環境で使われるか分かりません。でも、どんな環境で使われたとしてもヌルポインタは0ですむようになっているわけです。ヌルポインタの値が0でないことも想定したプログラムは、どんな環境でもきちんと動くわけです。
さて、ヌルポインタには、ヌルポインタを示すマクロが用意されています。それは第51章で出てきた NULL です。
NULL はプログラムを読みやすくするために使うわけであり、NULL が 0 に置き換わるとしても、ただの 0 の代わりとして使うわけにはいきません。間違っても
int i; for(i = NULL; i < 9; i++)
などということは、絶対にしないようにして下さい。(まぁ、しないとは思いますけど。)
それに、NULL は ((void*)0) と定義されていることもあるそうです。ポインタ以外の変数への代入ができないようにしているのでしょう。(この形にはいろいろ批判があります。NULL マクロ自体にもいろいろ批判があります。が、詳しいことは専門書、別HPなどに任せます。void* についても、第3部で話します。)VC++では、C言語を使うときは ((void*)0) 、C++を使うときは 0 となっているようです。
ヌルポインタは「どんなオブジェクトや関数のアドレスと比較しても等しくならないポインタ」です。NULL か、NULL でないかで処理を分けることができるわけですが、これにはいろいろな意味を持たせることができます。
例えば、以下のようなことができます。
実際に、fopen では関数が失敗すると NULL が返ってきましたし、strtok という関数では NULL を渡すと特別な処理をするようになっています。
このように、ヌルポインタはフラグ代わりに使用できるわけです。
今回はこれでおわりです。では、要点を見てみましょう。
地味な章でしたが、たまにはこんなのもいいでしょう。では、次回まで。
Last update was done on 2000.7.26
この講座の著作権はロベールが保有しています