一、题目内容
数据存储要求:
要求至少能够存储学生的学号、姓名、班级、实验1成绩、实验2成绩、实验3成绩,总分;也可以根据个人理解增加其他需要存储的信息。
基本功能:
1、学生名单管理:
①添加学生信息:录入学生的学号、姓名和班级;录入前先检测学生学号,如果学号已存在则提示学生已存在,输入新的学生信息。
②删除学生信息:先按照学生学号进行查找,找到,则删除学生信息(如果学生已有实验成绩,则实验成绩和总分也删除);找不到,给出提示信息。
③修改学生信息,先按照学生学号进行查找,找到对应的学生,先显示学生所有信息再选择修改姓名或者班级;找不到,给出提示信息。
④根据学号或姓名查询学生的信息,要求输出学号、姓名、班级。
⑤显示所有学生信息。
2、实验成绩管理:
①录入实验成绩,先输入要录入的学生学号,再选择录入实验1、实验2或者实验3成绩;如果学生学号不存在,则提示不存在。
②删除实验成绩,删除某个学生某一次实验的成绩。
③修改修改成绩,修改某个学生某一次实验的成绩。
④查找某个学生的成绩,根据学号进行查找,找到,则显示该生的姓名、学号、班级、实验1成绩、实验2成绩和实验3成绩;找不到,则给出提示信息。
⑤输出每个实验排名前三的学生学号和姓名;
⑥输出每个班级每次实验的平均分,输入如下信息:班级、实验1平均分、实验2平均分、实验3平均分。
⑦按照总分对于学生成绩进行降序排列,并输出学生成绩表,成绩表包含学号、姓名、班级和总分。
3、扩展功能:
①输出有一次实验不及格的学生信息;2次实验不及格的学生。
②可以用文件获取数据,每次程序运行开始时,把文件中存储的学生信息读入内存;程序退出时,先把内存中存储的学生信息保存在文件中,然后再结束程序。
③可自己定义其他功能需求,使系统功能更加完善。
二、程序代码
#define _CRT_SECURE_NO_WARNINGS
#define MAX_STUDENTS 100
#define MAX_NAME_LENGTH 50
#define MAX_CLASS_LENGTH 20
#define MAX_EXPERIMENTS 3
#define PASSING_SCORE 60
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<time.h>
struct student
{
int student_id;
char student_name[MAX_NAME_LENGTH];
char student_class[MAX_CLASS_LENGTH];
double experiment_scores[3];
double total_score;
};
struct student students[MAX_STUDENTS];
int num_students = 0;
//声明函数,以便于函数的调用
void read_student_data();
void add_student();
void delete_student();
void modify_student();
void search_student();
void display_all_students();
void enter_student_scores();
void delete_student_score();
void modify_student_score();
void find_student_by_id();
void display_top_three(int experiment_index);
void calculate_class_average();
void display_student_scores();
void display_failed_students(int num_failures);
int main()
{
read_student_data();
int choice;
do {
printf("\n======= 实验成绩统计系统 =======\n");
printf("1. 学生名单管理\n");
printf("2. 实验成绩管理\n");
printf("3. 扩展功能\n");
printf("0. 退出\n");
printf("请选择功能:");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("\n======= 学生名单管理 =======\n");
printf("1. 添加学生信息\n");
printf("2. 删除学生信息\n");
printf("3. 修改学生信息\n");
printf("4. 根据学号或姓名查询学生信息\n");
printf("5. 显示所有学生信息\n");
printf("请选择功能:");
scanf("%d", &choice);
switch (choice) {
case 1:
add_student();
break;
case 2:
delete_student();
break;
case 3:
modify_student();
break;
case 4:
printf("请输入要查询的学生姓名或学号:");
char keyword[50];
scanf("%s", keyword);
search_student(keyword);
break;
case 5:
display_all_students();
break;
default:
printf("无效的选项,请重新选择。\n");
}
break;
case 2:
printf("\n======= 实验成绩管理 =======\n");
printf("1. 录入实验成绩\n");
printf("2. 删除实验成绩\n");
printf("3. 修改实验成绩\n");
printf("4. 根据学号查询实验成绩\n");
printf("5. 输出每个实验排名前三的学生\n");
printf("6. 输出每个班级每次实验的平均分\n");
printf("7. 按照总分降序排列学生成绩制表\n");
printf("请选择功能:");
scanf("%d", &choice);
switch (choice) {
case 1:
enter_student_scores();
break;
case 2:
delete_student_score();
break;
case 3:
modify_student_score();
break;
case 4:
find_student_by_id();
break;
case 5:
// 输出每个实验排名前三的学生学号和姓名
for (int i = 0; i < 3; i++) {
display_top_three(i);
}
break;
case 6:
calculate_class_average();
break;
case 7:
display_student_scores();
break;
default:
printf("无效的选项,请重新选择。\n");
}
break;
case 3:
printf("\n======= 扩展功能 =======\n");
printf("1. 输出有一次实验不及格的学生信息\n");
printf("2. 输出两次实验不及格的学生信息\n");
printf("请选择功能:");
scanf("%d", &choice);
switch (choice) {
case 1:
display_failed_students(1);
break;
case 2:
display_failed_students(2);
break;
default:
printf("无效的选项,请重新选择。\n");
}
break;
case 0:
printf("感谢使用,再见!\n");
break;
default:
printf("无效的选项,请重新选择。\n");
}
} while (choice != 0);
return 0;
}
//一、学生名单管理
//1、添加学生信息
void add_student()
{
//检测存储是否已满
if (num_students >= MAX_STUDENTS)
{
printf("学生信息已满,无法添加。\n");
printf("如果希望添加更多的学生,请修改 MAX_STUDENTS 的值");
return;
}
// 检查学号是否已存在
for (int i = 0; i < num_students; i++) {
printf("请输入学生信息:\n");
printf("学号:");
int new_id;
scanf("%d", &new_id);
if (students[i].student_id == new_id) {
printf("该学生已存在,请重新输入。\n");
}
else {
break;
}
}
//对结构体数组进行赋值
printf("请再确认学号:");
scanf("%d", &students[num_students].student_id);
printf("姓名:");
scanf("%s", &students[num_students].student_name);
printf("班级:");
scanf("%s", &students[num_students].student_class);
students[num_students].experiment_scores[0] = 0.0;
students[num_students].experiment_scores[1] = 0.0;
students[num_students].experiment_scores[2] = 0.0;
students[num_students].total_score = 0.0;
num_students++;
//将结构体数组完全再一次存入文件中
FILE* file = fopen("D:/students.txt", "w");
if (file == NULL)
{
printf("无法打开文件进行写入。\n");
return;
}
for (int i = 0; i < num_students; i++)
{
fprintf(file, "%d %s %s %.2f %.2f %.2f %.2f\n",
students[i].student_id,
students[i].student_name,
students[i].student_class,
students[i].experiment_scores[0],
students[i].experiment_scores[1],
students[i].experiment_scores[2],
students[i].total_score);
}
fflush(file);
printf("学生信息添加成功。\n");
}
//2、删除学生信息
void delete_student()
{
int found = 0;
int student_id;
printf("请输入要删除的学生学号:");
scanf("%d", &student_id);
for (int i = 0; i < num_students; i++) {
if (students[i].student_id == student_id) {
found = 1;
// 将最后一个学生信息移到当前位置,然后减少学生数量
students[i] = students[num_students - 1];
num_students--;
printf("学生信息删除成功。\n");
break;
}
}
if (!found) {
printf("未找到学号为 %d 的学生信息。\n", student_id);
}
//将结构体数组完全再一次存入文件中
FILE* file = fopen("D:/students.txt", "w");
if (file == NULL) {
printf("无法打开文件进行写入。\n");
return;
}
for (int i = 0; i < num_students; i++)
{
fprintf(file, "%d %s %s %.2f %.2f %.2f %.2f\n",
students[i].student_id,
students[i].student_name,
students[i].student_class,
students[i].experiment_scores[0],
students[i].experiment_scores[1],
students[i].experiment_scores[2],
students[i].total_score);
}
fflush(file);
printf("学生信息删除成功。\n");
}
//3、修改学生信息
void modify_student()
{
int found = 0;
int student_id;
printf("请输入要修改的学生学号:");
scanf("%d", &student_id);
for (int i = 0; i < num_students; i++) {
if (students[i].student_id == student_id) {
found = 1;
printf("请输入新的学生信息:\n");
printf("姓名:");
scanf("%s", students[i].student_name);
printf("班级:");
scanf("%s", students[i].student_class);
printf("学生信息修改成功。\n");
break;
}
}
if (!found) {
printf("未找到学号为 %d 的学生信息。\n", student_id);
}
//将结构体数组完全再一次存入文件中
FILE* file = fopen("D:/students.txt", "w");
if (file == NULL) {
printf("无法打开文件进行写入。\n");
return;
}
for (int i = 0; i < num_students; i++)
{
fprintf(file, "%d %s %s %.2f %.2f %.2f %.2f\n",
students[i].student_id,
students[i].student_name,
students[i].student_class,
students[i].experiment_scores[0],
students[i].experiment_scores[1],
students[i].experiment_scores[2],
students[i].total_score);
}
fflush(file);
printf("学生信息修改成功。\n");
}
//4、以学号查询学生信息
void search_student(const char* keyword)
{
int found = 0;
for (int i = 0; i < num_students; i++)
{
//atoi函数将字符串转换成整型数据
if (strcmp(students[i].student_name, keyword) == 0 || students[i].student_id == atoi(keyword))
{
found = 1;
printf("学号:%d,姓名:%s,班级:%s\n",
students[i].student_id, students[i].student_name, students[i].student_class);
break;
}
}
if (!found)
{
printf("未找到与关键词匹配的学生信息。\n");
}
}
//5、显示所有学生信息
void display_all_students()
{
//检测学生信息是否为空
if (num_students == 0) {
printf("学生信息为空。\n");
return;
}
//打印学生信息
printf("所有学生信息如下:\n");
for (int i = 0; i < num_students; i++)
{
printf("学号:%d,姓名:%s,班级:%s\n",
students[i].student_id, students[i].student_name, students[i].student_class);
}
}
//二、实验成绩管理
//1、录入实验成绩
//因为我们在添加学生信息的时候,已经为学生成绩初始化赋值
//所以我们在录入实验成绩的时候,本质时修改学生成绩
//我们只需修改中文指引即可完成相应功能
void enter_student_scores()
{
//检测有无学生信息
if (num_students == 0) {
printf("没有学生信息可供录入成绩。\n");
return;
}
//录入学生成绩
printf("请输入要录入成绩的学生学号:");
int student_id;
scanf("%d", &student_id);
printf("请输入要录入的实验次数(1、2或3):");
int experiment_number;
scanf("%d", &experiment_number);
int found = 0;
for (int i = 0; i < num_students; i++)
{
if (students[i].student_id == student_id)
{
if (experiment_number >= 1 && experiment_number <= 3)
{
printf("请输入实验%d成绩:", experiment_number);
scanf("%lf", &students[i].experiment_scores[experiment_number - 1]);
// 更新总分
students[i].total_score = students[i].experiment_scores[0] + students[i].experiment_scores[1] + students[i].experiment_scores[2];
printf("学生 %s 的实验%d成绩已成功录入。\n", students[i].student_name, experiment_number);
found = 1;
}
else {
printf("请输入有效的实验次数(1、2或3)!\n");
}
break;
}
}
if (!found) {
printf("未找到学号为 %d 的学生信息。\n", student_id);
}
//将结构体数组完全再一次存入文件中
FILE* file = fopen("D:/students.txt", "w");
if (file == NULL) {
printf("无法打开文件进行写入。\n");
return;
}
for (int i = 0; i < num_students; i++)
{
fprintf(file, "%d %s %s %.2f %.2f %.2f %.2f\n",
students[i].student_id,
students[i].student_name,
students[i].student_class,
students[i].experiment_scores[0],
students[i].experiment_scores[1],
students[i].experiment_scores[2],
students[i].total_score);
}
fflush(file);
printf("学生成绩录入成功。\n");
}
//2、删除实验成绩
void delete_student_score()
{
//检测有无学生信息
if (num_students == 0) {
printf("没有学生信息可供删除成绩。\n");
return;
}
//删除学生成绩
printf("请输入要删除成绩的学生学号:");
int student_id;
scanf("%d", &student_id);
printf("请输入要删除的实验次数(1、2或3):");
int experiment_number;
scanf("%d", &experiment_number);
int found = 0;
for (int i = 0; i < num_students; i++) {
if (students[i].student_id == student_id) {
if (experiment_number >= 1 && experiment_number <= 3) {
students[i].experiment_scores[experiment_number - 1] = 0;
printf("学生 %s 的实验%d成绩已成功删除。\n", students[i].student_name, experiment_number);
found = 1;
// 更新总分
students[i].total_score = students[i].experiment_scores[0] + students[i].experiment_scores[1] + students[i].experiment_scores[2];
}
else {
printf("请输入有效的实验次数(1、2或3)!\n");
}
break;
}
}
if (!found) {
printf("未找到学号为 %d 的学生信息。\n", student_id);
}
//将结构体数组完全再一次存入文件中
FILE* file = fopen("D:/students.txt", "w");
if (file == NULL) {
printf("无法打开文件进行写入。\n");
return;
}
for (int i = 0; i < num_students; i++)
{
fprintf(file, "%d %s %s %.2f %.2f %.2f %.2f\n",
students[i].student_id,
students[i].student_name,
students[i].student_class,
students[i].experiment_scores[0],
students[i].experiment_scores[1],
students[i].experiment_scores[2],
students[i].total_score);
}
fflush(file);
printf("学生成绩删除成功。\n");
}
//3、修改学生成绩
void modify_student_score()
{
//检测有无学生信息
if (num_students == 0) {
printf("没有学生信息可供修改成绩。\n");
return;
}
//修改学生成绩
printf("请输入要修改成绩的学生学号:");
int student_id;
scanf("%d", &student_id);
printf("请输入要修改的实验次数(1、2或3):");
int experiment_number;
scanf("%d", &experiment_number);
int found = 0;
for (int i = 0; i < num_students; i++)
{
if (students[i].student_id == student_id)
{
if (experiment_number >= 1 && experiment_number <= 3)
{
printf("请输入新的实验%d成绩:", experiment_number);
scanf("%lf", &students[i].experiment_scores[experiment_number - 1]);
// 更新总分
students[i].total_score = students[i].experiment_scores[0] + students[i].experiment_scores[1] + students[i].experiment_scores[2];
printf("学生 %s 的实验%d成绩已成功修改。\n", students[i].student_name, experiment_number);
found = 1;
}
else {
printf("请输入有效的实验次数(1、2或3)!\n");
}
break;
}
}
if (!found) {
printf("未找到学号为 %d 的学生信息。\n", student_id);
}
//将结构体数组完全再一次存入文件中
FILE* file = fopen("D:/students.txt", "w");
if (file == NULL) {
printf("无法打开文件进行写入。\n");
return;
}
for (int i = 0; i < num_students; i++)
{
fprintf(file, "%d %s %s %.2f %.2f %.2f %.2f\n",
students[i].student_id,
students[i].student_name,
students[i].student_class,
students[i].experiment_scores[0],
students[i].experiment_scores[1],
students[i].experiment_scores[2],
students[i].total_score);
}
fflush(file);
printf("学生成绩修改成功。\n");
}
//4、查找学生的成绩
void find_student_by_id()
{
//检测有无学生信息
if (num_students == 0) {
printf("没有学生信息可供查找成绩。\n");
return;
}
//查找学生信息
printf("请输入要查找成绩的学生学号:");
int student_id;
scanf("%d", &student_id);
int found = 0;
for (int i = 0; i < num_students; i++) {
if (students[i].student_id == student_id) {
printf("姓名:%s\n", students[i].student_name);
printf("学号:%d\n", students[i].student_id);
printf("班级:%s\n", students[i].student_class);
printf("实验1成绩:%.2f\n", students[i].experiment_scores[0]);
printf("实验2成绩:%.2f\n", students[i].experiment_scores[1]);
printf("实验3成绩:%.2f\n", students[i].experiment_scores[2]);
found = 1;
break;
}
}
if (!found) {
printf("未找到学号为 %d 的学生信息。\n", student_id);
}
}
//5、输出每班实验前三的学生学号和姓名
void display_top_three(int experiment_index)
{
// 对特定实验成绩进行排序
for (int i = 0; i < num_students - 1; i++)
{
for (int j = 0; j < num_students - i - 1; j++)
{
if (students[j].experiment_scores[experiment_index] < students[j + 1].experiment_scores[experiment_index])
{
// 交换学生信息
struct student temp;
temp = students[j];
students[j] = students[j + 1];
students[j + 1] = temp;
}
}
}
// 输出排名前三的学生学号和姓名
printf("实验%d排名前三的学生信息如下:\n", experiment_index + 1);
for (int i = 0; i < num_students && i < 3; i++)
{
printf("排名%d: 学号: %d, 姓名: %s, 成绩: %.2f\n", i + 1, students[i].student_id,
students[i].student_name, students[i].experiment_scores[experiment_index]);
}
}
//6、输出每个班级每次实验的平均分
void calculate_class_average()
{
int class_printed[MAX_STUDENTS] = { 0 }; // 记录每个班级是否已经输出过
// 遍历所有班级
for (int i = 0; i < num_students; i++) {
if (!class_printed[i]) { // 如果该班级未输出过
char current_class[MAX_CLASS_LENGTH];
strcpy(current_class, students[i].student_class);
double total_score[MAX_EXPERIMENTS] = { 0 };
int count[MAX_EXPERIMENTS] = { 0 };
// 遍历所有学生
for (int j = 0; j < num_students; j++) {
// 如果班级匹配,则计算总分
if (strcmp(students[j].student_class, current_class) == 0) {
for (int k = 0; k < MAX_EXPERIMENTS; k++) {
total_score[k] += students[j].experiment_scores[k];
if (students[j].experiment_scores[k] != -1) { // -1表示该学生没有参加该次实验
count[k]++;
}
}
}
}
// 输出每个班级每次实验的平均分
printf("班级:%s\n", current_class);
for (int k = 0; k < MAX_EXPERIMENTS; k++)
{
if (count[k] != 0)
{ // 避免除以0
double average_score = total_score[k] / count[k];
printf("实验%d平均分:%.2f\n", k + 1, average_score);
}
else
{
printf("实验%d平均分:暂无数据\n", k + 1);
}
}
printf("\n");
// 标记该班级已经输出过
for (int j = 0; j < num_students; j++)
{
if (strcmp(students[j].student_class, current_class) == 0)
{
class_printed[j] = 1;
}
}
}
}
}
//7、对学生成绩进行降序排列
void display_student_scores()
{
for (int i = 0; i < num_students - 1; i++)
{
for (int j = 0; j < num_students - i - 1; j++)
{
if (students[j].total_score < students[j + 1].total_score)
{
// 交换位置
struct student temp;
temp = students[j];
students[j] = students[j + 1];
students[j + 1] = temp;
}
}
}
printf("学号\t\t姓名\t班级\t总分\n");
for (int i = 0; i < num_students; i++)
{
printf("%d\t%s\t%s\t%.2lf\n",
students[i].student_id, students[i].student_name, students[i].student_class, students[i].total_score);
}
}
//三、扩展内容
//1、查找实验不及格学生信息
void display_failed_students(int num_failures)
{
printf("以下是%d次实验不及格的学生信息:\n", num_failures);
printf("学号\t\t姓名\t班级\n");
for (int i = 0; i < num_students; i++)
{
int num_fails = 0;
for (int j = 0; j < MAX_EXPERIMENTS; j++)
{
if (students[i].experiment_scores[j] < PASSING_SCORE)
{
num_fails++;
}
}
if (num_fails == num_failures)
{
printf("%d\t%s\t%s\n", students[i].student_id, students[i].student_name, students[i].student_class);
}
}
}
//2、将文件信息读取到内存
void read_student_data()
{
FILE* file = fopen("D:/students.txt", "r");
if (file == NULL) {
printf("无法打开文件\n");
return;
}
//读取文件的时候,我们要将文件编码格式改为ANSI保存,才能正常读取中文
while (fscanf(file, "%d %s %s %lf %lf %lf %lf",
&students[num_students].student_id,
&students[num_students].student_name,
&students[num_students].student_class,
&students[num_students].experiment_scores[0],
&students[num_students].experiment_scores[1],
&students[num_students].experiment_scores[2],
&students[num_students].total_score) == 7) {
printf("学生信息:%d %s %s %.2lf %.2lf %.2lf %.2lf\n",
students[num_students].student_id,
students[num_students].student_name,
students[num_students].student_class,
students[num_students].experiment_scores[0],
students[num_students].experiment_scores[1],
students[num_students].experiment_scores[2],
students[num_students].total_score);
num_students++;
if (num_students >= MAX_STUDENTS) {
printf("学生数量超过最大限制\n");
break;
}
}
fclose(file);
}
三、注意事项
1、该程序使用文本文档读取与存储数据,需要在D盘底下创建一个students.txt文件。
2、students.txt文件的编码方式要从默认的UTF-8转换为ANSI;否则会乱码。具体如何转换,下一篇文章会作详细介绍。
3、学号使用int类型变量存储,int的取值范围是“-2147483648 ~ 2147483647”,学号不要超过这个范围。