目 录
第1章 实验基本信息
(本章满分1分)
1.1 实验目的
-
- 掌握结构化数据排序方法及文件相关操作
- 掌握共享库的建立与使用
- 掌握模块化程序设计和增量测试方法
- (选)掌握跨平台程序编写、调试方法
1.2 实验环境与工具
1.2.1 硬件环境
-
- 硬件平台:Intel X86-64、香橙派/树莓派
1.2.2 软件环境
-
- Ubuntu 18.04 LTS 64以上
(或Windows/MacOS + 虚拟机VirtualBox/Vmware );
- Ubuntu 18.04 LTS 64以上
1.2.3 开发工具
-
- gcc、g++;vi/vim/gedit
第2章 小型成绩管理系统
(本章满分29分)
2.1 小型成绩管理系统总体设计(4分)
(1)班级人数最多45人(具体人数由键盘输入确定)
(2)成绩科目包括计算机系统(iCS)、程序设计实践(PDP)、数据结构(DS)、数字逻辑(DL)4门课程
- 程序功能要求
(1)通过键盘录入每个学生的学号、姓名和各科成绩;
(2)按姓名查询学生成绩,并显示;
(3)按学号查询学生成绩,并显示;
(4)修改某个学生成绩;
(5)删除某个学生成绩;
(6)计算每个学生总成绩和平均成绩,并显示;
(7)计算班级各科平均成绩,并显示;
(8)按某一科成绩由高到低排序,并显示(包括其他科目成绩);
(9)按优秀(90~100)、良好(80~89)、中等(70~79)、及格(60~69)、不及格(0~59)五个类别,对每科成绩分别统计每个类别的人数及所占的百分比,并显示结果;
(10)导出,以文本或二进制文件形式输出1、4、5的结果,文本文件每行一个记录;
(11)导入,从文本或二进制文件读入所有学生成绩信息;
(12)退出。
2.2 主要功能模块设计(25分)
2.2.1成绩录入(3分)
从键盘输入至少5名学生的成绩,必须包括本人的信息。
相关函数代码与说明:
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
//input:学生数量n
//output:指向学生结构体数组的指针
//function:通过键盘录入每个学生的学号、姓名和各科成绩
STUDENT* append_record(int n)
{
STUDENT *stu;
stu = (STUDENT*)malloc(sizeof(STUDENT) * n);
if (stu == NULL)
{
printf("内存分配失败\n");
return NULL;
}
for (int i = 0; i < n; i++)
{
printf("请输入第%d个学生的学号、姓名和各科成绩\n", i + 1);
if (scanf("%ld %255s %f %f %f %f", &stu[i].id, stu[i].name, &stu[i].score.ics, &stu[i].score.pdp, &stu[i].score.ds, &stu[i].score.dl) != 6)
{
printf("输入格式错误\n");
free(stu);
return NULL;
}
printf("第%d个学生的学号、姓名和各科成绩输入成功!\n", i + 1);
}
return stu;
}
2.2.2成绩查询(3分)
以姓名查询本人的成绩。
相关函数代码与说明:
输入:结构体数组指针stu,学生人数n,学生姓名name
输出:指向查询的学生的结构体指针
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
#include <string.h>
//
//
//
STUDENT* search_by_name(STUDENT * stu,int n,char * name)
{
for(int i=0;i<=n-1;i++)
{
if(!strcmp(stu[i].name,name))
{
return stu+i;
}
}
return NULL;
}
2.2.3成绩修改(3分)
以学号找到自己成绩并修改。
相关函数代码与说明:
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
//
//
//
STUDENT* search_by_id(STUDENT * stu,int n,unsigned long iid)
{
for(int i=0;i<=n-1;i++)
{
if(stu[i].id==iid)
{
return &stu[i];
}
}
return NULL;
}
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
//
//
//
int modify(STUDENT *stu,int n,STUDENT *stu1)
{
for(int i=0;i<=n-1;i++)
{
if(stu1->id==stu[i].id)
{
stu[i].score.ics=stu1->score.ics;
stu[i].score.pdp=stu1->score.pdp;
stu[i].score.ds=stu1->score.ds;
stu[i].score.dl=stu1->score.dl;
return 1;
}
}
return 0;
}
输入:结构体数组指针stu,学生数量n,要查询的学生的结构体指针stu1
输出:1代表修改成功
功能:按学号修改学生成绩
2.2.4成绩删除(4分)
以学号为索引删掉本人成绩记录。
相关函数代码与说明:
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
//
//
//
int delect(STUDENT *stu,int n,STUDENT *stu1)
{
for(int i=0;i<=n-1;i++)
{
if (stu1->id == stu[i].id)
{
for (int j = i; j < n - 1; j++)
{
stu[j] = stu[j + 1];
}
return 1;
}
}
return 0;
}
输入:结构体数组指针stu,学生数量n,要查询的学生的结构体指针stu1
输出:1代表删除成功
功能:按学号删除学生成绩
2.2.5成绩计算(4分)
计算各科平均成绩并显示。
相关函数代码与说明:
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
//
//
//
/*typedef struct course
{
float ics;
float pdp;
float ds;
float dl;
}COURSE;*/
void caculate_aver(STUDENT *stu,int n)
{
double ics_total=0;
double pdp_total=0;
double ds_total=0;
double dl_total=0;
for(int i=0;i<=n-1;i++)
{
ics_total+=stu[i].score.ics;
pdp_total+=stu[i].score.pdp;
ds_total+=stu[i].score.ds;
dl_total+=stu[i].score.dl;
}
double ics_aver=ics_total/n;
double pdp_aver=pdp_total/n;
double ds_aver=ds_total/n;
double dl_aver=dl_total/n;
printf("该班级ics课程平均成绩为:%.2lf,\npdp课程平均成绩为:%.2lf,\nds课程平均成绩为:%.2lf,\ndl课程平均成绩为:%.2lf,\n",ics_aver,pdp_aver,ds_aver,dl_aver);
}
输入:结构体数组指针stu,学生数量n
输出:null
功能:计算各科平均成绩
2.2.6成绩排序(4分)
任意一科成绩为准进行降序排序。
相关函数代码与说明:
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
void sort_dl(STUDENT *stu, int n)
{
for (int i = 1; i < n; i++)
{
STUDENT temp = stu[i];
int k = i - 1;
while (k >= 0 && stu[k].score.dl < temp.score.dl)
{
stu[k + 1] = stu[k];
k--;
}
stu[k + 1] = temp;
}
}
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
void sort_ds(STUDENT *stu, int n)
{
for (int i = 1; i < n; i++)
{
STUDENT temp = stu[i];
int k = i - 1;
while (k >= 0 && stu[k].score.ds < temp.score.ds)
{
stu[k + 1] = stu[k];
k--;
}
stu[k + 1] = temp;
}
}
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
void sort_ics(STUDENT *stu, int n)
{
for (int i = 1; i < n; i++)
{
STUDENT temp = stu[i];
int k = i - 1;
while (k >= 0 && stu[k].score.ics < temp.score.ics)
{
stu[k + 1] = stu[k];
k--;
}
stu[k + 1] = temp;
}
}
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
void sort_pdp(STUDENT *stu, int n)
{
for (int i = 1; i < n; i++)
{
STUDENT temp = stu[i];
int k = i - 1;
while (k >= 0 && stu[k].score.pdp < temp.score.pdp)
{
stu[k + 1] = stu[k];
k--;
}
stu[k + 1] = temp;
}
}
输入:结构体数组指针stu,学生数量n
输出:null
功能:插入排序实现成绩降序。这里我一时没有想到更好的办法,于是干脆对四门课程各自封装了排序函数,从main函数中实现判断并调用。
2.2.7成绩统计分析(4分)
按五个类别,对每科成绩分别统计每个类别的人数及所占的百分比。
相关函数代码与说明:
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
#include <string.h> // 包含字符串操作的头文件
void analysis(STUDENT *stu, int n) {
float *s[4];
s[0] = &(stu->score.ics);
s[1] = &(stu->score.pdp);
s[2] = &(stu->score.ds);
s[3] = &(stu->score.dl);
char str[4][5];
strcpy(str[0], "ics");
strcpy(str[1], "pdp");
strcpy(str[2], "ds");
strcpy(str[3], "dl");
for (int j = 0; j <= 3; j++) {
int exe = 0;
int good = 0;
int mid = 0;
int pass = 0;
int bad = 0;
for (int i = 0; i <= n - 1; i++) {
float ans = *(s[j] + i); // 获取分数
if (ans >= 90 && ans <= 100)
exe++;
else if (ans >= 80 && ans <= 89)
good++;
else if (ans >= 70 && ans <= 79)
mid++;
else if (ans >= 60 && ans <= 69)
pass++;
else
bad++;
}
printf("科目:%s\n", str[j]);
printf("优秀成绩人数:%d, 优秀成绩百分比:%.2f%%\n", exe, ((float)exe / n) * 100);
printf("良好成绩人数:%d, 良好成绩百分比:%.2f%%\n", good, ((float)good / n) * 100);
printf("中等成绩人数:%d, 中等成绩百分比:%.2f%%\n", mid, ((float)mid / n) * 100);
printf("及格成绩人数:%d, 及格成绩百分比:%.2f%%\n", pass, ((float)pass / n) * 100);
printf("不及格成绩人数:%d, 不及格成绩百分比:%.2f%%\n", bad, ((float)bad / n) * 100);
printf("****************************************\n");
}
}
输入:结构体数组指针stu,学生数量n
输出:null
功能:分析成绩
注意有关字符串操作在头文件<string.h>中包含。
strcpy()是一个C语言标准库函数,用于将源字符串复制到目标字符串。它的函数原型如下:
char *strcpy(char *dest, const char *src);
参数说明:
dest:目标字符串的指针。
src:源字符串的指针。
strcpy()函数会将源字符串的内容复制到目标字符串中,包括终止字符'\0'。函数返回目标字符串的指针。
2.2.8成绩保存到本地文件
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
/*typedef struct course
{
float ics;
float pdp;
float ds;
float dl;
}COURSE;
typedf struct student
{
unsigned long id;
char name[256];
COURSE score;
}STUDENT;*/
void save(STUDENT *stu, int n, char *fn)
{
FILE *file = fopen(fn, "w");
if (file == NULL) {
printf("无法打开文件!\n");
return;
}
for (int i = 0; i < n; i++)
{
fprintf(file, "%ld %s %f %f %f %f\n", stu[i].id, stu[i].name, stu[i].score.ics, stu[i].score.pdp, stu[i].score.ds, stu[i].score.dl);
}
printf("success to save!\n");
fclose(file);
}
附:manage.h代码
typedef struct course
{
float ics;
float pdp;
float ds;
float dl;
}COURSE;
typedef struct student
{
unsigned long id;
char name[256];
COURSE score;
}STUDENT;
typedef struct answer
{
STUDENT *stun;
int num;
}ans;
STUDENT* append_record(int n);
STUDENT* search_by_name(STUDENT * stu,int n,char * name);
STUDENT* search_by_id(STUDENT * stu,int n,unsigned long iid);
int modify(STUDENT *stu,int n,STUDENT *stu1);
int delect(STUDENT *stu,int n,STUDENT *stu1);
void caculate_total(STUDENT *stu,int n);
void caculate_aver(STUDENT *stu,int n);
void sort_ics(STUDENT *stu, int n);
void sort_pdp(STUDENT *stu, int n);
void sort_ds(STUDENT *stu, int n);
void sort_dl(STUDENT *stu, int n);
void print(STUDENT *stu,int n);
void analysis(STUDENT *stu,int n);
void save(STUDENT *stu, int n, char *fn) ;
ans load(char *fn);
makefile
CC = gcc -m64 -w
#.. What optimization level for the compilers?
#COPT = -O2
COPT = -g
GRARC = main.a
GRSRCS = append_record.c load.c modify.c delect.c caculate_total.c caculate_aver.c sort_ics.c sort_pdp.c sort_ds.c sort_dl.c print.c analysis.c save.c search_by_name.c search_by_id.c main.c
GROBJS = append_record.o load.o modify.o delect.o caculate_total.o caculate_aver.o sort_ics.o sort_pdp.o sort_ds.o sort_dl.o print.o analysis.o save.o search_by_name.o search_by_id.o main.o
HEADER = manage.h
runfile: $(GROBJS)
$(CC) $(COPT) -o runfile $(GROBJS)
main.o: main.c manage.h
$(CC) $(COPT) -c main.c -o main.o
append_record.o: append_record.c manage.h
$(CC) $(COPT) -c append_record.c -o append_record.o
load.o: load.c manage.h
$(CC) $(COPT) -c load.c -o load.o
modify.o: modify.c manage.h
$(CC) $(COPT) -c modify.c -o modify.o
delect.o: delect.c manage.h
$(CC) $(COPT) -c delect.c -o delect.o
caculate_total.o: caculate_total.c manage.h
$(CC) $(COPT) -c caculate_total.c -o caculate_total.o
caculate_aver.o: caculate_aver.c manage.h
$(CC) $(COPT) -c caculate_aver.c -o caculate_aver.o
sort_ics.o: sort_ics.c manage.h
$(CC) $(COPT) -c sort_ics.c -o sort_ics.o
sort_pdp.o: sort_pdp.c manage.h
$(CC) $(COPT) -c sort_pdp.c -o sort_pdp.o
sort_ds.o: sort_ds.c manage.h
$(CC) $(COPT) -c sort_ds.c -o sort_ds.o
sort_dl.o: sort_dl.c manage.h
$(CC) $(COPT) -c sort_dl.c -o sort_dl.o
print.o: print.c manage.h
$(CC) $(COPT) -c print.c -o print.o
analysis.o: analysis.c manage.h
$(CC) $(COPT) -c analysis.c -o analysis.o
save.o: save.c manage.h
$(CC) $(COPT) -c save.c -o save.o
search_by_name.o: search_by_name.c manage.h
$(CC) $(COPT) -c search_by_name.c -o search_by_name.o
search_by_id.o: search_by_id.c manage.h
$(CC) $(COPT) -c search_by_id.c -o search_by_id.o
clean :
print函数
#include <stdio.h>
#include <stdlib.h>
#include "manage.h"
void print(STUDENT *stu,int n)
{
for(int i=0;i<=n-1;i++)
{
printf("该学生的学号为%ld,姓名为:%s,ics课程成绩为%.2f,pdp课程成绩为%.2f,ds课程成绩为%.2f,dl课程成绩为%.2f\n",stu[i].id,stu[i].name,stu[i].score.ics,stu[i].score.pdp,stu[i].score.ds,stu[i].score.dl);
}
}
很简单,但建议单独封装出来,不然会在各种奇奇怪怪的地方报错。
main函数
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include "manage.h"
/*头函数部分*/
/*typedef struct course
{
float ics;
float pdp;
float ds;
float dl;
}COURSE;
typedef struct student
{
unsigned long id;
char name[256];
COURSE score;
}STUDENT;
typedef struct answer
{
STUDENT *stun;
int num;
}ans;*/
STUDENT* append_record(int n);
STUDENT* search_by_name(STUDENT * stu,int n,char * name);
STUDENT* search_by_id(STUDENT * stu,int n,unsigned long iid);
int modify(STUDENT *stu,int n,STUDENT *stu1);
int delect(STUDENT *stu,int n,STUDENT *stu1);
void caculate_total(STUDENT *stu,int n);
void caculate_aver(STUDENT *stu,int n);
void sort_ics(STUDENT *stu, int n);
void sort_pdp(STUDENT *stu, int n);
void sort_ds(STUDENT *stu, int n);
void sort_dl(STUDENT *stu, int n);
void print(STUDENT *stu,int n);
void analysis(STUDENT *stu,int n);
void save(STUDENT *stu, int n, char *fn) ;
ans load(char *fn);
/*函数声明和结构体定义*/
int main()
{
int card=0;
STUDENT *stu;
int n=0;
START:
while(1)
{
printf("1. Append record\n");
printf("2. Search by name\n");
printf("3. Search by ID\n");
printf("4. Modify by ID\n");
printf("5. Delete by ID\n");
printf("6. Caculate total and average score of every student\n");
printf("7. Caculate average score of every course\n");
printf("8. Sort in descending order by course score\n");
printf("9. Statistic analysis for every course\n");
printf("10.Save record\n");
printf("11.Load record\n");
printf("0. Exit\n");
printf("Please enter your choice:\n");
scanf("%d",&card);
switch(card)
{
case 1:
printf("请输入学生数量\n");
scanf("%d",&n);
stu=append_record(n);
if(stu!=NULL)
{printf("学生信息录入成功!\n");
goto START;}
else
{printf("录入失败!");
break;}
case 2:
printf("请输入学生的姓名:\n");
char name[256];
scanf("%s",name);
//STUDENT *stu2;
STUDENT *stu2=(STUDENT *)malloc(sizeof(STUDENT));
stu2=search_by_name(stu,n,name);
if (stu2==NULL)
{
printf("没有找到这个学生\n");
}
else
{
printf("该学生的学号为%ld,ics课程成绩为%.2f,pdp课程成绩为%.2f,ds课程成绩为%.2f,dl课程成绩为%.2f\n",stu2->id,stu2->score.ics,stu2->score.pdp,stu2->score.ds,stu2->score.dl);
// free(stu2);
}
break;
case 3:
printf("请输入学生的学号:\n");
unsigned long iid=0;
scanf("%ld",&iid);
STUDENT *stu3=(STUDENT *)malloc(sizeof(STUDENT));
stu3=search_by_id(stu,n,iid);
if(stu3==NULL)
{
printf("没有找到这个学生\n");
}
else
{
printf("该学生的学号为%ld,ics课程成绩为%.2f,pdp课程成绩为%.2f,ds课程成绩为%.2f,dl课程成绩为%.2f\n",stu3->id,stu3->score.ics,stu3->score.pdp,stu3->score.ds,stu3->score.dl);
//free(stu3);
}
break;
case 4:
printf("请输入要修改的学生的id,以及修改后的ics、pdp、ds、dl成绩\n");
STUDENT *stu4 = (STUDENT *)malloc(sizeof(STUDENT));
if (stu4 == NULL)
{
printf("内存分配失败!\n");
goto START;
}
if (scanf("%ld %f %f %f %f", &stu4->id, &stu4->score.ics, &stu4->score.pdp, &stu4->score.ds, &stu4->score.dl) != 5)
{
printf("输入无效!\n");
free(stu4);
goto START;
}
int re=modify(stu,n,stu4);
if(re==0)
{
printf("没有找到该学生!\n");
}
else
{
printf("修改成功!\n");
}
free(stu4);
break;
case 5:
printf("请输入要删除的学生的id\n");
STUDENT *stu5=(STUDENT *)malloc(sizeof(STUDENT));
if (stu5 == NULL)
{
printf("内存分配失败!\n");
goto START;
}
fflush(stdin);
scanf("%ld", &stu5->id);
int ret=delect(stu,n,stu5);
if(ret==0)
{
printf("没有找到该学生!\n");
}
else
{
printf("删除成功!\n");
n--;
}
free(stu5);
break;
case 6 :
if(n==0)
{
printf("NO student!\n");
goto START;
}
else
{
caculate_total(stu,n);
break;
}
case 7:
if(n==0)
{
printf("NO student!\n");
goto START;
}
else
{
caculate_aver(stu,n);
break;
}
case 8:
printf("请输入要计算的课程名称:ics、pdp、ds或dl\n");
char sub[32];
scanf("%s", sub);
if (strcmp(sub, "ics") == 0)
{
sort_ics(stu,n);
print(stu, n);
break;
}
else if (strcmp(sub, "pdp") == 0)
{
sort_pdp(stu, n);
print(stu, n);
break;
}
else if (strcmp(sub, "ds") == 0)
{
sort_ds(stu, n);
print(stu, n);
break;
}
else if (strcmp(sub, "dl") == 0)
{
sort_dl(stu,n);
print(stu, n);
break;
}
else
{
printf("输入错误!请输入正确的课程!\n");
break;
}
case 9:
if(n==0)
{
printf("NO student!\n");
goto START;
}
else
{
analysis(stu,n);
break;
}
case 10:
printf("请输入要保存到的文件名\n");
char fn10[256];
scanf("%s",fn10);
save(stu,n,&fn10);
break;
case 11:
printf("请输入要读取的文件名\n");
char fn11[256];
scanf("%s",fn11);
ans rete;
rete=load(&fn11);
n=rete.num;
stu=rete.stun;
printf("success to load!\n");
break;
case 0:
printf("success to quit!\n");
goto END;
default:
printf("input wrong!please input the right number!\n");
break;
}
}
END:
return 0;
}
使用while(1)的死循环和goto语句实现反复操作和退出程序。在各个函数中,一定要注意申请完的动态内存在结束前要释放掉。对全局变量的改动要当心。