• ベストアンサー

qsortの引数について

以下のプログラムがあります。 int compare( const char **name1, const char **name2 ) { return strcmp( *name1, *name2 ); } int main( void ) { char *names[] = { "rand", "calloc", "malloc" }; int num = sizeof names / sizeof names[0]; qsort( names, num, sizeof( names[0] ), (int (*)(const void *, const void * ))compare ); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~この部分 return 0; } 上の「~~~」の上の部分のqsort関数の第4引数のキャストの意味が 分かりません。なぜ関数の前に引数が書かれるのでしょうか? またintの後にある(*)は「int型のポインタ」と言う意味なのか、 compare関数のポインタなのかも分かりません。 ご回答よろしくおねがいします。

質問者が選んだベストアンサー

  • ベストアンサー
  • noocyte
  • ベストアンサー率58% (171/291)
回答No.4

> int (*compare)(const void *, const void * )) > 普通の関数のポインタ宣言のようにではダメなのでしょうか・・・ ↑これは compare という変数の型を宣言 (定義) するのが目的ですが, qsort の第4引数では,ある型 (F1 型とする) の関数へのポインタを 別の型 (F2 とする) の関数へのポインタにキャストするのが目的です. したがって,F2 型の関数や変数の宣言ではなく,F2 型そのものの名前 (というか宣言) が必要になります.これは,「変数の型宣言から変数名 を除いたもの」と考えるとわかりやすいと思います. 例えば,変数の型宣言 (定義) char *string; から変数名 string を除くと char* が残るので,string の型(名) は char* 型です. 同様に関数の宣言 int (*compare)(const void *p1, const void *p2); から関数名 compare (および引数名) を除くと int(*)(const void*, const void*) が残るので,compare の型(名)は int(*)(const void*, const void*) 型 (上記の F2 型) です. このように,型そのものの宣言を抽象型宣言 (abstract type declaration) といいます. 日本語で "抽象型宣言" で検索してもわずかしかヒットしませんね…. Google 検索:「+"抽象型宣言"」 http://www.google.co.jp/search?sourceid=navclient-ff&ie=UTF-8&rls=GGGL,GGGL:2006-34,GGGL:ja&q=%2B%22%E6%8A%BD%E8%B1%A1%E5%9E%8B%E5%AE%A3%E8%A8%80%22 Google 検索:「+"abstract type declaration"」 http://www.google.co.jp/search?q=%2B%22abstract+type+declaration%22&hl=ja&lr=&rls=GGGL,GGGL:2006-34,GGGL:ja&start=30&sa=N

goo-ts
質問者

お礼

なるほど! そう考えると理解できます。 分かりやすいご説明ありがとうございました。 しかしこれについて書いてるサイトってほとんど無いに等しいのですね・・・

すると、全ての回答が全文表示されます。

その他の回答 (6)

回答No.7

再び#6です。 #6の方針でqsort()呼び出しを書き直してみましょう。 -- qsort(names, num, sizeof(names[0]), compare); -- シンプルですね。ではcompare()も書き直しましょう。 -- int compare(const void * p1, const void * p2) { const char ** name1 = (const char **) p1; const char ** name2 = (const char **) p2; return strcmp(*name1, *name2); } -- このようにシンプルなときはname1, name2が無駄に見えるかもしれませんが、ある程度複雑な関数ならこの方が見易いでしょう。 #或いはconst char **版の関数を別に用意して、それを呼び出してもいいでしょう。 さて、ポインタの扱いについて簡単に説明しておきます。 ソート対象物は、intの配列のときは勿論intです。処が今回のnamesの場合はchar *の配列ですね。つまり、char *がソート対象です。 intを指すポインタはint *ですから、当然char *を指すポインタはchar **になります。 逆に考えると、char *ではcharしか指せませんから、文字列のソートではなく文字のソートしかできないことになってしまうわけです。

goo-ts
質問者

お礼

ありがとうございます。 よく分かりました。

すると、全ての回答が全文表示されます。
回答No.6

compare()のプロトタイプをqsort()の要求する型に合わせてやれば、 その無意味なキャストをしないで済むのですけどね。 その場合は、compare()内部でconst void *をconst char **にキャストすればいいだけですから。

goo-ts
質問者

お礼

compare内部の処理が簡単な場合はそれでも良いのですが、ちょっと込み入った事をしようとすると一つ一つキャストすると見づらいので出来ればqsortでキャストをした方がスッキリするかなぁと思いまして。 int型のデータを扱うときはint*型にキャストをすれば良いと言うのは分かるのですが、char型のデータの場合はなぜchar**型となるのでしょう?char*型ではまずいですか?初歩的な質問ですいません。

すると、全ての回答が全文表示されます。
  • noocyte
  • ベストアンサー率58% (171/291)
回答No.5

#4 です.補足します. > qsort( names, num,sizeof(names[0]), > (int(*compare)(const void *, const void *)) ); > ってやるとうちの環境ではやっぱりコンパイルエラーが出ちゃいます。 qsort の第4引数では,F1 型の関数として定義されている compare を F2 型 (= int(*)(const void*, const void*) 型) にキャストするわけですから, (F2)compare つまり (int(*)(const void*, const void*))compare としなければならないわけです.

すると、全ての回答が全文表示されます。
  • t_nojiri
  • ベストアンサー率28% (595/2071)
回答No.3

http://www.linux.or.jp/JM/html/LDP_man-pages/man3/qsort.3.html まあ、UNIX等のマニュアルは引数後ろに普通に書かれてますけどね。

goo-ts
質問者

お礼

このサイトやリファレンスでは確かにこうなんですよね。でも qsort( names, num,sizeof(names[0]), (int(*compare)(const void *, const void *)) ); ってやるとうちの環境ではやっぱりコンパイルエラーが出ちゃいます。 引数を前にもってこないとダメなようです。

すると、全ての回答が全文表示されます。
noname#22058
noname#22058
回答No.2

#No.1の者です。 プロトタイプ宣言には、そう書くことができます。 しかし、引数で、関数へのポインタを指定する際には そのようには書けません。

goo-ts
質問者

お礼

なるほど。 この記述については説明している本やサイトが少ないですね。 早々のご回答ありがとうございました。

すると、全ての回答が全文表示されます。
noname#22058
noname#22058
回答No.1

qsortの第4引数は、 「const void *型の引数を2つ取り、戻り値がint型である関数へのポインタ」です。

goo-ts
質問者

お礼

早速のご回答ありがとうございます。 (int (*compare)(const void *, const void * )) 普通の関数のポインタ宣言のようにではダメなのでしょうか・・・

すると、全ての回答が全文表示されます。

関連するQ&A