• 締切済み

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」が定義される。 結論:「##演算子は使う事が無いので、覚えなくてよし」

関連するQ&A

  • 二次配列のqsortですが

    Cの初心者ですがよろしくおねがいします。 二次配列をqsortでソートしたいのですがまだソートする前の順番も記憶したいのですがどうすればいいのでしょうか 分かる方にはぜひ教えていただきたいのです! 例えばcount[j][i]をqsortでソートし、昇順で並べ変えた後のiの元の順番に対して今の順番も記憶する場合でお願いします.

  • 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関数のポインタなのかも分かりません。 ご回答よろしくおねがいします。

  • 二次配列のqsort

    二次配列のqsortについて分かる方に教えて頂きたいのですが 一段落のプログラムを載らせていただきました.count3[j][i]をバブルソートで降順でやってみましたが高速が要求されるため,qsortを使ってやり直したいのですが (ちなみにcount1[j][i],count2[j][i]は前で定義してあります.count4[j][i]にはiの順番を記憶するための二次配列です)  ぜひともよろしくおねがいします. int ind_near_search(int j,int t) { int i,var_num,count3[IND][VAR],count4[IND][VAR],temp1,temp2,num=0,m=0; for(i=0;i<VAR;i++){ if(individual[j].x[i]==1){ //変数が1と0の場合分け count2[j][i]=t-count[j][i]; }else{ count2[j][i]=count[j][i]; } if(individual[j].x[i]==1){ //全てcount3に値を入れる count3[j][i]=count2[j][i]; }else{ count3[j][i]=count[j][i]; } } for(i=0;i<VAR;i++){ count4[j][i]=num++; } for(m=0;m<VAR-1;m++){ for(i=0;i<VAR;i++){ //バブルソートにより降順に並べ換え if(count3[j][i]<count3[j][i+1]){ temp1=count3[j][i]; count3[j][i]=count3[j][i+1]; count3[j][i+1]=temp1; temp2=count4[j][i]; //count4にはcount3の並べ替え後の対応する番号を入れる count4[j][i]=count4[j][i+1]; count4[j][i+1]=temp2; } } } for(i=0;i<VAR;i++){ var_num=count4[j][i]; //count4の大きい順番からその番号をvar_numに渡す if(individual[j].x[var_num]==0){//0と1の場合分け individual[j].x[var_num]=1; }else{ individual[j].x[var_num]=0; }

  • qsortの関数ポイントについて

    qsortの関数ポイントについて int int_cmp(const int *a, const int *b) { ------ } main { qsort(x,nx,sizeof(int),(int (*) (const void *, const void * )) int_cmp); 上記の(1)関数のポイント,(int (*) (const void *, const void * )) int_cmpを  普通の(2)関数ポイント(* int_cmp) (const void *, const void * )で呼べない  理由 、また、(1)(2)は、同じ意味でしょうか、教えて頂きたい。

  • C言語のqsortについて

    現在、qsortのコードに取り組んでいます。 if (strcmp(ad, "ASC") == 0) { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_u); } else { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_d); } 恐らくこちらのqsortでの第二引数が書き方を間違えていると思うのですが、修正の方法が分からず、どなたか教えて頂けないでしょうか? #include <stdio.h> #include <time.h> #include <string.h> #include <stdlib.h> static char ad[10]; int cmp_u(const void* a, const void* d) { return strcmp((char*)a, (char*)d); } int cmp_d(const void* a, const void* d) { return strcmp((char*)d, (char*)a); } int main() { int num1, num2; char op; float answer; int r,i; FILE* fp; char c[11]; char sin[1000][1000]; char ad[8]; fp = fopen("log.txt", "a+"); if (fp == NULL) { printf("ファイルオープン失敗\n"); return -1; } while (1) { r = scanf("%d%c%d", &num1, &op, &num2); if (r != 3) { puts("input error"); return 1; } if (op == '+') { answer = num1 + num2; } else if (op == '-') { answer = num1 - num2; } else if (op == '*') { answer = num1 * num2; } else if (op == '/') { answer = (float)num1 / num2; } time_t t = time(NULL); struct tm* tm = localtime(&t); printf("%d/%02d/%02d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); printf("%02d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec); printf("%d%c%d,%f\n", num1, op, num2, answer); fprintf(fp, "%d/%02d/%02d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); fprintf(fp, "%02d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec); fprintf(fp, "%d%c%d,%f\n", num1, op, num2, answer); printf("計算を続けますか?"); scanf("%s\n", &c); if (strcmp(c, "no") == 0) { break ; } } fclose(fp); fp = fopen("log.txt", "r"); int cnt = 0; for (i = 0;i < 1000;i = i + 1) { if (fgets(sin[i], sizeof(sin[0]), fp)) ++cnt; else break; } fclose(fp); printf("ASC or DESC: "); scanf("%s", ad); if (strcmp(ad, "ASC") == 0) { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_u); } else { qsort(sin, sizeof(cnt), sizeof(sin[0]), cmp_d); } for (i = 0;i < cnt;i = i + 1) { printf("%s", sin[i]); } return 0; }

  • C言語のqsortについて

    下記の課題に取り組んでおり、qsortをファイルの行数分のみ出力するプログラムを書いているのですが if (strcmp(ad, "ASC") == 0) { qsort(sin,1000 , sizeof(sin[0]), cmp_u); if (sin[i][0] == 0) { break; } } else { qsort(sin, 1000, sizeof(sin[0]), cmp_d); if (sin[i][0] == 0) { break; } この書き方ではエラーが出てしまい、どなたか書き方を教えて頂けないでしょうか? 【課題】 電卓アプリケーションの作成  以下の機能を満たすアプリケーションを作成してください。  ※画面の表示やログの形式は原則として例示されている内容に従ってください。  1) 四則演算が出来ること  2) コンソールから計算対象となる数値と演算子を受け取る    例) 5 + 6  3) 結果をコンソール上に表示する    例) 11  4) 演算結果と実行した日、時間、秒をログファイルとして保存する    ログの上限は1000行とする(上限を超過するケースはひとまず考慮しなくて良い)    例) log.txt に 以下の内容を記録      2015/04/27 14:30:51, 5 + 6, 11  5) コンソールからパラメータを受け取り、ログを実行時間の昇順/降順に並べ替えて    コンソールに表示する    例) ASC を入力      2015/04/26 10:20:00, 5 + 6, 11      2015/04/27 14:30:51, 7 - 6, 1      2015/04/27 15:30:00, 7 + 8, 15      2015/04/28 14:30:51, 8 + 9, 17    例) DESC を入力      2015/04/28 14:30:51, 8 + 9, 17      2015/04/27 15:30:00, 7 + 8, 15      2015/04/27 14:30:51, 7 - 6, 1      2015/04/26 10:20:00, 5 + 6, 11 【現在のソースコード】 #include <stdio.h> #include <time.h> #include <string.h> #include <stdlib.h> static char ad[10]; int cmp_u(const void* a, const void* d) { return strcmp((char*)a, (char*)d); } int cmp_d(const void* a, const void* d) { return strcmp((char*)d, (char*)a); } int main() { int num1, num2; char op; float answer; int r,i,n; FILE* fp; char c[11]; char sin[1000][1000]; char ad[8]; fp = fopen("log.txt", "a+"); if (fp == NULL) { printf("ファイルオープン失敗\n"); return -1; } while (1) { r = scanf("%d%c%d", &num1, &op, &num2); if (r != 3) { puts("input error"); return 1; } if (op == '+') { answer = num1 + num2; } else if (op == '-') { answer = num1 - num2; } else if (op == '*') { answer = num1 * num2; } else if (op == '/') { answer = (float)num1 / num2; } time_t t = time(NULL); struct tm* tm = localtime(&t); printf("%d/%02d/%02d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); printf("%02d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec); printf("%d%c%d,%f\n", num1, op, num2, answer); fprintf(fp, "%d/%02d/%02d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday); fprintf(fp, "%02d:%02d:%02d ", tm->tm_hour, tm->tm_min, tm->tm_sec); fprintf(fp, "%d%c%d,%f\n", num1, op, num2, answer); printf("計算を続けますか?"); scanf("%s\n", &c); if (strcmp(c, "no") == 0) { break ; } } fclose(fp); fp = fopen("log.txt", "r"); for (i = 0;i < 1000;i=i+1) { fgets(sin[i], sizeof(sin[0]), fp); //if (strcmp(sin, "NULL") == 0) { if (sin[i][0] == 0) { break; } } fclose(fp); printf("ASC or DESC: "); scanf(" %s", ad); if (strcmp(ad, "ASC") == 0) { qsort(sin,1000 , sizeof(sin[0]), cmp_u); if (sin[i][0] == 0) { break; } } else { qsort(sin, 1000, sizeof(sin[0]), cmp_d); if (sin[i][0] == 0) { break; } } for (i = 0;i < 1000;i = i + 1) { if (sin[i][0] == 0) { break; } printf("%s", sin[i]); } return 0; }

  • int i,j; \n i=0,j=5;

    int i,j; i=0; j=5: と書いてあるソースは普通ですが、 int i,j; i=0,j=5: と書いてあるソースもあります。 後者はC++の正しい書式ですか? カンマ演算子というのは後者のカンマのことですか?

  • qsortの先頭のqの意味

    C言語の関数にqsortというのがありますが最初のqはどういう意味でしょうか 順番に並べ替えるだけならsortでいいと思うのですが、どういう経緯でqが先頭についているのでしょうか

  • クイックソートのプログラムについて

    一から自分なりにやってみましたが、再帰処理の部分がうまくゆきません。 改善方法をご教授願えたらと思います。 #include<stdio.h>   void qsort (int x[], int a, int b) {  int temp, kijyun, i;  kijyun = a;  i = a + 1;  while (i <= b)   {    if (x[i] < x[kijyun])     {      change (x, kijyun, i);      kijyun = kijyun + 1;     }    i++;   }  if (kijyun != 0) //基準より左側をソートする。   {    qsort (x, 0, kijyun - 1);   } //以下if文の部分で、うまくいきません。  if (kijyun != 9) //基準より右側をソートする。   {    qsort (x, kijyun + 1, 9);   } } int change (int x[], int a, int b) //x[b]をx[a]の位置に挿入させる。 {  int i, temp;  i = b;  while (i != a)   {    temp = x[i];    x[i] = x[i - 1];    x[i - 1] = temp;    i--;   } } int main (void) {  int i, x[9] = { 6, 8, 9, 5, 3, 2, 1, 4, 7 };  qsort (x, 0, 8);  for (i = 0; i != 9; i++)   {    printf ("\n%d", x[i]);   } }

  • qsortと動的確保の2次元配列

    C言語で以下のようなソートのあるプログラムを作ろうとしているのですが、良い方法が思いつきません。。。。 どなたか,知恵を貸していただけないでしょうか? ・複数人の身長と体重がcsvファイルに2列に入っている。 人 身長 体重 1 158.9 50.5 2 161.2 72.3 3 150.4 42.8 4 170.7 80.4 5 165.0 59.9 ・ ・ ・ ・ ・ ・ ・↑このように身長も体重もランダムに並んでいる状態 ・身長・体重をプログラムで読み込んだら 身長の低い順にソートする。この時体重も身長に対応して並び換わってほしい。 (わかりやすいかと思い人の番号列を設けましたが、人の番号は考えなくて良いです) この問題に対して,データ数が不特定かつ多いため 動的確保の2次元配列を使ったクイックソートで対応を考えます。 qsortについてあれこれ調べていたのですが,動的確保でのqsort例が無く困っています。。。 どなたかちょっとアドバイスをいただけないでしょうか? よろしくお願いします。 #include <stdio.h> #include <stdlib.h> enum {HIGHT, WEIGHT, COLUMN}; int comp (const void *a, const void *b) //比較関数 { return (int) (((double *)a)[HIGHT] - ((double *)b)[HIGHT]) ; } int main(void) { ////////////////////////////////////////////////////////// 私情により、ソート以前の処理で使用するため あらかじめ .csv ファイルから fget で値を読み込んで コンマで分割しx[]y[]に格納してある。 &データ数をカウントしている 今は省略  仮定として以下のように5つのデータ数を読み込んでいたとする double x[5] = {158.9,161.2,150.4,170.7,165.0}; double y[5] = {50.5,72.30,42.8,80.4,59.9}; int n=5; //データカウント数 /////////////////////////////////////////////////////////// int i; double **list; list = (double**)malloc(sizeof(double)*5); for (i=0 ; i< 5 ; i++) { list[i] = (double*)malloc(sizeof(double)*COLUMN); if (list[i]==NULL) return 1;/* 領域確保に失敗したか */ } for(i=0;i<n;i++) { list[i][HIGHT]=x[i]; list[i][WEIGHT]=y[i]; } for(i = 0; i < n; i ++) printf("%lf %lf\n", list[i][HIGHT], list[i][WEIGHT]); puts("Sort"); qsort(list,n, sizeof(double [COLUMN]), comp); for(i = 0; i <n; i ++) printf("%lf %lf\n", list[i][HIGHT], list[i][WEIGHT]); scanf("%d",i); return 0; }

専門家に質問してみよう