zl程序教程

您现在的位置是:首页 >  其他

当前栏目

赶紧进来看看--用C语言实现学生信息管理系统(1.0静态版)

2023-04-18 16:10:26 时间

本文介绍了用C语言实现学生信息管理系统设计,主要包括对学生信息增删查改.分类统计.排序等功能,文章最后有全部源码展示…

一.学生信息管理系统介绍

学生信息管理系统是针对学校学生处的大量工作处理工作而开发的 管理软件 ,主要用于学校学生信息管理,总体任务是实现学生信息关系的系统化、科学化、规范化和自动化,其主要任务是用手机和计算机对学生各种信息进行日常管理,如查询、修改、增加、删除等,另外还考虑到学生选课,针对这些要求设计了学生信息管理系统。 推行学校信息管理系统的应用是进一步推进学生学籍管理规范化、电子化、控制辍学和提高义务教育水平的重要举措。

学生信息管理系统也是很多大学的编程语言课程设计…

本篇博客实现的学生信息管理系统静态版 是纯C语言实现,实现对学生信息进行存储管理,增删查改,分类统计.排序 等功能.现包含了对学生以下信息:学号.姓名.性别.年龄.寝室号.电话号码.家庭地址

二.实现学生信息管理系统所需知识点

1.对顺序.分支.循环三大结构使用熟悉->顺序.分支.循环.三大结构
2.需要熟悉编写自定义函数和使用某些库函数->自定义函数和库函数
3.熟悉对指针的操作->C语言指针
4.熟悉使用结构体类型->自定义类型:结构体

5.熟悉使用多文件分文件编写程序->多文件

三.设计学生信息管理系统

综合所学知识,下面将实现的学生信息管理系统分函数模块进行介绍…

1.开头:设计多文件编写程序

在这里插入图片描述

学生信息管理系统需要用到的函数较多,为了便于维护管理,采取多文件的方法,创建的stu.h 为头文件,用于放结构体的定义.函数的声明
创建的stu.c源文件用来存放实现功能的各个函数.test.c是主main函数所在文件用来测试运行整个程序

因为存在多个文件 stu.c和test.c都需要包含一下stu.h头文件才能使用头文件里的函数声明结构体定义 及其库函数头文件的包含
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这样只需要头文件stu.h包含需要用到的头文件,其他文件包含stu.h即可使用,节省了多次包含重复文件的代码量

2.确定每个学生信息和存储信息方式

①.设计描述学生信息结构体和管理学生信息结构体

在这里插入图片描述

采用结构体类型,将描述学生的每个信息作为结构体成员变量存放
有7个成员变量分布表示学生的学号.名字.性别.年龄.寝室号.电话号码.家庭住址最后通过typedef将学生信息结构体类型重命名为studata(使类型名更具有标识性更简短.)

学生信息类型已确定,而需要描述多个学生,需要用这个类型创建多个学生变量,此时用到数组,创建studata类型数组,数组元素即表示学生的个数,而创建存放学生信息的数组后还需要有一个变量来记录当前数组存放的有效学生信息个数(因为学生记录是要一个个存进去,一开始不是整个数组元素都是有效的学生信息)

为了便于管理:将存放学生信息的数组studata stu[100]和记录当前有效学生信息个数int sz 放在一起作为一个新的结构体类型struct studentmanagement 成员变量 最后typedef将类型名重定义为stumgt 此时这个stumgt就是整个学生信息管理系统了…

②.对管理学生信息结构体初始化

当创建了管理学生信息结构体后.用结构体类型创建的变量.每个成员变量都是随机值,此时应对其进行初始化使里面都为0即空值

在这里插入图片描述

void initstus(stumgt* pstus)//初始化学生管理系统这个结构体变量
{
	assert(pstus != NULL); // 断言避免接受空指针
	memset(pstus, 0, sizeof(stumgt));
}

此处涉及结构体传参,需要传结构体类型指针变量,只有通过指针才能解引用访问修改结构体变量,再通过memset库函数设置这个结构体类型里成员变量每个内存单元都设置为0(memset内存设置库函数)

3.分模块设计学生信息管理系统功能

①.添加新的学生信息

刚创建的存放学生信息数组,有效学生信息是0个,此时需要封装一个函数对学生信息进行添加.

