#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define PERSON_MAX_COUNT 100
#define EXIT_CODE -1
#define VALID_DATA 1
#define INVALID_DATA 0
#define TRUE 0
#define FALSE -1
#define ArrayLength(type, array) sizeof(array)/sizeof(type)
// 学生
typedef struct student
{
// 学号
int id;
// 姓名
char* name;
// 注意:使用`char* name`是为了能够存储变长的字符串,而不限制字符串的长度。如果使用`char name`,则只能存储固定长度的字符串,例如`char name[20]`只能存储长度为20的字符串,而无法存储超过20个字符的字符串。
// 另外,使用`char* name`还可以动态分配内存,根据实际需要来分配字符串的长度,避免浪费内存空间。而使用`char name`则需要提前确定字符串的长度,可能会浪费内存或者无法满足实际需求。
// 性别
short sex;
} student;
// 成绩
typedef struct score
{
// 记录编号
int id;
// 语文
int chinese;
// 数学
int math;
// 总分
int score;
} score;
// 学生成绩对应关系
typedef struct student_score
{
// 学号
int student_record_id; // 即student结构体中的id
// 学生对应的成绩记录编号
int score_record_id; // 即score结构体中的id
// 记录是否有效
short is_valid;
} student_score;
// 菜单
typedef struct menu
{
// 菜单编号
int index;
// 菜单标题
char* menu_title;
// 菜单处理函数
void (*show)();
// 注解:定义了一个指向无返回值、无参数的函数的指针。
// 这个函数指针可以用来指向一个具体的函数,然后通过调用该函数指针来执行相应的操作。
// 在这个结构体中,show成员变量用来存储一个菜单项的处理函数。
// 通过使用函数指针,可以将不同的处理函数与不同的菜单项关联起来,使得菜单项可以执行不同的操作。
// 当用户选择某个菜单项时,可以通过调用show函数指针来执行与该菜单项关联的处理函数,实现相应的功能。
} menu;
int current_record_length = 0;
int exit_flag = 0;
student students[PERSON_MAX_COUNT];
score scores[PERSON_MAX_COUNT];
student_score stu_score_records[PERSON_MAX_COUNT];
void refresh_datas();
void show_menu();
void check_select_menu_index(int index);
void add_student();
int get_empty_record();
void add_student_info(int id);
void add_student_score(int id);
void add_student_score_record(int id);
void show_all_student(student_score* array);
void show_student(student_score stu_s);
void find_student();
int find_student_by_id(int student_id);
void delete_student();
int delete_student_record(int index);
void modify_student();
void show_rank_list();
void swap_student(student_score* array, int index1, int index2);
void copy_array(student_score* arr1, student_score* arr2);
void exit_system();
char* get_sex(short sex);
int convert_sex(char* sex);
menu menus[] =
{
{1, "添加学生信息", add_student},
{2, "显示学生信息", show_all_student},
{3, "删除学生信息", delete_student},
{4, "查找学生信息", find_student},
{5, "修改学生信息", modify_student},
{6, "学生成绩排序", show_rank_list},
{7, "退出管理系统", exit_system},
};
void main()
{
int select_index;
refresh_datas();
while (1)
{
show_menu();
scanf("%d", &select_index);
system("cls");
check_select_menu_index(select_index);
if (exit_flag == EXIT_CODE)
{
break;
}
printf("\n\n\n\n");
system("pause");
getchar();
system("cls");
}
return 0;
}
void refresh_datas()
{
int length = ArrayLength(student_score, stu_score_records);
for (int i = 0; i < length; i++)
{
stu_score_records[i].is_valid = INVALID_DATA;
}
}
void show_menu()
{
printf("\
*****************************\n\
****** 学生信息管理系统 *****\n\
*****************************\n\
***** *****\n");
int length = ArrayLength(menu, menus);
for (int i = 0; i < length; i++)
{
printf("***** %d、%s *****\n", (menus[i].index), menus[i].menu_title);
}
printf("\
***** *****\n\
*****************************\n\
\n\n\
请输入菜单编号:");
}
void check_select_menu_index(int index)
{
printf("你选择的选项是:%d\n\n\n\n", index);
int length = ArrayLength(menu, menus);
for (int i = 0; i < length; i++)
{
menu m = menus[i];
if (index == m.index)
{
m.show();
return;
}
}
}
// 系统功能 ******************************************
void add_student()
{
current_record_length++;
if (current_record_length == PERSON_MAX_COUNT)
{
printf("系统记录已满,无法添加");
return;
}
int index = get_empty_record();
add_student_info(index);
add_student_score(index);
add_student_score_record(index);
}
int get_empty_record()
{
int length = ArrayLength(student_score, stu_score_records);
for (int i = 0; i < length; i++)
{
if (stu_score_records[i].is_valid == INVALID_DATA)
{
return i;
}
}
}
void add_student_info(int id)
{
student stu;
printf("请输入学号:");
scanf("%d", &stu.id);
printf("请输入姓名:");
stu.name = (char*)malloc(sizeof(stu.name) * 10);
scanf("%s", stu.name);
char sex;
printf("请输入性别(m/f):");
getchar();
scanf("%c", &sex);
stu.sex = convert_sex(sex);
students[id] = stu;
}
void add_student_score(int id)
{
score s;
s.id = id + 1;
printf("请输入语文成绩:");
scanf("%d", &s.chinese);
printf("请输入数学成绩:");
scanf("%d", &s.math);
s.score = s.chinese + s.math;
scores[id] = s;
}
void add_student_score_record(int id)
{
student_score stu_s;
stu_s.student_record_id = id;
stu_s.score_record_id = id;
stu_score_records[id] = stu_s;
stu_score_records[id].is_valid = VALID_DATA;
}
void show_all_student(student_score* array)
{
if (array == NULL)
{
array = stu_score_records;
}
int length = ArrayLength(student_score, stu_score_records);
printf("学号\t姓名\t性别\t语文\t数学\t总分\n\n");
for (int i = 0; i < length; i++)
{
show_student(array[i]);
}
}
void show_student(student_score stu_s)
{
if (stu_s.is_valid == INVALID_DATA)
{
return;
}
student stu = students[stu_s.student_record_id];
score s = scores[stu_s.score_record_id];
printf("%d\t%s\t%s\t%d\t%d\t%d\n",
stu.id,
stu.name,
get_sex(stu.sex),
s.chinese,
s.math,
s.score);
}
void find_student()
{
int id;
printf("请输入要查找的学生的学号:");
getchar();
scanf("%d", &id);
int index = find_student_by_id(id);
if (index == FALSE)
{
printf("未找到相关学生信息");
return;
}
show_student(stu_score_records[index]);
}
int find_student_by_id(int student_id)
{
int length = ArrayLength(student_score, stu_score_records);
for (int i = 0; i < length; i++)
{
student_score stu_s = stu_score_records[i];
if (students[stu_s.student_record_id].id == student_id)
{
return i;
}
}
return FALSE;
}
void delete_student()
{
int id;
printf("请输入要删除的学生的学号:");
getchar();
scanf("%d", &id);
int index = find_student_by_id(id);
int result = delete_student_record(index);
if (result == TRUE)
{
printf("\n\n删除信息成功\n\n\n\n");
}
else
{
printf("\n\n删除信息失败\n\n\n\n");
}
}
int delete_student_record(int index)
{
if (index == FALSE)
{
return FALSE;
}
stu_score_records[index].is_valid = INVALID_DATA;
current_record_length--;
return TRUE;
}
void modify_student()
{
int id;
printf("请输入要查找的学生的学号:");
getchar();
scanf("%d", &id);
int index = find_student_by_id(id);
if (index == FALSE)
{
printf("未找到相关学生信息");
return;
}
printf("\n\n\n\n学号\t姓名\t性别\t语文\t数学\t总分\n\n");
modify_student_record(index);
}
int modify_student_record(int index)
{
add_student_info(index);
add_student_score(index);
}
void show_rank_list()
{
int length = ArrayLength(student_score, stu_score_records);
student_score* results = (student_score*)malloc(sizeof(student_score) * length);
// 使用malloc函数动态分配了一个大小为sizeof(student_score) * length的内存空间,并将返回的指针赋值给results指针。
copy_array(&results, stu_score_records);// 将stu_score_records数组中的数据复制到results指向的数组中。因为是选择菜单项,因此不能改变原来的数据排列,所以要重新复制一个新的内存空间中进行排序。
// 使用两个嵌套的for循环来遍历results数组。外层循环控制比较的轮数,内层循环用于比较相邻元素的大小。
// 在每次内层循环中,定义了两个student_score类型的变量stu_s1和stu_s2,分别用来存储results数组中第i个和第i+1个元素。
// 然后,通过访问全局变量scores数组,根据stu_s1和stu_s2的score_record_id成员变量,获取到对应的score结构体,并比较两个score的score成员变量的大小。
// 如果stu_s1的score小于stu_s2的score,就调用swap_student函数,交换results数组中第i个和第i+1个元素的位置。
for (int i = 0; i < length - 1; i++)
{
for (int j = i+1; j < length; j++)
{
student_score stu_s1 = results[i];
student_score stu_s2 = results[i + 1];
if (scores[stu_s1.score_record_id].score < scores[stu_s2.score_record_id].score)
{
swap_student(results, i, i + 1);
}
}
}
show_all_student(results); // 将排序后的results数组作为参数,显示所有学生的信息。
}
// 将arr2数组中的数据复制到arr1指向的数组中,实现数组的拷贝操作。
// 注意,arr1是指向指针的指针,通过使用双重解引用来访问和修改指向的数组。
void copy_array(student_score** arr1, student_score* arr2)
{
int length = ArrayLength(student_score, stu_score_records);
for (int i = 0; i < length; i++)
{
// 由于arr1是指向指针的指针,所以在对其进行操作时需要使用间接运算符*进行解引用操作,以获取到指向的真正的指针,然后再通过该指针访问对应的数组元素。
(*arr1)[i].is_valid = arr2[i].is_valid;
(*arr1)[i].score_record_id = arr2[i].score_record_id;
(*arr1)[i].student_record_id = arr2[i].student_record_id;
}
}
void swap_student(student_score* array, int index1, int index2)
// 参数student_score* array的作用是传递一个指向student_score类型的数组的指针。
// 通过使用这个指针,函数可以访问和修改传递进来的数组。在函数内部,可以使用array[index]的方式来访问数组中的特定元素,其中index是数组的索引。
// 通过传递数组的指针作为参数,可以避免在函数内部进行数组的拷贝,从而提高了程序的效率。同时,也可以在函数内部修改数组的内容,并将修改后的结果反映到函数外部。
{
student_score temp;
temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
void exit_system()
{
exit_flag = -1;
return;
}
// 辅助函数 ******************************************
char* get_sex(short sex)
{
return sex == 0 ? "m" : "f";
}
int convert_sex(char* sex)
{
return sex == 'm' ? 0 : 1;
}
学生成绩管理系统程序
于 2023-06-27 09:54:34 首次发布