C言語の分からないところ



DxLibFanに戻る


C言語の初心者がよく躓く所

pointer,ポインター

ポインタって実は私は躓かなかったんですけど、(良書のおかげ)結構躓くとの事ですので、ちと、簡単に説明します。
名前のとおり、指す人(変数)です。
何を指すかというと、メモリのアドレスです。
アドレス等が何なのかは 入門書等に詳しくかかれているので、そこを見てください。
では、メモリのアドレスを指すにはどうすればいいのでしょうか?
以下のプログラムを見てください。

とまぁ、こんな感じです。
実は、この応用として、関数のポインタがあります。

関数のポインタ

ポインタはアドレスを格納するための変数・・・だと言う事はすでに、入門書を見た方なら分かるはずです。
実は、関数のアドレスを格納できる、ポインタもあるんです。え、でも、どんな型?とお思いでしょう。
実は、関数のポインタは定義されていないので、自分で定義する必要があります。 では、以下のような関数があるとしましょう。
int myprintf(const char *str){
	return printf(ptr);
}
で、この関数のアドレスを記憶するためのポインタの宣言は、以下のようにします。
int (* funciton_address)(const char *);
まぁ、こんな風に対応します。↓
image
しかし、
例えば、関数が以下のようになった場合、DxLibのDrawChipMapより、

int DrawChipMap( int MapWidth, int MapHeight, int *MapData, int ChipTypeNum, int *ChipGrHandle, int TransFlag, int MapDrawPointX, int MapDrawPointY, int MapDrawWidth, int MapDrawHeight, int ScreenX, int ScreenY ) ;

いちいち関数のポインタの変数を宣言するのに、

int (*DrawChipMapNoKannsuuNoPointer)( int , int, int *, int , int *, int, int , int , int , int , int, int ) ;

こうしなければならないのは非常に億劫です!!

では、どうすれば・・・
で、ここになって出てくるのは、結構マイナ〜?なtypedefです。
typedefは自分の型を別の名前として登録する役目をするのは入門書に書いていたとおりです。
例えば、さっき出てきたmyprintfは以下のような感じに
typedef int (*FP_MYPRINT_TYPE)(const char *);
でも、なんか、変な宣言の仕方ですよね。私も最初は戸惑いました。
typedefって
typedef int seisuu;
見たいに使うって入門書に書いていますよね。
しかし、関数のポインタをtypedefするには違うみたいですね。
こう覚えちゃうしかないと思います。
で、このtypedefしたものはどう使うんでしょうか?
以下のように使います。
FP_MYPRINT_TYPE function_pointer_name; /* 普通に変数のように宣言できる*/
function_pointer_name = myprintf;/* 関数の名前を=で入れると、アドレスを格納できる。*/

こうすれば関数ポインタの宣言が簡単になります。
そして、ここで一番大切なことは
関数のポインタは関数の名前を=で入れる事によって、アドレスを格納できる。 です。この意義については次のコールバック関数で説明します。

こんばんはコラム
さて、Win32APIを使ったことがある方ならかなり疑問に思っているものが解決すると思います。
何故、WNDPROC型があるか・・・DLGPROC型があるか・・・答えは、関数のポインタの変数を宣言するのを面倒にしないためです。(多分・・・^^;)

コールバック関数

