ある試験を受けた生徒の結果を処理する場合を考えよう。このような場合、 データを格納するには構造体を使って行くと良い。数学、英語、国語 の3科目を行なうのであれば、以下のような構造体定義にすると良いだろう。
struct student {
  char name[30];
  int  mathpt;
  int  engpt;
  int  jpnpt;
};
あるテストの全員の得点を記録したデータファイルが 以下のようになっているものとする。
山田太郎	50	70	20
公益太郎	90	80	70
飯森花子	91	79	72
鶴岡一人	60	60	40
酒田三吉	52	70	80
三川一二三	12	34	99
これを、構造体変数に読み込んで行くプログラムは以下のようになる。 起動時にデータファイルをコマンドライン引数として与えられるように なっている。
#include <stdio.h>
#define NMAX	100
struct student {
  char name[30];
  int  mathpt;
  int  engpt;
  int  jpnpt;
};
int main(int argc, char *argv[])
{
  FILE *stream;
  char buf[500];
  struct student pt[NMAX+1];
  int i, n;
  void dispall(struct student[]);
  
  if (NULL == argv[1]) {
    stream = stdin;
  } else {
    stream = fopen(argv[1], "r");
    if (NULL == stream) {
      fprintf(stderr, "Cannot open data file [%s]\n", argv[1]);
      exit(1);
    }
  }
  i = 0;
  while (NULL != fgets(buf, sizeof buf, stream)) {
    if (i >= NMAX) {
      fprintf(stderr, "Reached to maximum number(%d)\n", NMAX);
      break;
    }
    n = sscanf(buf, "%29s %d %d %d",
               pt[i].name, &pt[i].mathpt, &pt[i].engpt, &pt[i].jpnpt);
    if (n == 4) {
      i++;
    }
  }
  if (stdin != stream)
    fclose(stream);
  pt[i].name[0] = 0;            /* 終端の印 */
  dispall(pt);
}
void dispall(struct student pt[])
{
  int i, sum;
  for (i=0; pt[i].name[0] != 0; i++) {
    sum = pt[i].mathpt+pt[i].engpt+pt[i].jpnpt;
    printf("%2d: %-20s, %d, %d, %d\n",
           i+1, pt[i].name, pt[i].mathpt, pt[i].engpt, pt[i].jpnpt);
  }
}
このプログラムでは、各生徒の氏名、数学得点、英語得点、国語得点
を含む構造体がいくつも集まった配列 pt[] にデータを格納している。
この配列に格納されているのは
pt[0]「山田太郎」のデータ pt[1]「公益太郎」のデータ pt[2]「飯森花子」のデータ pt[3]「鶴岡一人」のデータ pt[4]「酒田三吉」のデータ pt[5]「三川一二三」のデータ 
であり、これはデータの読み込み順になっている。これを並べ換えよう。
qsort()関数
qsort() 関数を使うと任意の型の配列に格納された
データを昇順(小さい順)、または降順(大きい順)に並べ換えることができる。
qsort() 関数は、並べ換えたい配列を用意した後、
以下の書式で利用する。
#include <stdlib.h>
qsort(配列の先頭アドレス, 配列の要素数, 配列1要素のバイトサイズ,
      大小比較のための関数ポインタ);
大小比較のための関数 は、各要素へのポインタを引数として 受け取り、それぞれの大小比較の結果をintで返すように作る必要がある。 2つの引数を比べて、最初のものが大きかったら「正の値」、 等しかったらゼロ、最初のものが小さかったら「負の値」を返すようにする。 もしintどうしの比較なら
int hikaku(const void *x, const void *y)
{
  int *a = (int*)x;
  int *b = (int*)y;
  return (*a - *b);
}
とする。比較関数は必ず2つの引数を受け取り、どちらも
const void * 型で宣言するように書かねばならない。
const void * 型とは「どんな型の値が渡されるか分からない」
ときに宣言する型のことで、そのままでは実際の値を取り出せない。
  int *a = (int*)x;
  int *b = (int*)y;
