• 締切済み

qsortについて

『独習C』を使って勉強しているのですがqsortの部分で *(int*)i - *(int*)j という文が出てくるのですが、この意味がよく分かりません ##演算子の使い方も分からないので、どなたか分かる方 回答お願いします。

みんなの回答

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.4

他の方がキャストの部分がわからないだろと判断して回答されているようなので 別の視点から。 qsort の呼び出す比較関数は、あるxとyを比較したとき x<y 負の整数を返す(典型的には-1) x==y 0を返す x>y 正の整数を返す(典型的には1) のように求められています。 *(int*)i - *(int*)j 式を見てみると、たとえば 10 と 20を比較したときは 10 - 20 → -10 10 と 5の場合には 10 - 5 → 5 10と10の場合は 10 - 10 → 0 となりますので比較関数としての要件は満たします。 ただし、このやり方には落とし穴があって、 特定の範囲の引数同士を比較しようとした場合に 正しい結果を返さない場合があります。 ですので、特に断りもなくこの手法を使っているような 解説本だとかwebページはそのレベルが知れたものだといわざるを得ません。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

qsortやbsearch関数に渡す比較関数は、 int compar(const void *i, const void *); の形式になっています。 ソートや探索の対象となる配列の要素がint型の場合、const void*型のままではint型の要素にアクセスすることができませんから、いったんint*型に変換して参照をはずしています。 ただし、const int*型ではなく、int*型に変換していることはあまり感心できません。やむを得ない理由がない限り、型修飾子を外すような型変換は行うべきではありません。 ##に関しては、マクロの実引数を連結するための前処理演算子です。(必ずしも字句(トークン)を結合するものではありません) 使い方に関しては、既に回答が出ているとおりです。

  • Oh-Orange
  • ベストアンサー率63% (854/1345)
回答No.2

★『##』は識別子(トークン)の結合演算子です。 ・プリプロセッサ部(#define)で活躍します。  ソースファイル内で複数の識別子をコンパイル時に結合したい場合に利用します。 サンプル1: #define Merge(a,b) a ## b ・上記のマクロを  『goto Merge(Label,120);』として使うと  『goto Label120;』に置き換わります。 ・つまり、『Label』という識別子と『120』という識別子を『結合』して1つの『Label120』  という識別子(トークン)をプリプロセッサ処理で作り出します。 ・なお、 #define Merge(a,b) a b  として同じ事をすると『goto Merge(Label,120);』が『goto Label 120;』という風に間に  スペースが1つ入ってしまい『構文エラー』となります。 サンプル2: #define Merge(a,b) a ## b #define DATA dataA int dataA[ 100 ]; int dataB[ 100 ]; int i; for ( i = 0 ; i < 100 ; i++ ){  printf( "%d\n", Merge(DATA,[i]) ); } ・記号定数『DATA』が『dataA』のとき『printf( "%d\n", dataA[i] );』の処理を 100 回行う。 ・記号定数『DATA』が『dataB』のとき『printf( "%d\n", dataB[i] );』の処理を 100 回行う。 最後に: ・『*(int*)i - *(int*)j』については『qsort』の比較関数の引数『i』『j』が汎用ポインタで、  そのポインタを参照するには『参照する型』のポインタで『キャスト』しないと『*』演算子で  ポインタ内容を参照できません。 ・これは汎用ポインタ『void *』がポインタ(アドレス)だけを表し、型のサイズが分からないからです。  『型』を指定しないと『サイズ』が分からないため『*』で参照できずにエラーになります。 ・そこで『(int*)i』と『(int*)』でキャストすることで『int』型(4バイト)へのポインタだと指示され  『*』演算子で『int』型(4バイト)の整数を取り出せます。→構造体の場合はその『型』を指示する。 ・つまり、  int a = 100;  void *p = (void *)&a;  の場合、ポインタ『p』を参照するには『型』=『int型』へのポインタを指示して参照します。  間違い⇒『printf("a=%d\n",*p);』  正しい⇒『printf("a=%d\n",*(int*)p);』 ・以上。おわり。→汎用ポインタはこのようにキャストしてから『*』演算子で内容を参照します。

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.1

「*(int*)i」は「iは何型のポインタか判らないが、ともかくint型のポインタだと解釈し、iの指すポインタからintの値を取り出す」と言う意味。 int compare(void *i,void *j) などと「何型のポインタか判らないが、引き数のiとjはポインタを受け取る」と言う関数を定義した際に、その関数の中で使う。 この時、単に「iが指すポインタの中身が欲しい」と「*i」と書いてしまうと「iは何型のポインタか判らないから、中身を参照できません!」ってコンパイルエラーがでて、コンパイル出来なくなってしまう。 なので、ポインタの前に「(型名 *)」を付け「このポインタは○○型へのポインタと言う事にしておいて」と言う書き方をする。 int compare(void *i,void *j) {  return(*(int*)i - *(int*)j); } は、以下のように書き換える事が出来る int compare(void *i,void *j) {  int *i2,*j2;  i2=(int *)i;  j2=(int *)j;  return(*i2 - *j2); } >##演算子の使い方も分からないので、どなたか分かる方回答お願いします。 バージョン番号を #define MAJOR_VER 2 #define MINOR_VER 13 と定義した時、数値として「213」が欲しい時にどうするか? #define VERSION MAJOR_VERMINOR_VER と書いてもダメ。MAJOR_VERMINOR_VERは1語として解釈されてしまう。 #define VERSION MAJOR_VER MINOR_VER と書いてもダメ。定義される内容は「2 13」となり間に空白が入ってしまい数値として使おうとすると文法エラーを起こす。 そこで #define VERSION MAJOR_VER##MINOR_VER と書くことで「VERSION」に「213」が定義される。 結論:「##演算子は使う事が無いので、覚えなくてよし」