ポインタのポインタ 疑問に思ったら作ってみる。
cvReleaseImage関数のプロトタイプ宣言はvoid cvReleaseImage( IplImage** );となっている。
静止画像データの開放の関数などは引数にポインタのポインタを渡すようになっている。
例として以下のような流れのコードで説明する。
int main(void){
???????;
IplImage *src_img_gray;//ポインタ変数を作る
????????;
src_img_gray = cvCreateImage (cvGetSize (src_img), IPL_DEPTH_8U, 1);//ポインタ変数が指す実体を作る。実体は静止画像。
????????;
????????;
????????;
cvReleaseImage (&src_img_gray);//実体が入っている先頭アドレスを渡して開放要求を出す。
return 0;
}
上記のコードを説明する。
IplImage *src_img_gray;と静止画像を保存するポインタ変数を宣言し、例えばcvCreateImage関数で実体を作る。
src_img_gray = cvCreateImage (cvGetSize (src_img), IPL_DEPTH_8U, 1);
src_img_grayはポインタ変数なのでアドレスが入るのだが、静止画像を保存する構造体があるメモリの先頭アドレスが入っているはずだ。開放する場合は、このアドレスがあれば開放できる。
さて、
これを開放する時にcvReleaseImage (&src_img_gray);とする。
引数には**が2つある変数を渡さなければいけないのだがsrc_img_grayは*1つ。だから&を付けることで結果的にsrc_img_grayが指しているアドレスを渡すことになる。
この仕組を調べるコードを書いてみる
#include<stdio.h>
void pointer_of_pointer(int **xx){//擬似cvReleaseImage関数
printf("in function xx data:%x **xx data:%x\n",xx,**xx);//xxの中身とxxが指している先のそのまたそこが指している先の値を表示
}
int main(void){
int i,*p,**pp;
i=9;
p=&i;
pp=&p;
printf("i data:%x i address:%x\n",i,&i);//変数の中身と変数のメモリ上のアドレスを表示する。
printf("p data:%x p address:%x\n",p,&p);
printf("pp data:%x pp address:%x\n",pp,&pp);
printf("pointer_of_pointer(pp);\t");
pointer_of_pointer(pp);
printf("pointer_of_pointer(&p);\t");
pointer_of_pointer(&p);
//これはエラー pointer_of_pointer(p);
return 0;
}
実行してみると。
C:\usr\opencv\C_C++の練習\ポインタのポインタ>main.exe
i data:9 i address:12ff70
p data:12ff70 p address:12ff74
pp data:12ff74 pp address:12ff6c
pointer_of_pointer(pp); in function xx data:12ff74 **xx data:9
pointer_of_pointer(&p); in function xx data:12ff74 **xx data:9
C:\usr\opencv\C_C++の練習\ポインタのポインタ>
&pを渡しても、ppを渡しても同じ結果だ。
i変数のメモリイメージ、i変数はコード上ではiという文字列(シンボル)だが、コンパイルして実行可能な状態になる(機械語)と0x12ff70の番地にある4バイト枠(int型)として処理される。
この番地を指しているp変数(p変数の中身は0x12ff70)。p変数はコンパイルして実行可能な状態になる(機械語)と0x12ff74の番地にある4バイト枠(ポインタだから)として処理される。
さらに、pp変数は、p変数のメモリ上の番地を入れている。
i 12ff70番地
p 12ff74番地
pp 12ff6c番地
ものぐさなひとに
関数の引数にポインタを渡すときに変数に&を付けると覚えているひとは、関数の引数にポインタのポインタを渡す必要があるときはポインタ変数に&を付けると覚える。
何でポインタのポインタにするの?
引数をポインタのポインタにすると利点がある?という疑問だ。
さて、main関数の第2引数もポインタのポインタだ。
int main(int argc,char* argv[]{。。。}
または、
int main(int argc,char** argv{。。。}
とも書ける。
第二引数はポインタのポインタだが、この引数にデータを渡すのはWindowsならcmd.exeかエクスプローラだ。cmd.exeとはコマンドプロンプトのこと。これらはシェルと言う。このシェルが引数にデータを渡すのでCコード上での引数の渡し方とは若干違いがあるが最も身近なポインタのポインタの例として説明する。
以下のコマンドmycalcは引数を使って計算する。
C:\Documents and Settings\username>mycalc 10 5
add:15
sub:5
引数の数とそれぞれの引数の長さがわからない場合にポインタのポインタが使える。
cmd.exeやエクスプローラは、引数のリスト4バイトサイズのリストを作る。このリストの個数はargcに入っている。実際に欲しいのは文字列だが、この長さがいろいろだ。だから一旦それぞれの文字列の先頭アドレスの表を作るという考え方だ。これでプログラムからはそのリストを参照することで長さがまちまちで、メモリ上に不規則に配置されている文字列を参照できる。
argv[0]の先頭アドレス |
argv[1]の先頭アドレス |
argv[2]の先頭アドレス |
argv[3]の先頭アドレス |
argv[4]の先頭アドレス |
最終更新:2010年02月22日 10:22