コールバック関数って結構、Windowを表示させるプログラムを組んでいる時はマニュアルとかに出てくる単語ですよね。
私がプログラミングを始めて結構経っても、このコールバック関数の意味がわかりませんでした。
まぁ、関数のポインタを使う意義がここにあるのですけどね^^;
さて、関数のポインタで触れたように関数のポインタは関数の名前を=で入れることによって、 アドレスを格納できました。
もしかしたら、このアドレスから、格納した関数を呼び出すことが出来るんではないか と考えた方がいましたら、正解です。
では、早速見てみましょう。
例えば、普通のintとかのポインタでは,
int *p;
int zittai = 0;
p = &zittai;
*p = 1;
こうすることによって、zittaiの中には1を入れることが出来ましたね。では、関数のポインタでは、
int myprintf(const char *p){return printf(p);}
int main(){
	int (*my)(const char *);
	my = myprintf;
	my("myprintfが呼び出せた");
	
	
	return 0;
}
こんな感じです。成るほど成るほど。(□。□-) フムフム
では、ちと応用です。
#include 
#include 
void myoutputdebugstring(const char *s){
	int i;
	for(i=0;i<6;i++){
		OutputDebugString(s);
	}
}
void myprintf(const char *s){
	int i;
	for(i=0;i<6;i++){
		printf(s);
	}
}

int main(){
	/*myprintfで*/
	myprintf("6回表示したいの〜〜");
	/*OutputDebugStringで*/
	myoutputdebugstring("6回表示されたはずなの〜〜");
	return 0;
}
こんな感じのソースがありました。

以下のようにしたいとあなたは考えました。
for(i=0;i<6;i++){ ... を書くのがめんどくさいので、関数の中の関数(ここでは、printfやOutputDebugString)をとっかえひっかえしたい。

で、そうなるとすると、今までの知識で以下のように書けるはずです。
#include 
#include 

void myoutputdebugstring(const char *s){OutputDebugString(s);}
void myprintf(const char *s){printf(s);}
void 6kai_print(const char *p,void (*fptr)(const char *)){
	int i;
	for(i=0;i<6;i++){
		fptr(p);
	}
}

int main(){
	/*myprintfで*/
	6kai_print("6回表示したいの〜〜",myprintf);
	/*OutputDebugStringで*/
	6kai_print("6回表示されたはずなの〜〜",myoutputdebugstring);
	
	return 0;
}
エクセレント!!これで、関数の中の関数を6kai_printの第二引数でとっかえひっかえ出来るようになりました。
このとっかえひっかえできる関数(ここでは、myprintとmyoutputdebugstring)をコールバック関数といいます。(多分^^;)
まぁ、関数のポインタの引数がついたものはその型に合った関数を入れればよいと、ソ〜(「・・)ン?名感じに覚えていれば良いかな?と思います。

C言語 小技

JumpTable(ジャンプテーブル)

ゲームプログラミングした事のある人ならわかるでしょう。
if文が無くなり、速度向上の効果があるらしい、
しかし参照するときの変数がマイナスになったり、配列の宣言した数より添え字が大きくなるとエラー。
なので変数はunsigned系でcharがいいかも?でもcharって遅いし…
BYTEかUINTか?
ULONGLONGをジャンプテーブルの添え字にしちゃえ!Σ^)/d金魚のアホーアホー☆ミ
添え字にはintを奨励します。

TaskProcessingTypeJampTable?
(タスク処理用ジャンプテーブル?(関数のポインタ極意))

重要報告: 実際、速度計測を行いました。その資料です。


Sentinel(番兵(番人,標識,見張りとも言うらしい))

よくアルゴリズム本に載っている有名な奴ですね^^;
実は私、この番兵の正しい(?)使い方を思いついたんです。
d金魚のC言語の愚痴でも書いていますが…、
int temp[100];
memset((void *)temp,NULL,sizeof(temp));
とやっても、temp[100]の中身が初期化されないんです。(少なくとも私の環境ではこうです)
って事で、ここに番兵を代入してはいかがでしょうか?
temp[100]=-111;//中に入れる値が自然数だった場合これでいいかも?
すみません、これは確か、C言語の愚痴でアホをやっていると、書いていたものでしたが、 なんと!!約、半年も放置しっぱなしでした。
x氏に感謝。
DxLibFanに戻る DxLibのダウンロードは以下から
Dxライブラリ置き場
DxLib Copyright(C) 山田 巧

The program using DxLib.
The text of this page.
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送