アドレスを返す関数を1つ紹介します。
以前、strchrという関数を紹介しました。
文字列の中に指定した文字が入っているかどうか調べる関数です。
strchr関数のプロトタイプ宣言を確認すると、
char* strchr(char* _String, int _Ch); |
となっています。
※分かりやすくするために、省略して表示しています。
引数は、「char* _String」が文字列の先頭番地を渡すポインタ変数です。
「メモリアドレス」にも書いてありますが、配列には連続したアドレスが割り当てられています。
配列を関数に渡すには、配列の先頭のアドレスを渡すようになります。
※これは後ほど詳しく書きます。
もう1つの引数「int _Ch」が探したい文字です。
文字ならchar型では?と思いますが、今は気にしないでください。
そして、戻り値は「char*」です。
「char型のアドレスを返す」という意味です。
どのようなアドレスが返ってくるのか、実際にプログラムを実行しながら確認しましょう。
まずは文字列を用意して、それぞれの番地を確認するプログラムを作成します。
<sample program 137-01>
#include <stdio.h> int main(void) { char str[] = "ABCDE"; int i; for (i = 0; i < 5; i++) { printf("str[%d] Address = %p\n", i, &str[i]); } return 0; } |
<実行結果>
str[0] Address = 00ADFCDC str[1] Address = 00ADFCDD str[2] Address = 00ADFCDE str[3] Address = 00ADFCDF str[4] Address = 00ADFCE0 続行するには何かキーを押してください・・・
※実行結果は毎回変わる可能性があります。
次に、strchr関数を使って文字'C'を探すプログラムを作ります。
以前のプログラムでは、if文の条件にstrchr関数を入れて作りました。
同じ要領で作ってみます。
<sample program 137-02>
#include <stdio.h> #include <string.h> int main(void) { char str[] = "ABCDE"; int i; for (i = 0; i < 5; i++) { printf("str[%d] Address = %p\n", i, &str[i]); } if (strchr(str, 'C')) { printf("ありました!\n"); } else { printf("ありませんでした!\n"); } return 0; } |
<実行結果>
str[0] Address = 00A5FBC8 str[1] Address = 00A5FBC9 str[2] Address = 00A5FBCA str[3] Address = 00A5FBCB str[4] Address = 00A5FBCC ありました! 続行するには何かキーを押してください・・・
※実行結果は毎回変わる可能性があります。
このif文が成り立つ、という事は「0」以外の数値が返ってきているということです。
実際にポインタ変数を追加して受け取ってみましょう。
<sample program 137-03>
#include <stdio.h> #include <string.h> int main(void) { char str[] = "ABCDE"; int i; char *p; for (i = 0; i < 5; i++) { printf("str[%d] Address = %p\n", i, &str[i]); } p = strchr(str, 'C'); printf("p = %p\n", p); if (strchr(str, 'C')) { printf("ありました!\n"); } else { printf("ありませんでした!\n"); } return 0; } |
<実行結果>
str[0] Address = 00B4FE08 str[1] Address = 00B4FE09 str[2] Address = 00B4FE0A str[3] Address = 00B4FE0B str[4] Address = 00B4FE0C p = 00B4FE0A ありました! 続行するには何かキーを押してください・・・
※実行結果は毎回変わる可能性があります。
戻り値を受け取ったポインタ変数pの中には、配列の「C」が入っている番地が入っていました。
strchr関数とは、発見した文字のアドレスを返す関数だったのです。
このアドレスは元々main関数で用意されているアドレスなので、strchr関数が完了しても領域が解放される訳ではありません。
このように安全な状況でアドレスを返す事が出来るのであれば、アドレスを返す関数を作っても問題ありません。
ついでに、見つからなかった場合は何が返ってきているのか確認しましょう。
<sample program 137-04>
#include <stdio.h> #include <string.h> int main(void) { char str[] = "ABCDE"; int i; char *p; for (i = 0; i < 5; i++) { printf("str[%d] Address = %p\n", i, &str[i]); } p = strchr(str, 'G'); printf("p = %p\n", p); if (strchr(str, 'G')) { printf("ありました!\n"); } else { printf("ありませんでした!\n"); } return 0; } |
<実行結果>
str[0] Address = 0026FDBC str[1] Address = 0026FDBD str[2] Address = 0026FDBE str[3] Address = 0026FDBF str[4] Address = 0026FDC0 p = 00000000 ありませんでした! 続行するには何かキーを押してください・・・
※実行結果は毎回変わる可能性があります。
当然、if文が成り立たなくなるので「0」が返ってきているのですが、この「0」には意味があります。
C言語の環境によっては「NULL」という定数が用意されていることがあります。
※Visual Studio Community 2015では、「vcruntime.h」で定義されており「stdio.h」などをincludeすると自動的にincludeされます。
この「NULL」は、
#define NULL 0 |
と定義されており、「0」であることが分かります。
意味としては「無効なアドレス」という意味を持っています。
「0番地」という特殊なアドレスで、使えないアドレスということです。
アドレスを返す関数の多くは、失敗した場合などに「NULL」を返す事が多いです。
ファイルの所で、fopen関数も失敗した時に「NULL」を返していましたね。
上のプログラムも「NULL」を使って書き換えると、↓のようになります。
<sample program 137-05>
#include <stdio.h> #include <string.h> int main(void) { char str[] = "ABCDE"; char *p; p = strchr(str, 'D'); if (p != NULL) { printf("ありました!\n"); } else { printf("ありませんでした!\n"); } return 0; } |
<実行結果>
ありました! 続行するには何かキーを押してください・・・