電子書籍の厳選無料作品が豊富!

以下のプログラムがあります。
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関数のポインタなのかも分かりません。

ご回答よろしくおねがいします。

A 回答 (7件)

> 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=navclien …

Google 検索:「+"abstract type declaration"」
http://www.google.co.jp/search?q=%2B%22abstract+ …
    • good
    • 0
この回答へのお礼

なるほど!
そう考えると理解できます。
分かりやすいご説明ありがとうございました。

しかしこれについて書いてるサイトってほとんど無いに等しいのですね・・・

お礼日時:2006/11/24 11:44

再び#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しか指せませんから、文字列のソートではなく文字のソートしかできないことになってしまうわけです。
    • good
    • 0
この回答へのお礼

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

お礼日時:2006/11/24 13:44

compare()のプロトタイプをqsort()の要求する型に合わせてやれば、


その無意味なキャストをしないで済むのですけどね。
その場合は、compare()内部でconst void *をconst char **にキャストすればいいだけですから。
    • good
    • 0
この回答へのお礼

compare内部の処理が簡単な場合はそれでも良いのですが、ちょっと込み入った事をしようとすると一つ一つキャストすると見づらいので出来ればqsortでキャストをした方がスッキリするかなぁと思いまして。

int型のデータを扱うときはint*型にキャストをすれば良いと言うのは分かるのですが、char型のデータの場合はなぜchar**型となるのでしょう?char*型ではまずいですか?初歩的な質問ですいません。

お礼日時:2006/11/24 12:48

#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
としなければならないわけです.
    • good
    • 0

http://www.linux.or.jp/JM/html/LDP_man-pages/man …

まあ、UNIX等のマニュアルは引数後ろに普通に書かれてますけどね。
    • good
    • 0
この回答へのお礼

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

お礼日時:2006/11/24 11:12

#No.1の者です。


プロトタイプ宣言には、そう書くことができます。
しかし、引数で、関数へのポインタを指定する際には
そのようには書けません。
    • good
    • 0
この回答へのお礼

なるほど。
この記述については説明している本やサイトが少ないですね。

早々のご回答ありがとうございました。

お礼日時:2006/11/24 10:35

qsortの第4引数は、


「const void *型の引数を2つ取り、戻り値がint型である関数へのポインタ」です。
    • good
    • 0
この回答へのお礼

早速のご回答ありがとうございます。

(int (*compare)(const void *, const void * ))
普通の関数のポインタ宣言のようにではダメなのでしょうか・・・

お礼日時:2006/11/24 10:06

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!