の2行で、「xをint型のポインタだとみなしてaに
代入」し、「yをint型のポインタだとみなしてbに
代入」している。こうすることで *a, *b が比べるべき2つの
intの値を表すようになる。
もっとも簡単な例として、int型配列に格納されたデータを
昇順に並べ換えるプログラムを見てみよう。
#include <stdio.h>
#include <stdlib.h>             /* qsort()のために必要 */
int compare_int(const void *x, const void *y)
     /* 必ず2引数を const void* でもらう */
{
  int *a = (int*)x;             /* intへのポインタに変換 */
  int *b = (int*)y;
  return (*a - *b);
}
int main()
{
  int data[] = {10, 20, 3, 48, 7, 2};
  int n = sizeof data / sizeof (int);
  int i;
  qsort(data, n, sizeof (int), compare_int);
  for (i=0; i<n; i++) {
    printf("%d\n", data[i]);
  }
}
構造体の配列も、int型配列の並べ換えと同様の手順で
行なえば良い。変わるのは比較関数を作る部分だけである。
struct student の配列を並べ換える場合、比較関数は
以下のようにすれば良い。
int comp_point(const void *x, const void *y)
{
  struct student *a = (struct student *)x;
  struct student *b = (struct student *)y;
  /* a と b は構造体へのポインタ
   したがって、メンバへのアクセスは ピリオドでなく -> を使う */
  int sum_a, sum_b;
  sum_a = a->mathpt + a->engpt + a->jpnpt;
  sum_b = b->mathpt + b->engpt + b->jpnpt;
  /* 引算の順番に注意 */
  return sum_b - sum_a;
}
以上をまとめると、読み込んだ試験結果ファイルをもとに、 合計点の大きい順に並べ換えるプログラムは以下のようになる。
#include <stdio.h>
#include <stdlib.h>
#define NMAX	100
struct student {
  char name[30];
  int  mathpt;
  int  engpt;
  int  jpnpt;
};
int main(int argc, char *argv[])
{
  FILE *stream;
  char buf[500];
  struct student pt[NMAX+1];
  int i, n;
  /* プロトタイプ宣言 */
  void dispall(struct student[]);
  int comp_point(const void*, const void*);
  
  if (NULL == argv[1]) {
    stream = stdin;
  } else {
    stream = fopen(argv[1], "r");
    if (NULL == stream) {
      fprintf(stderr, "Cannot open data file [%s]\n", argv[1]);
      exit(1);
    }
  }
  i = 0;
  while (NULL != fgets(buf, sizeof buf, stream)) {
    if (i >= NMAX) {
      fprintf(stderr, "Reached to maximum number(%d)\n", NMAX);
      break;
    }
    n = sscanf(buf, "%29s %d %d %d",
               pt[i].name, &pt[i].mathpt, &pt[i].engpt, &pt[i].jpnpt);
    if (n == 4) {
      i++;
    }
  }
  if (stdin != stream)
    fclose(stream);
  pt[i].name[0] = 0;            /* 終端の印 */
  qsort(pt, i, sizeof pt[0], comp_point);
  dispall(pt);
}
void dispall(struct student pt[])
{
  int i, sum;
  for (i=0; pt[i].name[0] != 0; i++) {
    sum = pt[i].mathpt+pt[i].engpt+pt[i].jpnpt;
    printf("%2d: %-20s, %d, %d, %d | %3d\n",
           i+1, pt[i].name, pt[i].mathpt, pt[i].engpt, pt[i].jpnpt, sum);
  }
}
/* 比較関数 */
int comp_point(const void *x, const void *y)
{
  struct student *a = (struct student *)x;
  struct student *b = (struct student *)y;
  int sum_a, sum_b;
  sum_a = a->mathpt + a->engpt + a->jpnpt;
  sum_b = b->mathpt + b->engpt + b->jpnpt;
  return sum_b - sum_a;
}