プログラミング論 関数ポインタ と 応用(qsort) http://www.ns.kogakuin.ac.jp/~ct13140/Prog/
概要 関数ポインタ qsort関数 関数(へのポインタ)を変数に入れてしまう. 分かりづらい? C言語に標準で搭載されているソート関数. 関数ポインタの理解が必須
関数ポインタの例 void hoge(){ printf("hello\n"); 実行結果 } hello void main(){ void (*p)(); /* ↑ 関数のアドレスを入れる変数pを宣言. */ p = &hoge; /* ↑ pに 関数hoge のアドレスを代入 */ (*p)(); /* pは関数hogeへのポインタ.(*p)は関数hogeそのもの */ 実行結果 hello
関数のアドレス 関数にはアドレスがある. 関数のアドレスは,「&関数名」あるいは「関数名」で取得で取得可能.(どちらでも良い) 関数はメモリ上に存在している. 関数のアドレスは,「&関数名」あるいは「関数名」で取得で取得可能.(どちらでも良い) void hoge(){ } void main(){ printf("&hoge = %p\n", &hoge); printf("hoge = %p\n", hoge); 実行結果 &hoge = 0x400498 hoge = 0x400498
関数のアドレス 標準関数にもアドレスがある. void main(){ printf("%p\n", &printf); } 実行結果 0x4003a0
関数ポインタ変数 関数のアドレスを入れる変数の宣言 void (*p)(); 「引数(),戻り値voidの関数」 へのポインタpを宣言. 解説? void hoge(){ printf("Hello\n"); } void main(){ void (*p)(); p = &hoge; (*p)(); int i; int *p; i と *p が同等の存在 void hoge(); void (*p)(); hoge と *p が同等の存在
関数ポインタ変数 関数のアドレスを入れる変数の宣言 int (*p)(int, int); 「引数(int,int), 解説? int hoge(int a, int b){ return a+b; } void main(){ int (*p)(int, int); p = &hoge; printf("%d\n", (*p)(3,4) ); int i; int *p; i と *p が同等の存在 int hoge(int a, int b); int (*p)(int a, int b); hoge と *p が同等の存在
関数ポインタ から 関数にアクセス pが関数ポインタなら,(*p)()あるいはp() にて,関数にアクセスできる.(どちらでも良い) void hoge(){ printf("Hello\n"); } void main(){ void (*p)(); p = &hoge; (*p)(); int hoge(int a, int b){ return a+b; } void main(){ int (*p)(int, int); p = &hoge; printf("%d\n", (*p)(3,4) ); 実行結果 Hello 実行結果 7
関数ポインタ から 関数にアクセス pが関数ポインタなら,(*p)()あるいはp() にて,関数にアクセスできる.(どちらでも良い) void hoge(){ printf("Hello\n"); } void main(){ void (*p)(); p = &hoge; p(); int hoge(int a, int b){ return a+b; } void main(){ int (*p)(int, int); p = &hoge; printf("%d\n", p(3,4) ); 実行結果 Hello 実行結果 7
関数ポインタの例 int hoge(int a, int b){ return a+b; } int fuga(int a, int b){ return a*b; void main(){ int x; int (*p)(int, int); p = &hoge; printf("%d\n", (*p)(3,4) ); p = &fuga; 実行結果 7 12 これは hoge これは fuga
関数ポインタの例 関数の引数に「関数ポインタ」を渡すことも可能。 int hoge(int a, int b){ return a+b; } int fuga(int a, int b){ return a*b; int func( int (*p)(int, int) ){ return (*p)(3,4); void main(){ printf("%d\n", func(&hoge) ); printf("%d\n", func(&fuga) ); 実行結果 7 12 この関数を実行 p=hogeなら加算 p=fugaなら乗算
qsort C言語の標準関数. クイックソートでデータをソートする. アドレスbaseに格納されているデータをソート. void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)); クイックソートでデータをソートする. アドレスbaseに格納されているデータをソート. 各データのサイズはsizeで,データ個数はnmumb. データ同士の比較は,関数ポインタcomparが指す関数の結果(戻り値)に従う. ユーザが関数を指定し,動作を決める. size_t型は「整数型」と考えて良い.
qsort 関数ポインタcompar comparが指す関数は, int(*compar)(const void *a, const void *b) comparが指す関数は, もしa<bなら,負の数を返す. もしa==bなら,0を返す. もしa>bなら,正の数を返す. qsortは,要素間大小比較をするときに,この関数を呼び出して結果を決める. 「const付き」のポインタは,そのポインタの先の値は「読み出しはできる」が「書き込み」はできない.
qsortの例 (int型) int comp(const void *a, const void *b){ const int *p, *q; p=a; q=b; return *p - *q; } void main(){ int x[5]={3,0,2,9,5}; printf("%d %d %d %d %d\n", x[0], x[1], x[2], x[3], x[4]); qsort( x, 5, sizeof(int), &comp); 実行結果 3 0 2 9 5 0 2 3 5 9
qsortの例 (文字列) int comp(const void *a, const void *b){ const char *p, *q; p=a; q=b; return strcmp(p, q); } void main(){ char x[3][5]={"hoge","fuga","piyo"}; printf("%s %s %s\n", x[0], x[1], x[2]); qsort( x, 3, 5, &comp); 実行結果 hoge fuga piyo fuga hoge piyo
qsortの例 (構造体) struct seiseki{ int math; int engl; }; int comp(const void *a, const void *b){ const struct seiseki *p, *q; p=a; q=b; return (p->math + p->engl) - (q->math + q->engl); } void main(){ struct seiseki stu[3]={{90,80}, {10,80}, {23,20}}; printf("(%d,%d),(%d,%d),(%d,%d)\n", stu[0].math, stu[0].engl, stu[1].math, stu[1].engl, stu[2].math, stu[2].engl); qsort( stu, 3, sizeof(struct seiseki), &comp); qsortの例 (構造体) 実行結果 (90,80),(10,80),(23,20) (23,20),(10,80),(90,80)