学生成绩管理系统程序

文章展示了如何使用C语言编程实现一个学生信息管理系统,包括添加、显示、删除、查找和修改学生信息,以及学生成绩排序等功能。系统利用结构体存储学生和成绩数据,使用函数指针实现菜单驱动的交互界面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述

#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;
}
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值