void addstu(stumgt* pstus)
{
	assert(pstus != NULL);
	if (pstus->sz == 100)
	{
		printf("学生信息已满,无法新增学生信息
");
		return;
	}
	else
	{
		system("cls"); //输入学生信息前清屏一次
		printf("请输入学生学号:");
		char tmp[20] = { 0 };
		scanf("%s", tmp);
		if (is_repeat(pstus, tmp))   //学生学号为主要属性  应是唯一的且不能为空
		{
			printf("输入失败!!!已存在学号信息为%s的学生,不同学生信息不允许设置相同学号
", tmp);
			return;
		}

		strcpy(pstus->stu[pstus->sz].sno, tmp);  //不存在重复时将当前信息拷贝作为学生学号信息
		printf("请输入学生名字:");
		scanf("%s", pstus->stu[pstus->sz].name);
		printf("请输入学生性别:");
		scanf("%s", pstus->stu[pstus->sz].sex);
		printf("请输入学生年龄:");
		scanf("%d", &pstus->stu[pstus->sz].age); //注意年龄这里要&其他的都是地址
		printf("请输入学生寝室号:");
		scanf("%s", pstus->stu[pstus->sz].roomnum);
		printf("请输入学生电话号码:");
		scanf("%s", pstus->stu[pstus->sz].number);
		printf("请输入学生家庭住址:");
		scanf("%s", pstus->stu[pstus->sz].add);
		pstus->sz++;
		system("cls");
		printf("添加成功
");
	}
}

封装addstu 增加学生信息的函数,参数为结构体类型指针
添加前先判断一个该指针指向的结构体变量里的sz即有效成员个数是否为100,如果是100则表示成员信息已满…
如果没满100,则进行添加成员信息.

而由于学生信息管理系统,学号应该是唯一的,避免当输入已经有系统里已经有的学号时出现重复,先输入学号,然后封装一个addstu里使用的函数 is_repeat 用来判断是否重复 ,因为这个函数是为了实现某个功能而封装的,只能在指定函数内使用 此时用static修饰 表示这个函数在外部文件里不能被声明调用.

static int is_repeat(stumgt* pstus, char tmp[]) //判断学号信息是否重复
{
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(tmp, pstus->stu[i].sno) == 0)
		{
			return 1;
		}
	}
	return 0;
}

在添加学生信息前,先用tmp存放学生学号,传给is_repeat函数通过循环遍历查找当前有效学生信息里是否存在学号相同的,如果存在返回1,最后不存在返回0
最后如果存在相同的则提示添加失败然后返回,
不存在相同学号则可以进行下面的添加操作

因为上面tmp存放的是输入的学号,先使用strcpy字符串拷贝函数将tmp里的学号拷贝到学生信息系统里,再一一通过scanf函数输入对应的学生信息给第一个元素,实现了添加学生信息的操作

②.删除指定学生信息

封装一个dropstu实现删除指定的学生信息,指定信息设置为了学号(因为学号是唯一标识,可以精确删除某个学生)

void dropstu(stumgt* pstus)  //删除学生信息
{
	assert(pstus != NULL);
	if (pstus->sz == 0)   //判断学生记录是否为空
	{
		printf("当前没有学生信息,无法删除
");
		return;
	}
	char tmp[20] = { 0 };
	printf("输入要删除的学生的学号信息:");
	scanf("%s", tmp);
	int num = findstu(pstus,tmp);  //使用内部封装的查找函数
	if ( num== -1)
	{
		printf("没有找到要删除的学生信息
");
		return;
	}
	else
	{
		int i = 0;
		for (i = num + 1; i < pstus->sz; i++)
		{
			pstus->stu[i - 1] = pstus->stu[i];
		}
		pstus->sz--;
		printf("已删除学号为%s的学生成员
",tmp);
	}
}

首先先判断sz是否为0即有效学生个数是否为空,为空则无法删除,不为空则先输入要删除的学号信息,然后封装一个查找学生信息的函数findstu

static int findstu(stumgt* pstus,char tmp[])  //封装的内部 查找学生学号信息的函数 找到返回对应的数组元素下标 没找到返回-1
{
	assert(pstus != NULL);
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(tmp, pstus->stu[i].sno) == 0)
			return i;
	}
	return -1;
}

通过遍历整个学生系统寻找是否有要删除的学生的学号信息,如果有则返回这个学号相同的学生的下标,如果没有则返回-1

通过接受返回值判断,如果是-1则显示没有要删除的成员,结束函数,如果不为-1则要删除这个下标上的学生信息,此时这个系统是数组结构,采用循环实现从后面的空间一个个往前面赋值的方法,将后面有效的学生信息将这个学生信息被覆盖,最后再sz–表示有效学生信息减-1实现了删除学生信息的操作…

③.查找指定学生信息

void search(stumgt* pstus)  //查找学生信息的函数  以名字作为查找标准
{
	assert(pstus != NULL);
	char tmp[20] = { 0 };
	printf("请输入要查找的学生姓名:");
	scanf("%s", tmp);
	printf("已查询到以下姓名为%s的学生信息↓↓↓
",tmp);  //找到后按设置的对齐格式输出查找的信息
	printf("%-10s	%-10s	%-5s	%-10s	%-10s	%-12s	%-20s	
", "学号", "姓名", "性别", "年龄", "寝室号", "电话号码", "家庭住址");
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(tmp, pstus->stu[i].name) == 0)
		{
			printf("%-10s	%-10s	%-5s	%-10d	%-10s	%-12s	%-20s	
",
				pstus->stu[i].sno,
				pstus->stu[i].name,
				pstus->stu[i].sex,
				pstus->stu[i].age,
				pstus->stu[i].roomnum,
				pstus->stu[i].number,
				pstus->stu[i].add);
		}
	}
}

封装一个serch函数实现查找指定学生信息功能, 而指定查找学生信息标识为学生姓名.
而显示学生信息的格式设置为先第一行显示学生每个信息的字段,然后下面每一行输出学生信息.
采用特定的输出对齐格式,使得界面更美观
在这里插入图片描述

④.修改指定学生信息

修改学生信息可以实现修改一个学生所有信息和一个学生的某单个信息
通过封装modifystu函数选择修改学生信息的选项.选择修改所有还是单个信息

void modifystu(stumgt * pstus)  //修改学生信息的函数
{
	
	
	int input = 0;
	do
	{
		modifymenu1();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)//选择修改整条学生信息还是修改一条里某一项的学生信息
		{
		case 1:
			modifyall(pstus);  
			break;
		case 2:
			modifyone(pstus);
			break;
		case 0:
			printf("已结束修改操作
");
			break;
		default:
			printf("非法输入,请重新输入
");
		}
		
	} while (input);
	
}

在这里插入图片描述

用户可以根据显示的菜单选择修改信息
选择的是1则是modifyall函数实现修改所有学生信息

static void modifyall(stumgt* pstus)  //内部封装的修改整条学生信息的函数
{
	char tmp[20] = { 0 };
	printf("请输入要修改的学生学号信息:");  
	scanf("%s", tmp);

	int num = findstu(pstus, tmp);  //先判断是否存在要修改的学生信息
	if (num == -1)
	{
		printf("未找到要修改的学生信息
");
		return;
	}
	else
	{
		system("cls"); //输入学生信息前清屏一次
		printf("请输入学生学号:");
		char tmp[20] = { 0 };
		scanf("%s", tmp);
		if (is_repeat(pstus, tmp))   //学生学号为主要属性  应是唯一的且不能为空
		{
			printf("输入失败!!!已存在学号信息为%s的学生,不同学生信息不允许设置相同学号
", tmp);
			return;
		}

		strcpy(pstus->stu[num].sno, tmp);  //修改后的学号在之前学生信息里没有重复的则将tmp的拷贝修改当前学生信息学号
		printf("请输入学生名字:");
		scanf("%s", pstus->stu[num].name);
		printf("请输入学生性别:");
		scanf("%s", pstus->stu[num].sex);
		printf("请输入学生年龄:");
		scanf("%d", &pstus->stu[num].age);
		printf("请输入学生寝室号:");
		scanf("%s", pstus->stu[num].roomnum);
		printf("请输入学生电话号码:");
		scanf("%s", pstus->stu[num].number);
		printf("请输入学生家庭住址:");
		scanf("%s", pstus->stu[num].add);
	}
}

通过学号信息进行查找是否存在这个学生,仍然使用封装的 内部findstu函数,找到则返回对应下标,找不到返回-1, 当找到之后,用tmp接受要修改的学号,
然后在使用封装的内部函数is_repeat进行查找当前学生信息是否有你要修改的学号,如果有,则显示修改失败,不能出现同名学号,不存在同学号 则可以进行下面修改操作…

如果用户选择的是2则运行modifyone函数修改指定学生的某个单独信息

static void modifyone(stumgt* pstus)  //内部封装修改整条学生信息里的某项信息函数
{
	char tmp[20] = { 0 };
	printf("请输入要修改的学生学号信息:");
	scanf("%s", tmp);
	int num = findstu(pstus, tmp);  //先判断是否存在该学生信息
	if (num == -1)
	{
		printf("未找到要修改的学生信息
");
		return;
	}
	else
	{
		int input = 0;
		modifymenu2();  //下面为函数指针数组将一个0和上面7个封装好的修改对应学生信息的函数指针作为数组初始化信息(0是为了方便下标对其选项)
		void(*mod[8])(stumgt*, int) = { 0,modifysno,modifyname,modifysex,modifyage,modifyroomnum,modifynumber,modifyadd };
		printf("请选择修改的内容:");
		do
		{
			scanf("%d", &input);
			if (input >= 8 || input < 0)
			{
				printf("非法输入,请重新选择
");
				
			}
			else if (input == 0)
			{
				printf("退回上一层修改菜单
");
			}
			else
			mod[input](pstus, num); //根据菜单对应input输入的值调用 数组里相对应的函数指针
			
		} while (input >= 8 || input <0); //超出重新输入
		
	}
}

先输入要修改的学生学号运行findstu函数查找是否存在该学生,
没找到则结束该函数,找到后根据菜单选择要修改的信息
在这里插入图片描述

static void modifysno(stumgt* pstus,int num) //内部封装的单独修改学号的函数
{
	printf("你要将学号修改为:");
	char tmp[20] = { 0 };
	scanf("%s", tmp);
	if (is_repeat(pstus, tmp))
	{
		printf("修改失败,不能输入已有的学号
");
		return;
	}
	else
	{
		strcpy(pstus->stu[num].sno, tmp);
		printf("修改成功
");
	}
	
}
static void modifyname(stumgt* pstus, int num)//内部封装的单独修改名字的函数
{
	printf("你要将名字修改为:");
	scanf("%s", pstus->stu[num].name);
	printf("修改成功
");
}
static void modifysex(stumgt* pstus, int num)//内部封装的单独修改性别的函数
{
	printf("你要将性别修改为:");
	scanf("%s", pstus->stu[num].sex);
	printf("修改成功
");
}
static void modifyage(stumgt* pstus, int num)//内部封装的单独修改年龄的函数
{
	printf("你要将年龄修改为:");
	scanf("%d", &pstus->stu[num].age);
	printf("修改成功
");
}
static void modifyroomnum(stumgt* pstus, int num)//内部封装的单独修改寝室号的函数
{
	printf("你要将寝室号修改为:");
	scanf("%s", pstus->stu[num].roomnum);
	printf("修改成功
");
}
static void modifynumber(stumgt* pstus, int num)//内部封装的单独修改电话号码的函数
{
	printf("你要将电话号码修改为:");
	scanf("%s", pstus->stu[num].number);
	printf("修改成功
");
}
static void modifyadd(stumgt* pstus, int num)//内部封装的单独修改地址的函数
{
	printf("你要将地址修改为:");
	scanf("%s", pstus->stu[num].add);
	printf("修改成功
");
}

对应菜单函数封装各个实现对应修改功能的函数
然后在modifyone函数中选择调用指定的函数,因为函数过多,
这里没有使用switch case结构 而使用了if else 通过函数指针的用法使用函数指针数组,将每个修改学生信息函数作为参数,然后对应输入的数字选项传参调用指定的修改学生信息的函数…

⑤.分类统计学生个数

统计学生个数可以统计所有学生,也可以按学生信息进行统计
通过封装countstu函数进行选择统计的方式

void countstu(stumgt* pstus)  //统计学生信息的函数
{
	assert(pstus != NULL);
	system("cls");
	
	int input = 0;
	do
	{
		countmenu();
		printf("请选择统计方式:");
		scanf("%d", &input);  
		switch (input)  //对应菜单输入input选择 跳转到上面封装的统计函数
		{
		case 1:
			countall(pstus);
			break;
		case 2:
			countage(pstus);
			break;
		case 3:
			countroom(pstus);
			break;
		case 4:
			countsex(pstus);
			break;
		case 0:
			printf("已结束统计
");
			break;
		default:
			printf("非法输入,请重新选择
");
		}
			
	} while (input);
}

在这里插入图片描述

选择1则运行countall统计所有学生个数

static void countall(stumgt* pstus)  //内部封装的统计当前所有学生信息记录函数
{
	printf("已统计当前系统中有%d个学生
", pstus->sz);
	return;
}

直接输出sz即有效元素个数即表示当前所有学生信息

选择2则运行countage 按年龄统计学生个数

static void countage(stumgt* pstus)  //统计年龄范围内学生记录的个数
{
	int age1 = 0;
	int age2 = 0;
	int age = 0;
	printf("请输入两个数字将统计其范围内的年龄个数(如果两个数字相同则统计这个数字年龄的学生个数)");
	scanf("%d%d", &age1, &age2);
	int count = 0;
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		 age = pstus->stu[i].age;
		if (age >= age1 && age <= age2)
		{
			count++;
		}
	}
	printf("在%d岁和%d岁之间的学生个数为%d
", age1, age2, count);
	return;
}

这里通过年龄范围来统计,设计两个变量age1和age2表示范围
age接受遍历学生信息的年龄信息
count记录学生个数
通过比较age是否在age1和age2里,如果在count++
这样设计使得范围更广可以查找多范围也可以单范围查找

选择3则运行countroom按寝室号统计学生个数

static void countroom(stumgt* pstus) //统计 寝室号的个数
{
	char room[20] = { 0 };
	printf("请输入寝室号:");
	scanf("%s", room);
	int i = 0;
	int count = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(room, pstus->stu[i].roomnum) == 0)
		{
			count++;
		}
	}
	printf("寝室号为%s的寝室个数为%d个
", room, count);
	return;
}

room接受要查找的寝室号,count记录个数
通过遍历学生信息管理系统 与查找的寝室号相同count++
最后输出count里的个数

选择4则运行countsex按性别统计学生个数

static countsex(stumgt* pstus)   //统计相同性别的学生个数
{
	char sex[5] = { 0 };
	printf("请输入要统计的性别:");
	scanf("%s", sex);
	int i = 0;
	int count = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(sex, pstus->stu[i].sex) == 0)
		{
			count++;
		}
	}
	printf("性别为%s的学生个数为:%d
", sex, count);
}

sex接受要统计的性别信息,
count记录个数
遍历数组查找性别相同则count++
最后输出count的信息

选择0最后退出分类统计功能

⑥.显示所有学生信息

通过封装pritstus函数实现显示所有有效学生信息

void pritstus(stumgt* pstus)   //打印所有信息
{
	assert(pstus != NULL);
	system("cls");   //输出所有信息前先清屏一次
	printf("%-10s	%-10s	%-5s	%-10s	%-10s	%-12s	%-20s	
", "学号", "姓名", "性别", "年龄", "寝室号", "电话号码", "家庭住址");//先设置好对应字段格式
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		printf("%-10s	%-10s	%-5s	%-10d	%-10s	%-12s	%-20s	
",  //按设置好的格式对其打印数据
			pstus->stu[i].sno,
			pstus->stu[i].name,
			pstus->stu[i].sex,
			pstus->stu[i].age,
			pstus->stu[i].roomnum,
			pstus->stu[i].number,
			pstus->stu[i].add);
	}
}

通过设计对应的对齐格式,使得更整齐的显示学生信息系统里的学生信息,第一行先打印每个学生信息对应的字段,后面每一行显示一个学生信息,通过循环遍历打印所有有限学生信息

⑦.排序所有学生信息

当我们输入的学生信息无序杂乱时,可以使用sortstu函数进行将学生信息进行排序

 int cmp_sno(const studata stu1, const studata stu2) // 为qsort 函数设置的函数指针 用于比较两个元素的大小传给qsort
{
	return strcmp(stu1.sno, stu2.sno);    //比较两个学生里的学号大小 进行排序 这两个学生元素
}
void sortstu(stumgt* pstus) //  升序排序所有学生记录的函数
{
	if (pstus->sz == 0)   //判断排序时是否为空
	{
		printf("当前学生记录为空,无法排序
");
		return;
	}
	qsort(pstus, pstus->sz, sizeof(studata), cmp_sno);
	printf("已按学号完成升序排序
");
}

如果sz为0则没有学生信息显示无法排序,当有学生信息时,通过使用之前学习到的qsort排序库函数->qsort介绍,第一个参数为排序的空间,第二个为要排序的元素个数,第三个参数为要排序的每个元素的大小,第四个为自定义的函数指针

封装的函数指针内容为对应的学生学号进行比较(因为学号是唯一标识不会重复),通过strcmp比较每个学生大小返回给qsort函数实现升序排序…

4.串联所有管理学生信息系统功能

将所有实现管理学生信息的函数封装后,为了方便调用每一个函数,
使用switch case 结构通过菜单选择对应操作的功能

int main()
{
	stumgt stus;  // 管理学生信息结构体 创建的变量stus 
	int i = 0;
	initstus(&stus);
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &i);
		switch (i)
		{
		case 1:
			 addstu(&stus);
			break;
		case 2:
			dropstu(&stus);
			break;
		case 3:
			search(&stus);
			break;
		case 4:
			modifystu(&stus);
			break;
		case 5:
			countstu(&stus);
			break;
		case 6:
			pritstus(&stus);
			break;
		case 7:
			sortstu(&stus);
			break;
		case 0:
			printf("已退出学生信息管理系统
");
			break;
		default :
			printf("选择错误,请重新输入
");
			break;
		}
	} while (i);
	return 0;
}

在这里插入图片描述

串联起来以后,用户可以根据菜单选择任意功能进行操作学生信息管理系统…

四.学生信息管理系统源代码展示↓↓↓

1. main函数所在的text.c源文件

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable : 6031)
#include"stu.h"
int main()
{
	stumgt stus;  // 管理学生信息结构体 创建的变量stus 
	int i = 0;
	initstus(&stus);
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &i);
		switch (i)
		{
		case 1:
			 addstu(&stus);
			break;
		case 2:
			dropstu(&stus);
			break;
		case 3:
			search(&stus);
			break;
		case 4:
			modifystu(&stus);
			break;
		case 5:
			countstu(&stus);
			break;
		case 6:
			pritstus(&stus);
			break;
		case 7:
			sortstu(&stus);
			break;
		case 0:
			printf("已退出学生信息管理系统
");
			break;
		default :
			printf("选择错误,请重新输入
");
			break;
		}
	} while (i);
	return 0;
}

2. 实现函数声明结构体定义所在的stu.h头文件


#pragma once   //防止头文件被重复包含
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
typedef struct studentdata
{
	char sno[20];  //学号
	char name[20]; //名字
	char sex[5]; //性别
	int age;  //年龄
	char roomnum[20];// 寝室号
	char number[12];// 电话号码
	char add[20];  //地址
}studata;

typedef struct studentmanagement
{
	studata stu[100];
	int sz;
}stumgt;

void menu();
void initstus(stumgt* pstus);
void addstu(stumgt* pstus);
void pritstus(stumgt* pstus);
void dropstu(stumgt* pstus);
void search(stumgt* pstus);
void modifystu(stumgt* pstus);
void countstu(stumgt* pstus);
void sortstu(stumgt* pstus);

3. 实现具体功能的函数所在stu.c源文件

#define _CRT_SECURE_NO_WARNINGS  
#pragma warning(disable : 6031) //忽略返回值
#include"stu.h"
void menu()
{
	printf("           欢迎使用学生信息管理系统              
");
	printf("*************************************************
");
	printf("#  1.添加新的学生信息    2.删除指定学生信息     #
");
	printf("#  3.查找指定学生信息    4.修改指定学生信息     #
");
	printf("#  5.分类统计学生个数    6.显示所有学生信息     #
");
	printf("#  7.排序所有学生信息    0.退出学生管理系统     #
");
	printf("*************************************************
");
}
static void modifymenu1()
{
	printf("*************************************************
");
	printf("#  1.修改整条学生信息    2.修改某项学生信息     #
");
	printf("#               0.退出修改菜单                  #
");
	printf("*************************************************
");
}
static void modifymenu2()
{
	printf("*************************************************
");
	printf("#       1.修改学生学号    2.修改学生姓名        #
");
	printf("#       3.修改学生性别    4.修改学生年龄        #
");
	printf("#       5,修改学生寝室号  6.修改学生电话号码    #
");
	printf("#       7.修改学生家庭住址 0.返回上一步修改     #
");
	printf("*************************************************
");
}
static void countmenu()
{
	printf("*************************************************
");
	printf("#  1.统计所有学生个数    2.按年龄统计学生个数   #
");
	printf("#  3.按寝室号统计学生个数4.按性别统计学生个数   #
");
	printf("#                  0.结束统计                   #
");
	printf("*************************************************
");
}

void initstus(stumgt* pstus)//初始化学生管理系统这个结构体变量
{
	assert(pstus != NULL);
	memset(pstus, 0, sizeof(stumgt));
}
static int is_repeat(stumgt* pstus, char tmp[]) //判断学号信息是否重复
{
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(tmp, pstus->stu[i].sno) == 0)
		{
			return 1;
		}
	}
	return 0;
}
void addstu(stumgt* pstus)
{
	assert(pstus != NULL);
	if (pstus->sz == 100)
	{
		printf("学生信息已满,无法新增学生信息
");
		return;
	}
	else
	{
		system("cls"); //输入学生信息前清屏一次
		printf("请输入学生学号:");
		char tmp[20] = { 0 };
		scanf("%s", tmp);
		if (is_repeat(pstus, tmp))   //学生学号为主要属性  应是唯一的且不能为空
		{
			printf("输入失败!!!已存在学号信息为%s的学生,不同学生信息不允许设置相同学号
", tmp);
			return;
		}

		strcpy(pstus->stu[pstus->sz].sno, tmp);  //不存在重复时将当前信息拷贝作为学生学号信息
		printf("请输入学生名字:");
		scanf("%s", pstus->stu[pstus->sz].name);
		printf("请输入学生性别:");
		scanf("%s", pstus->stu[pstus->sz].sex);
		printf("请输入学生年龄:");
		scanf("%d", &pstus->stu[pstus->sz].age); //注意年龄这里要&其他的都是地址
		printf("请输入学生寝室号:");
		scanf("%s", pstus->stu[pstus->sz].roomnum);
		printf("请输入学生电话号码:");
		scanf("%s", pstus->stu[pstus->sz].number);
		printf("请输入学生家庭住址:");
		scanf("%s", pstus->stu[pstus->sz].add);
		pstus->sz++;
		system("cls");
		printf("添加成功
");
	}
}

void pritstus(stumgt* pstus)   //打印所有信息
{
	assert(pstus != NULL);
	system("cls");   //输出所有信息前先清屏一次
	printf("%-10s	%-10s	%-5s	%-10s	%-10s	%-12s	%-20s	
", "学号", "姓名", "性别", "年龄", "寝室号", "电话号码", "家庭住址");//先设置好对应字段格式
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		printf("%-10s	%-10s	%-5s	%-10d	%-10s	%-12s	%-20s	
",  //按设置好的格式对其打印数据
			pstus->stu[i].sno,
			pstus->stu[i].name,
			pstus->stu[i].sex,
			pstus->stu[i].age,
			pstus->stu[i].roomnum,
			pstus->stu[i].number,
			pstus->stu[i].add);
	}
}
static int findstu(stumgt* pstus,char tmp[])  //封装的内部 查找学生学号信息的函数 找到返回对应的数组元素下标 没找到返回-1
{
	assert(pstus != NULL);
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(tmp, pstus->stu[i].sno) == 0)
			return i;
	}
	return -1;
}
void dropstu(stumgt* pstus)  //删除学生信息
{
	assert(pstus != NULL);
	if (pstus->sz == 0)   //判断学生记录是否为空
	{
		printf("当前没有学生信息,无法删除
");
		return;
	}
	char tmp[20] = { 0 };
	printf("输入要删除的学生的学号信息:");
	scanf("%s", tmp);
	int num = findstu(pstus,tmp);  //使用内部封装的查找函数
	if ( num== -1)
	{
		printf("没有找到要删除的学生信息
");
		return;
	}
	else
	{
		int i = 0;
		for (i = num + 1; i < pstus->sz; i++)
		{
			pstus->stu[i - 1] = pstus->stu[i];
		}
		pstus->sz--;
		printf("已删除学号为%s的学生成员
",tmp);
	}
}
void search(stumgt* pstus)  //查找学生信息的函数  以名字作为查找标准
{
	assert(pstus != NULL);
	char tmp[20] = { 0 };
	printf("请输入要查找的学生姓名:");
	scanf("%s", tmp);
	printf("已查询到以下姓名为%s的学生信息↓↓↓
",tmp);  //找到后按设置的对齐格式输出查找的信息
	printf("%-10s	%-10s	%-5s	%-10s	%-10s	%-12s	%-20s	
", "学号", "姓名", "性别", "年龄", "寝室号", "电话号码", "家庭住址");
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(tmp, pstus->stu[i].name) == 0)
		{
			printf("%-10s	%-10s	%-5s	%-10d	%-10s	%-12s	%-20s	
",
				pstus->stu[i].sno,
				pstus->stu[i].name,
				pstus->stu[i].sex,
				pstus->stu[i].age,
				pstus->stu[i].roomnum,
				pstus->stu[i].number,
				pstus->stu[i].add);
		}
	}
}
static void modifyall(stumgt* pstus)  //内部封装的修改整条学生信息的函数
{
	char tmp[20] = { 0 };
	printf("请输入要修改的学生学号信息:");  
	scanf("%s", tmp);

	int num = findstu(pstus, tmp);  //先判断是否存在要修改的学生信息
	if (num == -1)
	{
		printf("未找到要修改的学生信息
");
		return;
	}
	else
	{
		system("cls"); //输入学生信息前清屏一次
		printf("请输入学生学号:");
		char tmp[20] = { 0 };
		scanf("%s", tmp);
		if (is_repeat(pstus, tmp))   //学生学号为主要属性  应是唯一的且不能为空
		{
			printf("输入失败!!!已存在学号信息为%s的学生,不同学生信息不允许设置相同学号
", tmp);
			return;
		}

		strcpy(pstus->stu[num].sno, tmp);  //修改后的学号在之前学生信息里没有重复的则将tmp的拷贝修改当前学生信息学号
		printf("请输入学生名字:");
		scanf("%s", pstus->stu[num].name);
		printf("请输入学生性别:");
		scanf("%s", pstus->stu[num].sex);
		printf("请输入学生年龄:");
		scanf("%d", &pstus->stu[num].age);
		printf("请输入学生寝室号:");
		scanf("%s", pstus->stu[num].roomnum);
		printf("请输入学生电话号码:");
		scanf("%s", pstus->stu[num].number);
		printf("请输入学生家庭住址:");
		scanf("%s", pstus->stu[num].add);
	}
}
static void modifysno(stumgt* pstus,int num) //内部封装的单独修改学号的函数
{
	printf("你要将学号修改为:");
	char tmp[20] = { 0 };
	scanf("%s", tmp);
	if (is_repeat(pstus, tmp))
	{
		printf("修改失败,不能输入已有的学号
");
		return;
	}
	else
	{
		strcpy(pstus->stu[num].sno, tmp);
		printf("修改成功
");
	}
	
}
static void modifyname(stumgt* pstus, int num)//内部封装的单独修改名字的函数
{
	printf("你要将名字修改为:");
	scanf("%s", pstus->stu[num].name);
	printf("修改成功
");
}
static void modifysex(stumgt* pstus, int num)//内部封装的单独修改性别的函数
{
	printf("你要将性别修改为:");
	scanf("%s", pstus->stu[num].sex);
	printf("修改成功
");
}
static void modifyage(stumgt* pstus, int num)//内部封装的单独修改年龄的函数
{
	printf("你要将年龄修改为:");
	scanf("%d", &pstus->stu[num].age);
	printf("修改成功
");
}
static void modifyroomnum(stumgt* pstus, int num)//内部封装的单独修改寝室号的函数
{
	printf("你要将寝室号修改为:");
	scanf("%s", pstus->stu[num].roomnum);
	printf("修改成功
");
}
static void modifynumber(stumgt* pstus, int num)//内部封装的单独修改电话号码的函数
{
	printf("你要将电话号码修改为:");
	scanf("%s", pstus->stu[num].number);
	printf("修改成功
");
}
static void modifyadd(stumgt* pstus, int num)//内部封装的单独修改地址的函数
{
	printf("你要将地址修改为:");
	scanf("%s", pstus->stu[num].add);
	printf("修改成功
");
}

static void modifyone(stumgt* pstus)  //内部封装修改整条学生信息里的某项信息函数
{
	char tmp[20] = { 0 };
	printf("请输入要修改的学生学号信息:");
	scanf("%s", tmp);
	int num = findstu(pstus, tmp);  //先判断是否存在该学生信息
	if (num == -1)
	{
		printf("未找到要修改的学生信息
");
		return;
	}
	else
	{
		int input = 0;
		modifymenu2();  //下面为函数指针数组将一个0和上面7个封装好的修改对应学生信息的函数指针作为数组初始化信息(0是为了方便下标对其选项)
		void(*mod[8])(stumgt*, int) = { 0,modifysno,modifyname,modifysex,modifyage,modifyroomnum,modifynumber,modifyadd };
		printf("请选择修改的内容:");
		do
		{
			scanf("%d", &input);
			if (input >= 8 || input < 0)
			{
				printf("非法输入,请重新选择
");
				
			}
			else if (input == 0)
			{
				printf("退回上一层修改菜单
");
			}
			else
			mod[input](pstus, num); //根据菜单对应input输入的值调用 数组里相对应的函数指针
			
		} while (input >= 8 || input <0); //超出重新输入
		
	}
}
void modifystu(stumgt * pstus)  //修改学生信息的函数
{
	
	
	int input = 0;
	do
	{
		modifymenu1();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)//选择修改整条学生信息还是修改一条里某一项的学生信息
		{
		case 1:
			modifyall(pstus);  
			break;
		case 2:
			modifyone(pstus);
			break;
		case 0:
			printf("已结束修改操作
");
			break;
		default:
			printf("非法输入,请重新输入
");
		}
		
	} while (input);
	
}
static void countall(stumgt* pstus)  //内部封装的统计当前所有学生信息记录函数
{
	printf("已统计当前系统中有%d个学生
", pstus->sz);
	return;
}
static void countage(stumgt* pstus)  //统计年龄范围内学生记录的个数
{
	int age1 = 0;
	int age2 = 0;
	int age = 0;
	printf("请输入两个数字将统计其范围内的年龄个数(如果两个数字相同则统计这个数字年龄的学生个数)");
	scanf("%d%d", &age1, &age2);
	int count = 0;
	int i = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		 age = pstus->stu[i].age;
		if (age >= age1 && age <= age2)
		{
			count++;
		}
	}
	printf("在%d岁和%d岁之间的学生个数为%d
", age1, age2, count);
	return;
}
static void countroom(stumgt* pstus) //统计 寝室号的个数
{
	char room[20] = { 0 };
	printf("请输入寝室号:");
	scanf("%s", room);
	int i = 0;
	int count = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(room, pstus->stu[i].roomnum) == 0)
		{
			count++;
		}
	}
	printf("寝室号为%s的寝室个数为%d个
", room, count);
	return;
}
static countsex(stumgt* pstus)   //统计相同性别的学生个数
{
	char sex[5] = { 0 };
	printf("请输入要统计的性别:");
	scanf("%s", sex);
	int i = 0;
	int count = 0;
	for (i = 0; i < pstus->sz; i++)
	{
		if (strcmp(sex, pstus->stu[i].sex) == 0)
		{
			count++;
		}
	}
	printf("性别为%s的学生个数为:%d
", sex, count);
}
void countstu(stumgt* pstus)  //统计学生信息的函数
{
	assert(pstus != NULL);
	system("cls");
	
	int input = 0;
	do
	{
		countmenu();
		printf("请选择统计方式:");
		scanf("%d", &input);  
		switch (input)  //对应菜单输入input选择 跳转到上面封装的统计函数
		{
		case 1:
			countall(pstus);
			break;
		case 2:
			countage(pstus);
			break;
		case 3:
			countroom(pstus);
			break;
		case 4:
			countsex(pstus);
			break;
		case 0:
			printf("已结束统计
");
			break;
		default:
			printf("非法输入,请重新选择
");
		}
			
	} while (input);
}
 int cmp_sno(const studata stu1, const studata stu2) // 为qsort 函数设置的函数指针 用于比较两个元素的大小传给qsort
{
	return strcmp(stu1.sno, stu2.sno);    //比较两个学生里的学号大小 进行排序 这两个学生元素
}
void sortstu(stumgt* pstus) //  升序排序所有学生记录的函数
{
	if (pstus->sz == 0)   //判断排序时是否为空
	{
		printf("当前学生记录为空,无法排序
");
		return;
	}
	qsort(pstus, pstus->sz, sizeof(studata), cmp_sno);
	printf("已按学号完成升序排序
");
}

五.学生信息管理系统设计总结

本篇博客实现了对学生信息管理系统1.0的简易设计,是一个静态版本.主要实现了对学生信息的增删查改,显示,统计,排序,等功能共516行代码,后续会发布动态增长2.0版本

写文不易,给个一键三连支持下吧~

在这里插入图片描述