• 学生管理系统


    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


    前言

    本程序使用纯C制作一个学籍管理系统。利用单链表实现学生管理系统,具体功能包括录入学生信息、打印学生信息、统计学生人数、查找学生信息、修改学生信息、删除学生信息、按成绩排序
    同时将学生信息保存至文件中,当再次启动程序时,自动读取学生数据。


    0. 准备

    0-0 头文件

    创建StudentManager.h ,加入以下代码

    // 标准输入输出
    #include 
    // _getch:不需要回车,直接获取输入的字符,需要包含conio.h头文件#include 
    // 动态申请内存
    #include 
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    0-1 封装学生和结点数据

    定义学生结构体,用于保存学生的学号、姓名、成绩信息,并使用typedef给 struct _Student 类型起别名为Student ,方便使用。

    typedef struct _Student
    {
    	int stuNum; //学号char name[20];//姓名int score; //成绩
    }Student;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    定义结点结构体,用于保存链表中的结点数据,结点需要保存学生信息及下一个结点的地址,并使用
    typedef给 struct _Node 类型起别名为Node ,方便使用。

    typedef struct _Node
    {
    	Student stu; //学生
    	struct _Node* next; //指向下一个结点的指针
    }Node;
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    0-2 创建头结点

    创建StudentManager.c ,加入main函数,并创建链表的头结点,定义head头指针指向头结点

    //导入头文件
    #include "StudentManager.h"
    int main() {
    	//创建头结点
    	Node* head = malloc(sizeof(Node)); 
    	head->next = NULL;
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    0-3 系统功能提示

    定义welcome函数,用于提示用户系统功能

    void welcome() {
    	printf("*********************************\n"); 
    			printf("*\t学生成绩管理系统\t*\n");  
    			printf("*\t请选择功能列表\t\t*\n"); 
    			printf("*\t1.录入学生信息\t\t*\n");
    			printf("*\t2.打印学生信息\t\t*\n");
    			printf("*\t3.统计学生人数\t\t*\n"); 
    			printf("*\t4.查找学生信息\t\t*\n"); 
    			printf("*\t5.修改学生信息\t\t*\n");
    			printf("*\t6.删除学生信息\t\t*\n");
    			printf("*\t7.按成绩排序\t\t*\n"); 
    			printf("*\t8.退出系统\t\t*\n");
    	printf("*********************************\n");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在头文件中声明函数,并在main函数中调用,后面定义的其他函数,也应该先在头文件中声明,再调 用:
    StudentManager.h

    //欢迎信息
    void welcome();
    
    
    • 1
    • 2
    • 3

    main函数

    //创建头结点
    Node* head = malloc(sizeof(Node)); head->next = NULL;
    
    welcome();
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    0-4 根据用户输入选择功能

    通过_getch() 函数获取用户输入的单个字符,此函数不需要回车,并通过switch进行判断

    welcome();
    char c = _getch(); switch (c)
    {
    	case '1'://录入学生信息
    	break; 
    	case '2'://打印学生信息
    	break;
    	case '3'://统计学生人数
    	break; 
    	case '4'://查找学生信息
    	break; 
    	case '5'://修改学生信息
    	break;
    	case '6'://删除学生信息
    	break; 
    	case '7'://按成绩排序
    	break; 
    	case '8'://退出系统
    	break;
    	default:
    	break;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    1. 录入学生信息

    定义inputStudent 函数,实现新增学生信息的功能,在main函数中调用。

    void inputStudent(Node* head) {
    	//定义指针指向头结点,用于遍历链表Node* move = head;
    	while (move->next != NULL) { 
    		move = move->next;
    	}
    	//创建结点
    	Node* fresh = malloc(sizeof(Node)); 
    	fresh->next = NULL;
    	//输入用户信息
    	printf("请输入学生的学号、姓名、成绩: ");
    	scanf("%d%s%d", &fresh->stu.stuNum, fresh->stu.name, &fresh->stu.score);
    	//将新创建的结点,添加到链表的尾部move->next = fresh;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在main函数中调用

    ...
    	case '1': //录入学生信息
    	inputStudent(head); break;
    ...
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1-0 实现循环录入

    添加循环,将welcome 函数及switch判断都加入到循环体,保持程序一直运行,实现循环录入学生信息功能

    int main() {
    		//创建头结点
    		Node* head = malloc(sizeof(Node));
    		head->next = NULL;
    		while (1) {
    		welcome();
    		/*
    		等待从键盘接收一个字符, 输入字符后,回车才能录入,注意:回车符号会被存储至缓存区,下次
    		循环导致获取到回车
    		//char c = getchar();
    		//getchar(); 吸收回车
    		getch:不需要回车,直接获取输入的字符,需要包含conio.h头文件,2022之前的版本需要使用
    		_getch()
    		*/
    		char c = _getch();
    		switch (c) {
    			case '1': //录入学生信息
    			inputStudent(head);
    			break;
    			case '2': //打印学生信息
    			break;
    			case '3': //统计学生人数
    			break;
    			case '4': //查找学生信息
    			break;
    			case '5': //修改学生信息
    			break;
    			case '6': //删除学生信息
    			break;
    			case '7': //按成绩排序
    			break;
    			case '8': //退出系统
    			break;
    			default:
    			break;
    		}
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    注意,如果使用的是 getchar 函数或 scanf 函数,会存在缓冲区的问题,每次输入数据后,回车都会被
    保存到缓冲区,导致下次出现问题,需要再使用一次getchar吸收回车。
    _getch 函数不需要回车就可以直接读取到数据,不存在此问题。

    1-1 程序暂停和清空控制台

    每次录入学生信息后,进入到下一次循环,会重新打印欢迎信息,可以先使程序暂停,等待用户下一步指示

    system("pause");//按下任意键后,会继续执行程序
    
    • 1

    当用户按下任意键后,可以先清空控制台,防止重复出现欢迎信息

    system("cls");
    
    • 1

    两者合用,加入到 inputStudent 函数中

    void inputStudent(Node* head) {
    	//定义指针指向头结点,用于遍历链表
    	Node* move = head;
    	...
    	...
    	system("pause");
    	system("cls");
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2. 打印学生信息

    定义 printStudent 函数,实现打印所有学生信息的功能

    void printStudent(Node* head) {
    	Node* move = head->next;
    	while (move != NULL) {
    	printf("学号:%d 姓名:%s 成绩:%d\n",move->stu.stuNum,move->stu.name,move-
    	>stu.score);
    	move = move->next;
    	}
    	system("pause");
    	system("cls");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在main函数中调用

    ...
    	case '2': //打印学生信息
    	printStudent(head);
    	break;
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3. 统计学生人数

    定义 countStudent 函数,统计学生总人数

    void countStudent(Node* head) {
    	int count = 0;
    	Node* move = head->next;
    	while (move != NULL) {
    	count++;
    	move = move->next;
    	}
    	printf("学生总人数为:%d\n",count);
    	system("pause");
    	//清屏
    	system("cls");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在main函数中调用

    	case '3': //统计学生人数
    	countStudent(head);
    	break;
    
    • 1
    • 2
    • 3

    4. 查找学生信息

    定义 findStudent 函数,用于根据学号查找学生信息

    void findStudent(Node* head) {
    	int stuNum;
    	printf("请输入要查找的学生的学号: ");
    	scanf("%d", &stuNum);
    	Node* move = head->next;
    	while (move != NULL) {
    		if (move->stu.stuNum = stuNum) {
    		printf("学号:%d 姓名:%s 成绩:%d\n", move->stu.stuNum, move->stu.name,move->stu.score);
    		system("pause");
    		system("cls");
    		return;
    		}
    		move = move->next;
    	}
    	printf("未查找到学生信息\n");
    	system("pause");
    	system("cls");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在main函数中调用

    case '4': //查找学生信息
    	findStudent(head);
    
    • 1
    • 2

    4-0. 学生信息持久化

    定义 saveStudent 函数,将链表数据保存至文件中

    void saveStudent(Node* head) {
    	//打开文件
    	FILE* file = fopen("./stu.info", "w");
    	if (file == NULL) {
    	printf("打开文件失败\n");
    	return;
    	}
    	Node* move = head->next;
    	while (move != NULL) {
    		//将结构体写入文件
    		if (fwrite(&move->stu, sizeof(Student), 1, file) != 1) {
    			printf("保存%s出现错误\n", move->stu.name);
    		}
    		move = move->next;
    	}
    	//关闭文件
    	fclose(file);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在 inputStudent 函数中调用 saveStudent ,实现信息的保存

    void inputStudent(Node* head) {
    	//定义指针指向头结点,用于遍历链表
    	Node* move = head;
    	...
    	//将学生信息保存至文件
    	saveStudent(head);
    	system("pause");
    	system("cls");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    定义 loadStudent 函数实现学生信息的读取

    void loadStudent(Node* head) {
    	//打开文件
    	FILE* file = fopen("./stu.info", "r");
    	if (!file) {
    	printf("未找到学生文件,跳过读取\n");
    	return;
    	}
    	//创建一个结点
    	Node* fresh = malloc(sizeof(Node));
    	fresh->next = NULL;
    	Node* move = head;
    	while (fread(&fresh->stu, sizeof(Student), 1, file) == 1) {
    	move->next = fresh;
    	move = fresh;
    	fresh = malloc(sizeof(Node));
    	fresh->next = NULL;
    	}
    	free(fresh); //最后多定义一个fresh,要将它释放掉
    	//关闭文件
    	fclose(file);
    	printf("读取成功\n");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在main函数中调用 loadStudent ,每次程序启动时,先读取之前存储的学生信息

    int main() {
    	//创建头结点
    	Node* head = malloc(sizeof(Node));
    	head->next = NULL;
    	//读取学生信息
    	loadStudent(head);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5. 修改学生信息

    定义 modifyStudent 函数,用于根据学生学号修改学生信息

    void modifyStudent(Node* head) {
    	printf("请输入需要修改的学生学号 ");
    	int stuNum = 0;
    	scanf("%d", &stuNum);
    	Node* move = head;
    	while (move != NULL) {
    	if (move->stu.stuNum == stuNum) {
    	printf("请输入学生姓名,成绩\n");
    	scanf("%s%d",move->stu.name,&move->stu.score);
    	printf("修改学生信息成功\n");
    	//不再循环
    	break;
    	}
    	move = move->next;
    	}
    	//如果循环完毕,也没找到学生
    	if (move == NULL) {
    	printf("未找到学生信息\n");
    	}
    	//同步到文件
    	saveStudent(head);
    	system("pause");
    	system("cls");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在main函数中调用

    case '5': //修改学生信息
    	modifyStudent(head);
    	break;
    
    • 1
    • 2
    • 3

    6. 删除学生信息

    定义 deleteStudent 函数,用于根据学号删除学生

    void deleteStudent(Node* head) {
    	printf("请输入要删除的学生学号 ");
    	int stuNum = 0;
    	scanf("%d", &stuNum);
    	Node* move = head;
    	while (move->next != NULL) {
    	if (stuNum == move->next->stu.stuNum) {
    	Node* temp = move->next;
    	move->next = move->next->next; //删除结点只需要一句
    	free(temp); //最后记得将删除的动态空间释放掉
    	temp = NULL; //释放后随即指向NULL
    	//同步到文件
    	saveStudent(head);
    	printf("删除学生成功\n");
    	break;
    	}
    	move = move->next;
    	}
    	if (move->next == NULL) {
    	printf("未找到学生信息\n");
    	}
    	system("pause");
    	system("cls");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    7. 按成绩排序

    定义 sortStudent 函数,使用冒泡排序,按成绩从小到大进行排序

    void sortStudent(Node* head) {
    	Node* save = NULL;
    	Node* move = NULL;
    	for (Node* turn = head->next; turn->next != NULL; turn = turn->next) {
    		for (move = head->next; move->next != save; move = move->next) {
    			if (move->stu.score > move->next->stu.score) {
    			Student temp = move->stu;
    			move->stu = move->next->stu;
    			move->next->stu = temp;
    			}
    		}
    		save = move;
    	}
    	printStudent(head);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在main函数中调用

    case '7': //按成绩排序
    	sortStudent(head);
    
    • 1
    • 2

    8. 退出系统

    	case '8': //退出系统
    	system("cls");
    	printf("Bye Bye!\n");
    	exit(0);
    
    • 1
    • 2
    • 3
    • 4

    总结

    学籍管理系统是一种基于单链表的学生管理系统,通过使用纯C语言实现。该系统具有多项功能,包括录入学生信息、打印学生信息、统计学生人数、查找学生信息、修改学生信息、删除学生信息以及按成绩排序。此外,该系统还具备学生信息持久化的功能,能够将学生数据保存至文件中,以便下次启动程序时自动读取。在录入学生信息功能中,用户可以逐个输入学生的学号、姓名和成绩。打印学生信息功能可以将系统中存储的所有学生信息依次输出。统计学生人数功能可以统计出当前系统中的学生总人数。查找学生信息功能可以根据学号查找学生的详细信息。修改学生信息功能可以根据学号修改学生的姓名和成绩。删除学生信息功能可以根据学号删除学生的信息。按成绩排序功能可以将学生信息按照成绩从小到大进行排序。最后,退出系统功能可以结束程序的运行。通过以上功能,学籍系统可以方便地管理学生的信息,并能够保证数据的持久化安全性。

    可执行的代码和pdf文档大家根据下面链接进行下载
    https://gitee.com/shiguangliushui/student-management-system.git

  • 相关阅读:
    动态代理与静态代理
    好物周刊#11:远程桌面软件
    P2181 对角线
    如何在 Blender 中更快地渲染?
    YARN 应用提交过程
    链表合并 分数 25
    中项系统集成项目管理2023上半年真题及解析
    CSS清除浮动的五种方法(超详细)
    mysql 多表查询,多次使用inner join和left join混合查询时
    PMP(Project Management Professional)证在哪个行业比较有用?
  • 原文地址:https://blog.csdn.net/qq_65101190/article/details/133661453