📢文章已收录于我的博客,欢迎访问:https://keyhuy.gitee.io/posts/202304019a4b78c86ac3
📄 StuManage.h(头文件)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define OK 1
#define ERROR 0
#define INFINITY INT_MAX //计算机允许的整数最大值,即无穷大
#define MAXSIZE 11 //默认存入的学生个数
typedef int Status; // Status是函数的类型,其值是函数结果状态代码,如OK等
//学生信息结构体
typedef struct{
int num;//学号,默认为8位数字,前4位表示年级,第5和6位表示性别,01表示男,00表示女
char *name;//姓名
char gender;//性别 ,M表示男,W表示女
int avscore;//平均成绩
int clas;//班级,与类class区分开
char *major;//专业,都是计算机学院的专业
}Stu;
//学生链表
typedef struct SLNode{
Stu data;//学生信息
struct SLNode *next;
}SLNode,*SLinkList;
/*创建学生信息链表*/
//学生链表初始化
Status InitList(SLinkList &SL){
SL = (SLinkList)malloc(sizeof(SLinkList));//创建一个头节点分配空间
//为专业和姓名两个数组分配空间
SL->data.major = (char *)malloc(sizeof(char));
SL->data.name = (char *)malloc(sizeof(char));
if(!SL||!SL->data.major||!SL->data.name) return ERROR;//分配失败,返回失败
SL->next = NULL;//分配成功,创建头节点,返回OK
return OK;
}
//构建一个学生节点
SLNode *MakeNode(Stu s){
SLNode *p;
p = (SLNode *)malloc(sizeof(SLNode));
if(!p) return NULL;//构建失败,返回空指针
//分配空间成功,构建新节点p,并返回
p->data = s;
p->next = NULL;
return p;
}
//录入学生信息(插入),按学号大小升序插入
Status EnterNode(SLinkList &SL, SLNode *p){
if(!SL||!p) return ERROR;//头节点或要插入的节点为空,参数不合理,返回ERROR
SLNode *q;
q = SL->next;//q指向第一个学生节点
if(!q){ //若第一个学生节点为空,直接插入新学生节点作为第一位学生
SL->next = p;
p->next = NULL;
return OK; //插入完成,返回OK;
}else{//第一个学生节点不为空,按照学号大小升序插入
//若p学号比第一位学生的学号还小,则在最前面插入
if(p->data.num < q->data.num){
p->next = q;
SL->next = p;
return OK;
}else{
while(q->next){
//若原来学生中已有p学生的信息,插入失败
if(p->data.num == q->data.num) return ERROR;
//若p学号大小大于当前节点且小于当前节点下一个节点,则插入
if(q->data.num < p->data.num&&(q->next)->data.num > p->data.num){
p->next = q->next;
q->next = p;
return OK;
}
q = q->next;//未找到继续遍历下一个节点
}
//若p学号大小比最后一个学生节点还大,直接插到最后
q->next = p;
p->next = NULL;
return OK;
}
}
return ERROR;
}
//构建长度为n的学生有序单链表,数组S[]提供n个元素值(学生)
Status CreateList(SLinkList &SL, int n, Stu *S){
SLNode *sp;
//初始化失败或参数不合理,返回ERROR
if(!InitList(SL)||n <= 0||!S) return ERROR;
//依次插入n个节点
for(int i = 0;i < n;i++){
sp = MakeNode(S[i]);//以S[i]提供的信息创建新的节点
if(!EnterNode(SL,sp)) return ERROR;//有序插入,如果插入失败,返回ERROR;
}
return OK;
}
/*对学生信息进行操作*/
//输出全部学生信息
void OutputAll(SLinkList SL){
SLNode *p;
p = SL->next;
printf("学号\t\t姓名\t性别 平均成绩\t班级\t专业\n");
while(p){
printf("%d\t%s\t%c\t%d\t%d\t%s\n",
p->data.num,p->data.name,p->data.gender,p->data.avscore,p->data.clas,p->data.major);
p = p->next;
}
}
//输出单个学生信息
void Output(SLNode *p){
//printf("学号\t\t姓名\t性别 平均成绩\t班级\t专业\n");
printf("%d\t%s\t%c\t%d\t%d\t%s\n",
p->data.num,p->data.name,p->data.gender,p->data.avscore,p->data.clas,p->data.major);
}
//通过学号查找目标学生的前一个学生(方便删除操作),找到返回该学生结点,找不到返回空指针
SLNode *NumFindNode(SLinkList SL, int n){
SLNode *p;
p = SL->next;
//如果目标节点为第一位学生,则返回头节点
if(p->data.num == n) return SL;
//遍历每一个结点,找到目标节点的前一个节点就返回
while(p->next){//如果写p会出错
if(p->next->data.num == n) return p;
p = p->next;
}
return NULL;
}
//初始化一个学生信息结构体类型变量
void InitStu(Stu &S){
S.major = (char *)malloc(sizeof(char));
S.name = (char *)malloc(sizeof(char));
}
/*对信息进行检查*/
//汉字比较
Status CompareChinese(char *c, SLNode *p){
char a[3];//定义一个字符数组来存储一个汉字
for(int j = 0;j < strlen(p->data.name);j += 2){//汉字的存储占两个字节,故j每次加2
//一个汉字占两个字节,把每个字节当成一个字符赋给数组a,最后赋值一个字符0作为结束。
a[0] = *(p->data.name+j);
a[1] = *(p->data.name+j+1);
a[2] = '\0';
//用strcmp函数比较两个汉字
if(!strcmp(a,c)) return OK;//找到直接返回OK
}
//没找到
return ERROR;
}
//检查学生信息的合理性
Status CheckManage(Stu s){
int j = 0;
char *maj[4] = {"软件工程","计算机科学与技术","信息安全","网络工程"};
//先检查学号、班级、成绩合理性
if(s.num <= 20170000||s.num >= 20200199||s.clas <= 0||s.clas > 5||s.avscore < 0||s.avscore > 100)
return ERROR;
if((s.num%10000)/1000 != 0&&((s.num%1000)/100 != 0||(s.num%1000)/100 != 1))
return ERROR;
//再检查性别合理性
if(((s.num%1000)/100 == 1&&s.gender != 'M')||((s.num%1000)/100 == 0&&s.gender != 'W'))
return ERROR;
//再检查姓名合理性
for(int i = 0;i < strlen(s.name);i += 2)
if(*(s.name+i) > 0) return ERROR;
//最后检查专业合理性
for(int i = 0;i < strlen(s.major);i += 2)
if(*(s.major+i) > 0) return ERROR;
//如果专业都是汉字就看是不是计算机专业
for(j = 0;j < 4;j++)
if(!strcmp(maj[j],s.major)) break;//如果输入有符合的专业就结束循环
if(j == 4) return ERROR;//for循环进行到最后,说明专业不符合
return OK;
}
//检查有无信息冲突
Status CheckMaConflict(Stu s, SLinkList SL){
if(!SL) return ERROR;
SLNode *p = SL->next;
while(p){
if(s.num == p->data.num) return ERROR;//学号不能一样,直接返回ERROR
//如果其他信息完全一样,则产生冲突,返回ERROR
if(!strcmp(s.name,p->data.name)&&s.gender == p->data.gender&&
s.avscore == p->data.avscore&&s.clas == p->data.clas&&!strcmp(s.major,p->data.major))
return ERROR;
p = p->next;
}
return OK;
}
📄 StuManage.cpp(源文件)
#include "StuManage.h"
//修改学生信息
void ModifyManage(SLinkList &SL, int num){
// 参数不合理,直接返回
if(!SL||num <= 0||num <= 20170000||num >= 20200199){//学号默认大于0且为大于20170000且小于等于20200199的8位数字
printf("\n参数不合理,修改失败!(@.@)\n");
return ;
}
int flag;
SLNode *p,*q;
q = NumFindNode(SL,num);//调用函数找到该学生的前一个学生
//找到该结点
if(q&&q->next){
p = q->next;//p指向目标学生节点
printf("\n您要修改的学生信息为:\n");
printf("学号\t\t姓名\t性别 平均成绩\t班级\t专业\n");
Output(p);//输出修改前该学生信息
Stu s1;
InitStu(s1);//先初始化一个新的学生信息结构体变量,再替换原来学生链表中的学生信息
printf("\n请您按照如下格式依次重新输入该学生信息:\n");
printf("学号(8位学号) 姓名 性别(M/W) 平均成绩 班级 专业\n");
scanf("%d %s %c %d %d %s",&s1.num,s1.name,&s1.gender,&s1.avscore,&s1.clas,s1.major);
printf("\n请问您是否确认修改信息?是(1)/否(0):");
scanf("%d",&flag);
//如果用户不确认,则重新输入
if(!flag){
Stu s2;
InitStu(s2);
printf("\n请重新输入:\n");
printf("学号(8位学号) 姓名 性别(M/W) 平均成绩 班级 专业\n");
scanf("%d %s %c %d %d %s",&s2.num,s2.name,&s2.gender,&s2.avscore,&s2.clas,s2.major);
if(!CheckManage(s2)){
printf("\n输入参数不合理,修改失败!(@.@)\n");
return ;
}
//如果信息由冲突,则修改失败
if(!CheckMaConflict(s2,SL)){
printf("\n输入信息有冲突,修改失败!(@.@)\n");
return ;
}
//如果学号没有被修改,则直接替换原来信息
if(s2.num == p->data.num)
p->data = s2;//用外部输入的新信息替换原来的学生信息
else{//如果学号被修改,则需重新排序插入
p->data = s2;
q->next = p->next;
p->next = NULL;
//重新插入
EnterNode(SL,p);
}
}else{
if(!CheckManage(s1)){
printf("\n输入参数不合理,修改失败!(@.@)\n");
return ;
}
//检查输入信息有无冲突
if(!CheckMaConflict(s1,SL)){
printf("\n输入信息有冲突或与原信息相同,修改失败!(@.@)\n");
return ;
}
//如果学号没有被修改,则直接替换原来信息
if(s1.num == p->data.num)
p->data = s1;//用外部输入的新信息替换原来的学生信息
else{//如果学号被修改,则需重新排序插入
p->data = s1;
q->next = p->next;
p->next = NULL;
//重新插入
EnterNode(SL,p);
}
}
printf("\n修改成功!(^0^)\n当前全部学生信息为:\n");
OutputAll(SL);//输出当前全部学生信息
}else printf("\n修改失败!未找到该学生信息(@.@)\n");
}
//删除学生信息
void DeleteNode(SLinkList &SL, int num){
//参数不合理,直接返回
if(!SL||num <= 20170000||num >= 20200199){//学号默认大于0且为大于20170000的8位数字
printf("\n参数不合理,删除失败!(@.@)\n");
return ;
}
int flag;
SLNode *p,*q;
q = NumFindNode(SL,num);//q指向目标学生的前一个
//找到就删除
if(q&&q->next){
p = q->next;//p指向目标学生
printf("您要删除的学生的信息为:\n");
printf("\n学号\t\t姓名\t性别 平均成绩\t班级\t专业\n");
Output(p);
printf("\n请问您是否确认删除该学生信息?是(1)/否(0):");
scanf("%d",&flag);
//用户不确认,删除失败,直接返回
if(!flag){
printf("\n删除失败!(@.@)\n");
return ;
}
q->next = p->next;
free(p);//销毁目标学生节点
printf("\n删除成功!(^0^)\n当前学生信息为:\n");
OutputAll(SL);//输出当前学生信息
}else printf("\n删除失败!未找到该学生信息(@.@)\n");//找不到返回失败
}
//插入新的学生结点
void InsertNode(SLinkList &SL){
if(!SL){
printf("插入失败!参数不合理\n");
return ;
}
Stu s1;
InitStu(s1);
printf("\n请您按照如下格式依次输入新的学生的信息:\n");
printf("学号(8位学号) 姓名 性别(M/W) 平均成绩 班级 专业\n");
scanf("%d %s %c %d %d %s",&s1.num,s1.name,&s1.gender,&s1.avscore,&s1.clas,s1.major);
//检查输入参数合理性以及信息有无冲突
if(!CheckManage(s1)) printf("\n参数不合理,插入失败!(@.@)\n");
else if(!CheckMaConflict(s1,SL)) printf("\n输入信息有冲突,修改失败!(@.@)\n");
else if(!MakeNode(s1)) printf("\n参数不合理,插入失败!(@.@)\n");
else if(EnterNode(SL,MakeNode(s1))){//调用EnterNode函数将新节点插入
printf("\n插入成功!(^0^)\n当前全部学生信息为:\n");
OutputAll(SL);//输出当前全部学生信息
}else printf("\n插入失败!(@.@)\n");
}
//按照学号检索学生信息
void NumSearchNode(SLinkList SL, int num){
//参数不合理,直接返回
if(!SL||num <= 20170000||num >= 20200199){
printf("\n参数不合理,检索失败!(@.@)\n");
return ;
}
SLNode *p;
//找到目标学生节点的前一个
p = NumFindNode(SL,num);
if(p&&p->next){
//输出目标学生的信息
printf("\n检索成功!(^0^)\n该学生信息为:\n");
printf("学号\t\t姓名\t性别 平均成绩\t班级\t专业\n");
Output(p->next);
}else printf("\n检索失败!(@.@)未找到相关信息\n");
}
//模糊检索学生信息
/*
功能介绍:
1、通过学号前4位(也就是年级)模糊检索,输出学号前4位都一样的学生信息
2、通过单个汉字模糊检索,输出姓名中有该字的学生信息
3、通过班别模糊检索,输出班别一样的学生信息
4、通过专业模糊检索,输出专业一样的学生信息
*/
void SearchNode(SLinkList SL){
//flag用来标记是否找到相关信息 ;k用来判断是否需要输出学生信息格式,找不到信息就不用输出
int k = 0,choose,i,flag1,flag = 0;
char *c,*s;
SLNode *p = SL->next;
printf("请选择检索的方式:\n学号前4位--2/单个汉字---3/班别----4/专业----5\n");
scanf("%d",&choose);
//用switch语句来实现选择
switch(choose){
case 2:
//学号前4位检索
printf("\n请输入您要检索的学号前4位:");
scanf("%d",&i);
if(i > 2020||i < 2017){//年级范围为2017到2020
printf("\n参数不合理\n");
break;
}
printf("\n学号\t\t姓名\t性别 平均成绩\t班级\t专业\n");
while(p){
if(p->data.num/10000 == i){
flag = 1;
Output(p);//满足条件的就输出;
}
p = p->next;
}
break;
case 3:
//姓名中汉字检索
//因为一个汉字占两个字节,相当于两个字符,故用字符串指针来存入外部输入的汉字
c = (char *)malloc(sizeof(char));
printf("\n请输入您要检索的汉字:");
scanf("%s",c);
//判断输入参数是否为汉字(汉字的第一个字节首位为1,对于有符号字符型来说是负数)
if(*c > 0){
printf("\n参数不合理\n");
free(c);//输入参数不合理,直接销毁c
break;
}
while(p){
//调用函数比较汉字
if(CompareChinese(c,p)){
k++;
if(k == 1) printf("\n学号\t\t姓名\t性别 平均成绩\t班级\t专业\n");
flag = 1;
Output(p);
}
p = p->next;
}
free(c);//用完c就销毁,释放内存
break;
case 4:
//班级检索
printf("\n请输入您要检索的班级:");
scanf("%d",&i);
if(i <= 0||i > 5){//班级号范围为1到5
printf("\n参数不合理(@.@)\n");
break;
}
printf("\n学号\t\t姓名\t性别 平均成绩\t班级\t专业\n");
while(p){
if(p->data.clas == i){
flag = 1;
Output(p);
}
p = p->next;
}
break;
case 5:
//专业检索
flag1 = 0;//用来判断参数是否合理
s = (char *)malloc(sizeof(char));
printf("\n请输入您要检索的专业:");
scanf("%s",s);
//判断输入参数是否都为汉字
for(int j = 0;j < strlen(s);j += 2){
if(*(s+j) > 0){
printf("\n参数不合理\n");
flag1 = 1;
free(s);//参数不合理,直接销毁s
}
}
if(flag1) break;
while(p){
if(!strcmp(p->data.major,s)){//用strcmp函数比较两个字符串,相同就返回0
k++;
if(k == 1) printf("\n学号\t\t姓名\t性别 平均成绩\t班级\t专业\n");
flag = 1;
Output(p);
}
p = p->next;
}
free(s);//用完s就销毁,释放内存
break;
default:
printf("\n参数不合理");
break;
}
//通过flag的值判断是否找到目标信息
if(!flag) printf("\n未找到相关信息,检索失败!(@.@)\n");
else printf("\n检索成功!(^0^)\n");
}
//main函数实现
int main(){
int num1,choose,m = 1;
SLinkList SL;
//N=11,默认录入11个学生信息
Stu stu[MAXSIZE] = {{20200091,"张三",'W',60,3,"软件工程"},
{20190100,"李华",'M',90,4,"计算机科学与技术"},
{20190102,"陈皮",'M',100,3,"软件工程"},
{20180080,"吴屏",'W',81,1,"信息安全"},
{20190111,"麦仁",'M',98,5,"网络工程"},
{20170075,"李柱",'W',76,2,"计算机科学与技术"},
{20180129,"陈刘",'M',76,1,"网络工程"},
{20170156,"李广",'M',59,2,"信息安全"},
{20200043,"刘华",'W',75,3,"软件工程"},
{20190118,"张友",'M',66,5,"计算机科学与技术"},
{20180138,"华山",'M',78,4,"信息安全"}
};
//录入学生信息,创建学生链表
CreateList(SL,MAXSIZE,stu);
//功能选择
/*功能选择介绍
输出当前全部学生信息,扣1
插入新的学生,扣2
删除某个学生,扣3
修改某个学生信息,扣4
按学号检索某个学生信息,扣5
检索学生信息,扣6
结束进程,扣0*/
printf("\n\t*********************************************************************\n");
printf("\t* * \n");
printf("\t* 欢迎进入学生信息管理系统(^0^) *\n");
printf("\t* *\n");
printf("\t* *\n");
printf("\t*********************************************************************\n");
//用一个for循环实现多次选择操作,最多可选择无穷大次
for(int i = 0;i < INFINITY;i++){
if(i != 0) printf("\n\t\t\t**********学生信息管理系统**********\n");
printf("\n\t\t\t*************************************\n");
printf("\n\t\t\t* 输出当前全部学生信息--1 *\n");
printf("\t\t\t* 插入学生信息----------2 *\n");
printf("\t\t\t* 删除学生信息----------3 *\n");
printf("\t\t\t* 修改学生信息----------4 *\n");
printf("\t\t\t* 按学号检索学生信息----5 *\n");
printf("\t\t\t* 模糊检索学生信息------6 *\n");
printf("\t\t\t* 退出系统--------------0 *\n");
printf("\n\t\t\t*************************************\n");
printf("\n*请选择您想要进行的操作:");
scanf("%d",&choose);
switch(choose){
case 1:
//输出当前全部学生信息
system("cls");
printf("\n\t*********************************************************************\n");
printf("\t * * \n");
printf("\t * 欢迎进入学生信息管理系统(^0^) *\n");
printf("\t * *\n");
printf("\t * 当前功能为 输出当前全部学生信息 *\n");
printf("\t * *\n");
printf("\t*********************************************************************\n");
printf("\n当前全部学生信息为:\n\n");
OutputAll(SL);
break;
case 2:
//插入
system("cls");
printf("\n\t*********************************************************************\n");
printf("\t * * \n");
printf("\t * 欢迎进入学生信息管理系统(^0^) *\n");
printf("\t * *\n");
printf("\t * 当前功能为 插入学生信息 *\n");
printf("\t * *\n");
printf("\t*********************************************************************\n");
InsertNode(SL);//调用插入函数
break;
case 3:
//删除
system("cls");
printf("\n\t*********************************************************************\n");
printf("\t * * \n");
printf("\t * 欢迎进入学生信息管理系统(^0^) *\n");
printf("\t * *\n");
printf("\t * 当前功能为 删除学生信息 *\n");
printf("\t * *\n");
printf("\t*********************************************************************\n");
printf("\n当前全部学生信息为:\n\n");
OutputAll(SL);
printf("\n请输入您要删除的学生的学号:");
scanf("%d",&num1);
DeleteNode(SL,num1);
break;
case 4:
//修改
system("cls");
printf("\n\t*********************************************************************\n");
printf("\t * * \n");
printf("\t * 欢迎进入学生信息管理系统(^0^) *\n");
printf("\t * *\n");
printf("\t * 当前功能为 修改学生信息 *\n");
printf("\t * *\n");
printf("\t*********************************************************************\n");
printf("\n当前全部学生信息为:\n\n");
OutputAll(SL);
printf("\n请输入您要修改的学生的学号:");
scanf("%d",&num1);
ModifyManage(SL,num1);
break;
case 5:
//按学号检索
system("cls");
printf("\n\t*********************************************************************\n");
printf("\t * * \n");
printf("\t * 欢迎进入学生信息管理系统(^0^) *\n");
printf("\t * *\n");
printf("\t * 当前功能为 按学号检索 *\n");
printf("\t * *\n");
printf("\t*********************************************************************\n");
printf("\n请输入您要检索的学生的学号:");
scanf("%d",&num1);
NumSearchNode(SL,num1);
break;
case 6:
//模糊检索
system("cls");
printf("\n\t*********************************************************************\n");
printf("\t * * \n");
printf("\t * 欢迎进入学生信息管理系统(^0^) *\n");
printf("\t * *\n");
printf("\t * 当前功能为 模糊检索 *\n");
printf("\t * *\n");
printf("\t*********************************************************************\n\n");
SearchNode(SL);
break;
case 0:
//退出系统
m = 0;
printf("\n您已成功退出系统,感谢您的使用,再见!");
break;
default:
printf("\n参数不合理,系统已自动关闭(@.@)\n");
m = 0;
break;
}
if(!m) break;
system("pause");
system("cls");//清空窗口的内容
}
return 0;
}
💻 运行初始界面
🔗 源码地址