Thinkers'Studio
JavaとC言語の自習ツール
qsort で構造体のポインタ配列をソートする例

 今回は、構造体そのものの配列でなく、構造体を指すポインタの配列を qsort するプログラム例です。
 以前の Tips で「構造体配列の qsort」を扱いましたが、構造体のサイズが大きくて配列要素もたくさんあるときは、構造体配列の各要素を指すポインタの配列を作ってソートする方が効率的です。

ポインタ配列のソート
 ポインタ配列を用意するひと手間がありますが、かさばる構造体を並べ替えるより、効率よく処理することができます。
 下記では、卒業論文のデータを入れた構造体配列をソートする例を示します。

構造体のポインタ配列を qsort するプログラム例 】
 ronbun_t型(ID, 年度, 評価点, 論文タイトル)の配列は、「評価点の高い順」に初期化されています。
 この各要素を指すポインタの配列を用意して、「ID順」に qsort します。
#include <stdio.h>
#include <stdlib.h>
#define NDATA ((sizeof lst)/(sizeof(ronbun_t)))
typedef struct {
    int id;        //ID
    int year;      //年度
    int hk;        //評価点
    char *title;   //論文タイトル
} ronbun_t;

// --------------- 比較用の関数 cmp -------------------
int cmpptr( const void *p, const void *q ) {
    return (*(ronbun_t**)p)->id - (*(ronbun_t**)q)->id;
}
// ----------------------------------------------------
main()
{
    ronbun_t lst[] =
    { {45,2011,99,"貿易と産業"},        {89,2011,99,"アニメに見る社会"}
    , {73,1999,98,"なぜ人は山に登るか"},{33,2011,98,"邦画と洋画考察"}
    , {64,2003,97,"世界進出するには"},  {21,2013,96,"ゲームと戦略"}
    , {72,2006,96,"ハリウッドの変遷"},  { 3,2009,95,"製造業の未来"}
    , {30,2013,95,"金融政策について"},  { 9,2003,94,"原価計算の研究"}
    , {87,2011,94,"デザインの多様性"},  {99,2008,93,"OJTの効果"}
    , {51,2002,92,"緑の地球を取り戻す"},{34,2009,91,"似合う色とは"}
    , {66,2004,91,"待ち行列について"},  {26,2012,90,"ネット依存心理"}
    , {11,1995,90,"職人技とは"},        {18,2008,90,"ディズニーの戦略"} };

    int i;
    ronbun_t *plst[NDATA];

    // ポインタの配列 plst に構造体配列のアドレスを代入
    for( i = 0; i < NDATA; i++ ) plst[i] = &lst[i];
    // id順にソート
    qsort( plst, NDATA, sizeof(ronbun_t*), cmpptr );
    // 並べ替え後の内容を表示
    printf( "ID, 年度, タイトル(評価点)\n" );
    for( i = 0; i < NDATA; i++ )
        printf( "%2d, %d, %s(%d)\n"
        , plst[i]->id, plst[i]->year, plst[i]->title, plst[i]->hk );
}
実行結果
ID, 年度, タイトル(評価点)
 3, 2009, 製造業の未来(95)
 9, 2003, 原価計算の研究(94)
11, 1995, 職人技とは(90)
18, 2008, ディズニーの戦略(90)
     :途中略
99, 2008, OJTの効果(93)
 plst は ID順になるようポインタが並べ替えられますが、元の構造体配列 lst は、元のままです。

qsort にはポインタの配列 plst とそのサイズを渡します

qsort( plst, NDATA, sizeof(ronbun_t*), cmpptr );
 plst には plst[i] = &lst[i]; で構造体配列の各要素のアドレスを設定済みです。

cmpptr 関数の内容

 return (*(ronbun_t**)p)->id - (*(ronbun_t**)q)->id;
p  仮引数の p と q に渡されるのは、ポインタ配列 plst の配列要素を指すポインタです。
 plst の配列要素の型は ronbun_t* ですから、p と q の型は ronbun_t** であり、比較するメンバは (**(ronbun_t**)p).id です。
 これを (*(ronbun_t**)p)->id と書いています。

  (今週のクイズはありません)

[ 関連記事 ] int配列をqsort, 構造体配列をqsort
[ ご案内 ] 要点を学習できるコース:要点講座 [配列とポインタ編]/[構造体編]

前回の答え: (前回の問題を見る
入力用の標準関数で、入力の終了やエラー時にNULLを返す関数には、gets, fgets があります。