![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e8efa67)
以下のプログラムがあります。
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関数のポインタなのかも分かりません。
ご回答よろしくおねがいします。
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=navclien …
Google 検索:「+"abstract type declaration"」
http://www.google.co.jp/search?q=%2B%22abstract+ …
なるほど!
そう考えると理解できます。
分かりやすいご説明ありがとうございました。
しかしこれについて書いてるサイトってほとんど無いに等しいのですね・・・
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しか指せませんから、文字列のソートではなく文字のソートしかできないことになってしまうわけです。
No.6
- 回答日時:
compare()のプロトタイプをqsort()の要求する型に合わせてやれば、
その無意味なキャストをしないで済むのですけどね。
その場合は、compare()内部でconst void *をconst char **にキャストすればいいだけですから。
compare内部の処理が簡単な場合はそれでも良いのですが、ちょっと込み入った事をしようとすると一つ一つキャストすると見づらいので出来ればqsortでキャストをした方がスッキリするかなぁと思いまして。
int型のデータを扱うときはint*型にキャストをすれば良いと言うのは分かるのですが、char型のデータの場合はなぜchar**型となるのでしょう?char*型ではまずいですか?初歩的な質問ですいません。
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
としなければならないわけです.
No.3
- 回答日時:
このサイトやリファレンスでは確かにこうなんですよね。でも
qsort( names, num,sizeof(names[0]),
(int(*compare)(const void *, const void *)) );
ってやるとうちの環境ではやっぱりコンパイルエラーが出ちゃいます。
引数を前にもってこないとダメなようです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
- C言語・C++・C# C pointer? or... 2 2022/03/29 00:47
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# leetcode 155 minstack 1 2022/05/07 16:43
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
既定のコンストラクタがありま...
-
多重定義が起きている?--lnk20...
-
戻り値を返す関数の前に(void)...
-
静的でないメンバ関数の呼び出...
-
int main()、void main()、void...
-
ドラッグしたときにマウスカー...
-
C++にてtemplateで受け取った任...
-
const_castのつかいどころを教...
-
C# Controls.Addで動的に配置し...
-
クラス内で、親ではない他のク...
-
(void)0 はどんな意味ですか
-
typedef unsigned int UINT;が...
-
ソケット通信時のWSACleanup処...
-
SC_SIZEがわからない
-
LNK2019:未解決の外部シンボル ...
-
【gcc・cygwin】multiple defin...
-
C/C++でのScene管理について
-
void*型の配列について
-
PIC12F683を用いたCapture実験
-
VC++でGetKeyboardStateがうま...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
既定のコンストラクタがありま...
-
【gcc・cygwin】multiple defin...
-
戻り値を返す関数の前に(void)...
-
C++にてtemplateで受け取った任...
-
多重定義が起きている?--lnk20...
-
gcc: incompatible pointer type
-
静的でないメンバ関数の呼び出...
-
int main()、void main()、void...
-
Notepad++の関数リスト表示の変...
-
C# KeyDownイベントでショート...
-
C# Controls.Addで動的に配置し...
-
ArduinoでMouse関数を使用して...
-
(void)0 はどんな意味ですか
-
DLLの関数呼び出しで引数がある...
-
void*型の配列について
-
ウインドウの移動禁止
-
const_castのつかいどころを教...
-
VC++でGetKeyboardStateがうま...
-
C言語 プロトタイプ宣言
-
stddef.hって何?
おすすめ情報