NWAFU 2021阶段二 D
从二进制文件Student.dic中读取指定序号范围的学生信息并存储到结构体数组中,要求对这些学生信息按照成绩及出生日期排序后输出,其中成绩是降序,而出生日期是升序,且仅在成绩相同时才比较出生日期。学生的出生日期由其身份证的第6-13位(从第0位开始计位)确定。学生结构体定义如下:
typedef struct { char Sno[10]; /* 学号 */ char Name[20]; /* 姓名 */ char Id[18]; /* 身份证号 */ float Score; /* 成绩 */ int Ranking; /* 排名位次 */ } Student, *PStudent;
排序函数原型规定为: void OrderStu(PStudent stu_array, int len);
其中stu_array是指向要排序的学生结构体数组的指针,len是参与排序的学生人数。
比较函数原型规定为:int Compare(const void *a, const void *b);
其中a和b分别是指向要参与比较的两个学生结构体变量的指针。比较的办法是,按学生成绩及其出生日期比较。如果两个学生成绩相等,再判断出生日期,此时若前者的出生日期小于后者,则函数返回负数,反之为正数。成绩不相等时,如果前者的成绩大于后者,则函数返回负数,反之返回正数。
程序主体已经完成,但其中包含几处错误,请在不改变程序主体的前提下修改源代码中的错误,并完成排序和比较函数的编写。
二进制文件Student.dic请使用wget从这里获取,含有错误的程序代码请从这里获取。提交时注意不提交main()函数结束前的内容。
#include
#include
#include
#define FileName "Student.dic"
typedef struct StuInfo
{
char Sno[12];
char Name[20];
char Id[20];
float Score;
int Ranking;
} Student, *PStudent;
int Compare(const void *, const void *);
void OrderStu(PStudent stu_array, int len);
int ReadFile(PStudent a,int start, int end);
void Print(PStudent stu_array, int len);
int main()
{
PStudent a;
int len;
int start, end;
scanf("%d%d", &start, &end);
len = end - start + 1;
a=(PStudent)malloc(len * sizeof(Student));
len = ReadFile(a, start, end);
OrderStu(a,len);
Print(a, len);
free(a);
return 0;
}
/* 以上代码中不包含错误,在提交时不要包含在内。 */
int ReadFile(PStudent a,int start, int end)
{
FILE *fp;
PStudent t;
int i, len;
fp=fopen(FileName, "w");
while(i < start) {
fread(&t, sizeof(Student), 1, fp);
i++;
}
len = fread(&a, sizeof(Student), end - start + 1, fp);
fclose(fp);
return len;
}
void Print(PStudent a, int len)
{
int i;
/* 请不要修改输出格式相关的内容 */
printf(" 学号 | 姓名 | 身份证 | 成绩 |排名\n");
printf("----------------------------------------------------\n");
for(i=0;i < len;i++)
printf("%10s|%-8s|%18s|%6.2f|%3d\n",a[i]->Sno, a[i]->Name, a[i]->Id, a[i]->Score, a[i]->Ranking);
printf("----------------------------------------------------\n");
}
两个正整数,表示从文件中要读取的学生信息的序号范围。
按成绩和出生日期排序后的学生信息。
3 5
学号 | 姓名 | 身份证 | 成绩 |排名
----------------------------------------------------
2021999013|李元华 |411302196603042095| 99.00| 3
2021999015|尤子越 |133000197402029470| 92.00| 35
2021999014|陈心洁 |511826200012061797| 91.00| 57
----------------------------------------------------
使用qsort()函数可实现快速排序。
这个问题由纠错与排序函数的编写两部分组成。Print函数显然没有错误,因此第一部分主要考察ReadFile函数中文件操作相关语句。首先是变量的问题,结构体指针 t 没有指向有效的内存空间,而作为循环变量的 i 在进入while循环之前显然没有赋0。其次是函数的问题,题设条件是二进制文件,因此fopen()函数的mode应当为 "rb" ,fread()函数的第一个参数是文件指针,因而在调用时应当传入指针,而非指针的地址。(PS:ReadFile函数返回值的意义小于其对文件指针位移的作用,因为在file正确的情况下,len = start - end + 1,或许后期优化可以利用这一点进行检查)(PS里的内容不重要)
至于函数的编写,题目中明目张胆地提示:使用qsort()函数可实现快速排序。
那就用呗 熟悉qsort()的朋友都知道,我们之所以喜欢泡泡就是因为qsort()的第四个参数太过复杂,然而熟悉qsort()的朋友会发现:其中a和b分别是指向要参与比较的两个学生结构体变量的指针。比较的办法是,按学生成绩及其出生日期比较。如果两个学生成绩相等,再判断出生日期,此时若前者的出生日期小于后者,则函数返回负数,反之为正数。成绩不相等时,如果前者的成绩大于后者,则函数返回负数,反之返回正数。
这不妥妥的cmp函数么!那还等什么,直接按照题目的保姆式教程使用qsort(),然后将Compare函数作为cmp参数传入qsort()。
代码实现:
int ReadFile(PStudent a, int start, int end)
{
FILE *fp;
PStudent t = (PStudent)malloc(1*sizeof(Student));
int i = 0, len;
fp = fopen(FileName, "rb");
while (i < start) {
fread(t, sizeof(Student), 1, fp);
i++;
}
len = fread(a, sizeof(Student), end - start + 1, fp);
// fread(a,sizeof(Student),len,fp);
fclose(fp);
return len;
}
void Print(PStudent a, int len)
{
int i;
/* 请不要修改输出格式相关的内容 */
printf(" 学号 | 姓名 | 身份证 | 成绩 |排名\n");
printf("----------------------------------------------------\n");
for (i = 0; i < len; i++)
printf("%10s|%-8s|%18s|%6.2f|%3d\n", a[i].Sno, a[i].Name,
a[i].Id, a[i].Score, a[i].Ranking);
printf("----------------------------------------------------\n");
}
int Compare(const void * a, const void * b){
int i;
//强制类型转换
PStudent x = (PStudent)a;
PStudent y = (PStudent)b;
if(x->Score == y->Score) //成绩相等,比较日期
{
for(i = 6;i <= 13;i++)
{
if(x->Id[i] > y->Id[i])
{
return 1;
}
else if(x->Id[i] < y->Id[i])
{
return -1;
}
else
return 0;
}
}
else{ //比较成绩
if(x->Score > y->Score)
{
return -1;
}
else
{
return 1;
}
}
}
void OrderStu(PStudent stu_array, int len){
qsort(stu_array,len,sizeof(stu_array[0]),Compare);
}
NWAFU 2021阶段二 D