代码大体框架如下:
#include <stdio.h>
#include <stdlib.h>
#define M 30
typedef struct STUDENT
{
int studentID;
char studentName[10];
float score[3];
} stu, *pstu;
typedef int (*CmpFunPtr)(float, float); /* 定义函数指针类型CmpFunPtr,该类型的指针指向的函数应该返回一个整型数据,且含有两个float型形参。 */
int compareA(float, float); /* 降序排序比较函数 */
int compareD(float, float); /* 升序排序比较函数 */
stu *read(FILE *fp, int m, int n);
void sort(stu *stud, int mode, int sub, int n);
void print(pstu stud, int n);
CmpFunPtr setmode(int mode); /* 返回一个CmpFunPtr类型的函数指针 */
int main()
{
struct STUDENT *stud;//*stud 表示 stud 是指向 struct STUDENT 类型对象的指针。也就是说,stud 变量存储的是一个 STUDENT 结构体实例的地址。
但是,在这个声明之后,stud 指针并未初始化,它没有指向任何具体的 STUDENT 结构体实例。若要使用此指针,需要先通过如分配内存(如使用 malloc 函数)或者直接指向已有的 STUDENT 结构体实例等方式进行初始化。
FILE *fp;
int m, n, mode, sub;
scanf("%d%d%d%d",&m, &n, &mode, &sub);
if(m < 0 || m > M || n < 0 || n+m > M || (mode != 1 && mode != 2) || (sub != 0 && sub !=1 && sub != 2))
{
printf("error!\n");
exit(0);
}
fp = fopen("stud.dic", "rb");//以二进制只读的形式打开文件。
if(fp == NULL )
exit(0);//确保文件已经打开,若未打开则fp == NULL。
stud=read(fp, m, n);//stud指向读取的所需要进行排序的学生数组的首地址
sort(stud, mode, sub, n);//对取得的多组学生数组数据进行排序。
print(stud, n);
free(stud);//记得释放给stud分配的动态内存空间否则容易造成内存外溢。
fclose(fp);//关闭文件。
return 0;
}
CmpFunPtr setmode(int mode)
{
if (mode == 1)
return compareD;
else
return compareA;
}
void print(pstu stud, int n)
{
int i;
for(i = 0; i < n; i++)
{
printf("%dth: %d %s %.2f %.2f %.2f\n", i, stud[i].studentID,
stud[i].studentName, tud[i].score[0], stud[i].score[1], stud[i].score[2]);
}
}
int compareA(float x, float y)//返回值:如果 x 大于 y,则返回非零(在C/C++中通常表示为1),否则返回零。这意味着当需要对浮点数进行升序排序时,可以调用此函数作为比较函数。
{
return x > y;
}
int compareD(float x, float y)//返回值:如果 x 小于 y,则返回非零,否则返回零。这个函数适合于在需要对浮点数进行降序排序的场合下作为比较函数。
{
return x < y;
}//这两个函数常被用于排序算法中作为自定义比较规则,如快速排序、选择排序等算法中的回调函数。
代码测试样例:
输入:0 3 1 0
输出:
0th: 2009011360 卢 莹 13.27 85.45 26.72
1th: 2010036201 张 阳 87.10 54.00 63.90
2th: 2010036209 赵扶强 90.50 54.00 65.00
解决代码如下;
struct STUDENT *read( FILE *fp, int m, int n)
{
pstu stud;//首先用指针类型pstu来定义一个指针stud,该指针指向的是结构体STUDENT
stud =(pstu)malloc(n*sizeof(stu));//给stud分配动态内存,n为需要读入的学生个数,使用malloc函数的时候强制类型转换未pstu指针类型,大小未stud指针指向的stu结构体的大小,而乘以n是n个学生数据。
fseek(fp, (long)m * sizeof(stu), SEEK_SET);//使用fseek函数将文件位置指针移动到由起始位置开始,用long强制转换数据为long型来符合fseek函数的格式,m*sizeof(stu)为文件指针的位移量,即指以起始位置为基准值向前移动的字节数。
fread(stud, sizeof(stu), n, fp);//stud为读入数据在内存中存放的起始地址,sizeof(stu)是每次要读取的字符数,n为要读取的个数。
return stud;//返回需要参与排序的学生数组的首地址
}
void sort(stu *stud, int mode, int sub, int n)
{
int i,j,k;
stu temp;
CmpFunPtr comp = setmode(mode);//使用函数指针类型CmpFunPtr来定义一个函数指针comp使其接受setmode函数返回的函数。
/* 使用选择排序法进行排序。也可以用冒泡排序法。因为排序字段与变量相关,不宜使用快速排序法。 */
for (i = 0; i < n-1; i++)
{
k = i;//令k和第一个数据的下标相同
for (j = i+1; j < n; j++)
{
if(comp(stud[j].score[ sub ], stud[k].score[ sub ]))//若j大于k则执行k = j,否则跳过。
k = j;
}
if ( k != i )//若看k != i则说明j和i二者大小不同,需要进行交换,而具体是升序还是降序这取决于comp所指向的函数
{
temp = stud[i];
stud[i] = stud[k];
stud[k] = temp;
}
}
}
附言:本体难度较大,作者发表自己对本题的理解,若有失误,欢迎批评指正。