《C语言》学生信息管理系统:链表(嵌套)+文件


前言:

基本信息:

登录信息文件(自定义):

学生信息文件(自定义):

“系统构思”:

学生信息链表:

课程信息链表:

运行截图和基本函数:

初始化账户:

用户登录界面:

根据学号查找学生:

根据名称查找学生:

导入学生信息:

导出学生信息:

管理员删除页面:

按学号删除学生:

释放所有动态内存:

查询某班级某门课程排名情况(自行转换瑕疵):

展示所有学生信息:

展示某个同学信息:

管理员添加学生信息:

是否确认修改:

改变学生信息:

课程信息更改:

源码:


 
 

前言:

源码置于文末,原创,取用不忘点赞,不符之处请读者根据要求自行更改!

基本信息:

登录信息文件(自定义):

学生信息文件(自定义):

“系统构思”:

学生信息链表:

课程信息链表:

运行截图和基本函数:

初始化账户:

void initaccountes(Loggers* q){
    FILE *fp=fopen(Infileaccount,"r");//以只读的方式打开登录信息文本文件,文件必须存在 
    if(!fp){printf("用户登陆信息文件打开失败!\n");exit(2);}//文件打开失败提醒 
    (*q)->next=NULL;//为登录信息链表头插法做准备 
    Loggers current=(Loggers)malloc(sizeof(loggers));//申请登录信息节点 
    if(!current){printf("初始化账户内存不够!\n");exit(3);}//申请失败提醒 
    printf("登录账号\t密码   身份\n");
    while(fscanf(fp,"%s%s%d",current->account,current->password,&current->users)==3)//按条件读取文件账号、密码以及身份 
		{
    		printf("%s\t%s\t%d\n",current->account,current->password,current->users);
        	current->next=(*q)->next;
        	(*q)->next=current;//头插法 
       	 	if(!(current=(Loggers)malloc(sizeof(loggers)))){
			printf("初始化账户内存不够!\n");exit(3);}//为下一次读取信息做准备 
        }
    printf("用户登陆信息显示成功!\n用户登陆信息文件%s内容读取成功!\n",Infileaccount);
    fclose(fp);//关闭文件 
}

用户登录界面:

void tablelog(Loggers q,Students qq){
 	initaccountes(&q);//调用函数初始化账户信息 
	shower(qq);//展示所有输入的学生信息 
 	printf(" _____________________________________\n");
 	printf("|        欢迎来到学生管理系统         |\n");
 	printf("|_____________________________________|\n");
 	char account1[15],password1[15];//登陆时输入的账号以及密码 
 	Loggers p,r;
 	int opportunity=Attemptingpassword,user,key=1;//key的值的改变判断登录成功与否 
 	while(key)
	{
  		printf("请依次正确输入您的账号,密码和用户类型(123456 abcdef 1普通用户/0管理员):");
  		while(fflush(stdin),scanf("%s%s%d",account1,password1,&user)!=3||user<0||user>1) printf("请输入正确数据格式以及状态(0/1):");//fflush(stdin)清空输入缓冲区,循环条件的满足为fflush(stdin)其后的','表达式后面的表达式是否为真 
  		p=r=q;
 		while(p=p->next)//第一个正确登陆数据节点是否存在并在其后不断循环 
   		if(!strcmp(account1,p->account)&&!(strcmp(password1,p->password)))//账号密码同时成立 
    		if(user)
			{
				printf("普通用户账号登陆成功!\n");
				key=0;//最外层循环条件不满足,表示登陆成功 
				norsearch(qq);//进入普通用户界面 
				freeall(&qq,&q);//释放所有账户以及学生信息 
				break;//终止用户登录验证界面(已经登陆成功) 
			}
    		else
			{
				printf("管理员账号登陆成功!\n");
				key=0;
				DeleteTable(&qq);//进入管理员操作页面 
				impartstuinfo(qq);//保存管理员操作后的信息 
				freeall(&qq,&q);
				break;
			}
  		if(!p)//登陆失败时查找失败原因(账号/密码/账号和密码)错误 
	  	{
   			r=q;//为头节点的下一届节点做准备 
   			if(--opportunity)//登陆机会减少1次后还有无机会(非零还有机会)
			   {
   			 		while(r=r->next)
					{
     				if(!strcmp(account1,r->account))//账号正确 
				 		{
      					printf("密码错误!您还有%d次有效机会!\n",opportunity);break;//错误原因查找成功 
						}
      				else if(!strcmp(password1,r->password))//密码正确 
				  		{
      					printf("账号错误!您还有%d次有效机会!\n",opportunity);break;
						}
					}
    				if(!r) //账号密码均不正确时访问至空节点 
					printf("账号密码错误!您还有%d次有效机会!\n", opportunity);
				}
   			else//opportunity为0时无剩余机会 
			   {
			   printf("很抱歉,机会已耗尽,您的账户已被锁定,请稍后尝试\n",opportunity);
			   freeall(&qq,&q);
			   exit(1);//登陆失败程序异常终止提醒 
			   }
  		}
	}
}

根据学号查找学生:

Students searchnumber(Students pre)
{
    printf("请输入您想要查询的学生学号(12345678901):");
    char number[15];
	Students now=pre;
    while(fflush(stdin),scanf("%s",number)!=1) printf("请输入正确学号(12345678901):");//清空输入缓冲区并检测是否满足输入条件 
    while(now)
	{
    	if(!strcmp(now->number,number))//学号查找成功 
		{
        	showerone(now);//展示查找到的学生的信息 
        	return now; 
        }
    	else if(!(now->next))//查找至最后一个节点的空指针域 
		{
			printf("无学号为%s的学生!\n",number);
        	return NULL;
		}
        now=now->next;
	}
}

根据名称查找学生:

Students searchname(Students pre,char*name,int num)
{
    int number=num;//是否重名以及是否存在此名称学生 
	Students now=pre;
    while(now)//学生节点存在即循环 
	{
    	if(!strcmp(now->name,name))//名称相匹配 
		{
        	showerone(now);//展示此学生信息 
			//printf("%d:学生%s查询成功!\n",++number,now->number,now->name);//show(now);
        	searchname(now->next,name,++number);//继续循环直至无学生信息节点 
        	return now;//返回查找到的当前节点 
        }
        else if(!(now->next)&&!number)//找至最后一个节点的空指针域以及number==0时为查找失败 
		{
			printf("无名称为%s的学生!\n",name);
        	return NULL;
    	}
    	now=now->next;//下一个学生节点 
	}
}

导入学生信息:

Students stuinfoget()
{
    FILE *fp=fopen(Infilestu,"r");//以只读的方式打开文本文件,文件必须存在 
    if(!fp){printf("文件%s打开失败,学生信息读取失败!\n",Infilestu);exit(1);}//文件读入失败时退出程序 
    Students current,previous=NULL,origin;
    Curriculums now,pre=NULL;
    char c=' ';//方便(c=='#')||((c=fgetc(fp))=='#')的正确执行 (如果是'#'而且没有到达文件尾直接进入循环,否则读取一个文件字符再进行循环)
    while(!feof(fp))//未到文件尾时继续循环 
	{
    	while(((c=='#')||((c=fgetc(fp))=='#'))&&c!=EOF)//先判断'#',是则判断是否不为EOF,否则读取一个文件后再判断EOF,如果刚开始以及读取一个后都不为'#',则退出此循环 
		{
    		if(!(current=(Students)malloc(sizeof(students)))){printf("内存不足,申请学生信息失败!\n");exit(1);}//申请内存信息失败时退出程序 
			if(fscanf(fp,"%s%s%s%s",current->banji,current->name,current->number,current->gender)==4)//成功读入学生基本信息 
			{
      	  		current->next=current->pre=NULL;//置空当前指针信息 
      	  		if(!previous) origin=current;//previous为空,此时为第一个节点,用origin保存 
      	  		if(!(now=current->curriculum=malloc(sizeof(curriculums)))){
				printf("内存不足,申请学生%s课程信息失败!\n",current->name);exit(2);}//申请此学生的第一个课程信息以及相应的判断 
				if(fscanf(fp,"%s%s%f",now->curriculum,now->semester,&now->score)==3)
					now->next=now->pre=NULL;//初始化第一个课程节点的指针域 
				pre=now;//方便下一个课程节点的插入 
             	while((c=fgetc(fp))=='$')//从第二个开始进行课程信息循环,退出时c要么为 '#',要么为EOF 
				{
             		if(!(now=malloc(sizeof(curriculums)))){
					printf("内存不足,申请学生%s课程信息失败!\n",current->name);exit(3);}//申请以及判断 
                	if(fscanf(fp,"%s%s%f",now->curriculum,now->semester,&now->score)==3)//成功读入课程信息 
                	{
						now->next=pre->next;//当前课程节点的后继为前一个节点的后继 
						now->pre=pre;//当前课程节点的前继为前一个结点 
						pre->next=now;//前一个课程节点的后继为当前课程节点 
					} 
					pre=now;//当前课程节点赋给前一个课程节点 
				}
        	}
        	if(previous)//如果学生信息节点不唯一,进行类似的插入操作 
			{
        		current->next=previous->next;
        		current->pre=previous;
        		previous->next=current;
			}
        	previous=current;//当前学生节点赋值给前一个学生节点 
		}
	}
	fclose(fp);//关闭打开文件 
    printf("学生信息读取成功!\n");
    return origin;
}

导出学生信息:

void impartstuinfo(Students q)
{
    FILE *fp=fopen(Outfilestu,"w");//w:以只写的方式打开文本文件,文件若存在则清空文件内容从文件头部开始写,若不存在则根据文件名创建新文件并只写打开 
    if(!fp){printf("写入文件%s打开失败!\n",Outfilestu);exit(1);}//打开失败,程序退出 
    Students current=q;Curriculums now;
    while(current)//学生信息节点存在时 
	{
    	if(strcmp(current->name,""))//如果为真,则为已经删除的第一个节点以及后继节点组成,此时跳过第一个节点 
		{
    		now=current->curriculum;
        	fprintf(fp,"#%s %s %s %s %s %s %.2f",current->banji,current->name,current->number,current->gender,now->curriculum,now->semester,now->score);//此方式方便打开文件的操作 
        	while(now=now->next)//第二个课程节点以及其后存在时 
			fprintf(fp,"$ %s %s %.2f",now->curriculum,now->semester,now->score);
			fputc('\n',fp);//输出换行符至已打开文件 
		}
        current=current->next;//下一个学生信息节点 
    }
    	fclose(fp);//关闭写入完毕的文件 
        printf("学生信息写入文件%s成功!\n",Outfilestu);
}

管理员删除页面:

void DeleteTable(Students* origin)
{
    Students now;
	int todo;
    char number[15],name[10];
    while(1)//不断循环 
	{
    	printf("请输入您想要进行的操作:1.按学号删除学生\t2.按名称查询学生\t3.按学号查询学生\t4.添加学生信息\t5.按学号修改学生信息\t6.退出(1/2/3/4/5/6):");
    	while(fflush(stdin),scanf("%d",&todo)!=1||todo<1||todo>6) printf("请输入有效选项(1-6):");//清空输入缓冲区并检验输入是否符合(是否进入循环) 
    	switch(todo)
		{
        	case 1:if(!(now=searchnumber(*origin))) break;//如果学号同学不存在则结束此轮选择 
               	deletesthroughnumber(&now);break;//否则调用函数删除/修改(第一个节点)节点信息后结束此轮选择 
        	case 2:printf("请输入待查找的名称(重庆):");
        	   	while(fflush(stdin),scanf("%s",name)!=1) ;
			   	searchname(*origin,name,0);break;//0不断在函数内更新以检验有无以及是否多个同名学生 
        	case 3:searchnumber(*origin);break;//调用函数 
        	case 4:anew(origin);break;//调用添加函数
			case 5:if(!(now=searchnumber(*origin))) break;
				changeable(&now);break;
        	case 6:return;//退出当前函数,返回上一级 
        	default:;
        }
    }
}

按学号删除学生:

void deletesthroughnumber(Students* origin)
{
	if(!*origin) exit(1);//*origin为空时,程序退出 
	if(!(*origin)->next&&!(*origin)->pre) exit(1);//*origin唯一时,程序退出 
	else if(!(*origin)->next)//由上一条if语句易知此时当前节点的两个指针域至少有一个不为空,此时节点空后,*origin为尾节点时,置空前一个节点的后指针域,并在最后统一释放内存 
		(*origin)->pre->next=NULL;
	else if(!(*origin)->pre)//此时节点空前,*origin为第一个节点,由于没有头节点,故仅将此节点所有信息置为空,第一个成绩数据记为负数(方便清空整个学生链表)
	{
		Curriculums previous,current=(*origin)->curriculum;
		strcpy((*origin)->banji,"");
		strcpy((*origin)->name,"");
		strcpy((*origin)->number,"");
		strcpy((*origin)->gender,"");
		strcpy(current->semester,"");
		strcpy(current->curriculum,"");
		current->score=Fault;
		while(current=current->next)//从第二个课程节点开始删除 
		{
			previous=current;
			current=current->next;
			free(previous);
		}
		(*origin)->curriculum->next=NULL;
		printf("删除成功!\n");
		return;//避免第一个节点被删除后结束时无法删除其后的节点 
	}
	else//当前节点的两个指针域都存在时的删除操作 
	{
   		(*origin)->pre->next=(*origin)->next;
    	(*origin)->next->pre=(*origin)->pre;
	}
	free(*origin);//统一删除可以删除的节点 
    printf("删除成功!\n");
}

释放所有动态内存:

void freeall(Students* origin,Loggers* key)
{
	if(*origin)//第一个学生信息节点存在时 
	{
		Students current=*origin,previous;
		Curriculums now,pre;
		while(current)//学生信息节点存在时 
		{
			now=current->curriculum;//当前学生的课程信息节点 
			while(now)//课程信息节点不为空时 
			{
				pre=now;//当前课程节点
				now=now->next;//下一个课程节点 
				free(pre);//释放当前课程节点 
			}
			previous=current;//当前学咸亨信息节点 
			current=current->next;//下一个学生信息节点 
			free(previous);//适当当前学生信息节点 
		}
	}
	Loggers p=*key,q;
	while(q=p,p=p->next)//有头节点的链表删除操作:q保留当前,p表示当前的指针域,若p不为空,释放当前节点 
		free(q);
	free(q);//释放循环条件假时的最后一个节点 
	printf("数据释放成功!\n");
}

查询某班级某门课程排名情况(自行转换瑕疵):

void searchclasscurriculumrank(Students origin){
	char banji[10],curriculum[20];
	int i=0,j,k,num;
	Students now=origin,primitive=origin;
	Curriculums current;
	ones a;//直接插入法的临时变量 
	Ones newone,previous=NULL,initial=NULL;
	printf("请输入班级和课程(计算机217 高数):");
	while(fflush(stdin),scanf("%s%s",banji,curriculum)!=2) printf("请输入有效信息:");
	while(now)//学生信息存在 
	{
		if(!strcmp(now->banji,banji))//班级符合 
		{
			current=now->curriculum;
			while(current)//课程信息存在 
			{
				if(!strcmp(current->curriculum,curriculum))//课程符合 
				{
					++i;break;//增加此班级课程人数 
				}
				current=current->next;
			}
		}
		now=now->next;
	}
	if(!i)//无待查找量 
	{
		printf("无此课程或班级!\n");
		exit(1);
	}
	if(!(initial=newone=(Ones)malloc(sizeof(ones)*(num=i))))//利用initial存储首地址,方便对已申请查找到的个数利用指针进行转数组进行排序
	{printf("申请信息失败!\n");exit(1);} 
	while(primitive)//将目标值(班级、学号和这门课程的分数)带入新申请的空间中 
	{
		if(!strcmp(primitive->banji,banji))
		{
			current=primitive->curriculum;
			while(current)
			{
				if(!(strcmp(current->curriculum,curriculum)))
				{
					newone->score=current->score;
					strcpy(newone->number,primitive->number);
					strcpy((newone++)->name,primitive->name);//此次赋值操作后,newone指向申请的连续空间的下一个地址 
				}
				current=current->next;
			}
		}
		primitive=primitive->next;
	}
	previous=newone=initial;//回到首地址 
	for(i=1;i<num;++i)//直接插入法排序 
	{
		a=previous[i];
		j=i-1;
		while(j>=0&&previous[j].score<a.score)
		{
			previous[j+1]=previous[j];
			--j;
		}
		previous[j+1]=a;
	}
	for(i=0;i<num;++i)
	printf("%d--%s--%s:%.2f\n",i+1,previous[i].number,previous[i].name,previous[i].score);
	printf("成绩输出成功!\n");
} 

展示所有学生信息:

void shower(Students origin)
{
	Students current=origin;
	Curriculums now;
	printf("班级\t    名称\t学号\t性别课程-学期-成绩\n");
	while(current)//学生信息节点存在时 
	{
		now=current->curriculum;//当前学生信息节点中的第一个课程节点 
		printf("%s---%s---%s---%s-%s-%s-%.2f\t",current->banji,current->name,current->number,current->gender,now->curriculum,now->semester,now->score);
		while(now=now->next)//第二个以及以后的课程节点存在时 
		printf("%s-%s-%.2f\t",now->curriculum,now->semester,now->score);
		printf("\n");//每个同学信息输出完毕时换行 
		current=current->next;//下一个学生信息节点 
	}
	printf("数据输出成功!\n");
}

展示某个同学信息:

void showerone(Students origin)
{
	Students current=origin;
	Curriculums now;
	printf("班级\t    名称\t学号\t性别课程-学期-成绩\n");
	now=current->curriculum;//当前学生信息中第一个课程信息节点 
	printf("%s---%s---%s---%s-%s-%s-%.2f\t",current->banji,current->name,current->number,current->gender,now->curriculum,now->semester,now->score);
	while(now=now->next)//第二个以及以后的课程信息存在时 
	printf("%s-%s-%.2f\t",now->curriculum,now->semester,now->score);
	printf("\n");
}

管理员添加学生信息:

void anew(Students* origin)
{
	Students now=(Students)malloc(sizeof(students)),forever=*origin;
    if(!now){printf("申请学生节点失败!\n");exit(1);}
    char banji[10],name[10],number[15],gender;
    Curriculums previous,curriculum;
	int i=1;
    while(i)//判断新增加学号是否符合唯一性规则 
	{
    	printf("请输入学号:");
    	while(fflush(stdin),scanf("%s",now->number)!=1) printf("请输入有效信息:");
   		while(forever)
		{
    		if(!strcmp(now->number,forever->number))
			{
    			printf("学号应具有唯一性!\n");
    			break;
			}
			else if(!(forever->next)) i=0;
    		forever=forever->next;
		}
	}
    printf("请输入姓名:");
    while(fflush(stdin),scanf("%s",now->name)!=1) printf("请输入有效信息:");
    printf("请输入性别(f/m/F/M):");
    while(((gender=getche())!='f')&&(gender!='M')&&(gender!='m')&&(gender!='F')){printf("\n请输入有效选项(f/F/m/M):");continue;}
    printf("\n你输入的是%c\n",gender);
	(gender=='f'||gender=='F')?strcpy(now->gender,"女"):strcpy(now->gender,"男");
    printf("请输入班级:");
    while(fflush(stdin),scanf("%s",now->banji)!=1) printf("请输入有效信息:");
    now->next=(*origin)->next;//将学生信息利用头插法添加到双向链表中 
    now->pre=(*origin);
    (*origin)->next=now;
    printf("请输入学生课程信息(高数 大一 66.6):");
    if(!(curriculum=now->curriculum=(Curriculums)malloc(sizeof(curriculums))))
    {printf("请求课程信息失败!\n");exit(1);}
	curriculum->next=curriculum->pre=NULL;//置空课程信息 
	fflush(stdin);//清空输入缓冲区 
	scanf("%s%s%f",curriculum->curriculum,curriculum->semester,&curriculum->score);
	previous=curriculum;
	if(!(curriculum=(Curriculums)malloc(sizeof(curriculums))))
	{printf("请求课程信息失败!\n");exit(1);}
	printf("请输入下一门课程信息(分数<=0结束):");
	while(1)//不断添加课程信息 
	{
    	while(fflush(stdin),(scanf("%s%s%f",curriculum->curriculum,curriculum->semester,&curriculum->score)==3))
		{
    		if(curriculum->score<=0)
			{
				free(curriculum);//释放此节点并等待返回 
				return;
			}
    		curriculum->next=previous->next;//满足课程节点基本信息则头插法添加课程双向链表 
    		curriculum->pre=previous;
    		previous->next=curriculum;
    		if(!(curriculum=(Curriculums)malloc(sizeof(curriculums)))){
			printf("请求课程信息失败!\n");exit(1);}
			printf("请输入下一门课程信息(分数<=0结束):");
		}
	}printf("学生%s信息添加成功!\n",now->name);
}

是否确认修改:

int Deliberation(){
	printf("您确定修改此信息吗(y/Y/n/N)?");
	char ch;
    while(((ch=getche())!='y')&&(ch!='Y')&&(ch!='n')&&(ch!='N'))
	{printf("\n请输入有效选项(y/Y/n/N):");continue;}//输入的非需要的字符,自动等待重新输入 
    printf("\n你输入的是%c\n",ch);
    if(ch=='y'||ch=='Y') printf("此数据修改成功!\n");
    else printf("抱歉,数据修改失败!\n");
    return((ch=='y'||ch=='Y')?1:0);//确认返回值为真,否则为假 
}

改变学生信息:

void changeable(Students* origin)
{
    char banji[10],name[10];
    int todo;
    while(1)//不断循环 
	{
    	printf("请输入您想要修改的序号:\n1.姓名\t2.班级\t3.成绩信息\t4.返回:");
    	while(fflush(stdin),scanf("%d",&todo)!=1||todo<1||todo>4) printf("请输入有效选项(1-4):");//先清空输入缓冲区再读取数据 
    	switch(todo)
		{
    		case 1:printf("请输入修改后的姓名:");
    		while(fflush(stdin),scanf("%s",name)!=1) printf("请输入有效信息:");
			if(Deliberation()) strcpy((*origin)->name,name);break;
    		case 2:printf("请输入修改后的班级:");
    		while(fflush(stdin),scanf("%s",banji)!=1) printf("请输入有效信息:");
			if(Deliberation()) strcpy((*origin)->banji,banji);break;
    		case 3:CurriculumChange(&(*origin)->curriculum);break;//调用课程信息更改函数 
    		case 4:return;//返回上一级 
    		default:;
    	}
    }
}

课程信息更改:

void CurriculumChange(Curriculums*origin)
{
	Curriculums now,newone;
	int todo,surrounding;
	while(1)
	{
		printf("请输入您想要进行的操作:1.添加课程\t2.更改课程\t3.返回:");
		while(fflush(stdin),scanf("%d",&todo)!=1||todo<1||todo>3) printf("请输入有效选项(1-3):");
		if(!(newone=(Curriculums)malloc(sizeof(curriculums))))
			{printf("申请课程信息节点失败!\n");exit(1);}
			surrounding=1;
		switch(todo)
		{
			case 1:printf("请输入新添加的课程信息(高数 大一 79.5)分数<=0退出:");
				   now=*origin;
					while(fflush(stdin),scanf("%s%s%f",newone->curriculum,newone->semester,&newone->score)==3)//先清空输入缓冲区再输入数据
					{
						if(newone->score<=0)
						{
							printf("课程成绩%.2f不符合要求,添加失败!\n",newone->score);
							free(newone);//成绩有误,释放数据等待返回 
							break;//结束当前循环 
						}
						while(now)
						{
							if(!strcmp(now->curriculum,newone->curriculum)&&!strcmp(now->semester,newone->semester)&&now->score==newone->score)
							{
								printf("此同学%s时期%s课程分数%.2f添加前存在,添加失败!\n",now->semester,now->curriculum,now->score);
								free(newone);//已存在输入数据,删除新添加的节点即可 
								surrounding=0;
								break;//返回上一级 
							}
							else if(!strcmp(now->curriculum,newone->curriculum)&&!strcmp(now->semester,newone->semester))
							{
								now->score=newone->score;//补充成绩即可 
								free(newone);//删除新添加项目即可
								surrounding=0;
								break;//返回上一级 
							}
							now=now->next;
						}
						if(surrounding)
						{
							newone->next=(*origin)->next;
							newone->pre=(*origin);
							(*origin)->next=newone;
							printf("%s-%s-%.2f添加成功!\n",newone->curriculum,newone->semester,newone->score);
						}
						if(!(newone=(Curriculums)malloc(sizeof(curriculums))))
						{printf("申请课程信息节点失败!\n");exit(1);}
						printf("请输入新添加的课程信息(高数 大一 79.5)分数<=0退出:");
					}
					break;
			case 2:printf("请输入更改后的课程信息(高数 大一 79.5):");
					now=*origin;
					while(fflush(stdin),scanf("%s%s%f",newone->curriculum,newone->semester,&newone->score)==3)
					{
						if(newone->score<=0)
						{
							free(newone);//成绩有误,释放数据等待返回 
							printf("更改后的课程信息不符合要求,更改失败!\n");
							break;//结束当前循环 
						}
						while(now)
						{
							if(!strcmp(now->curriculum,newone->curriculum)&&!strcmp(now->semester,newone->semester)&&now->score==newone->score)
							{
								printf("此同学%s时期%s课程分数%.2f已存在!\n",now->semester,now->curriculum,now->score);
								free(newone);//已存在输入数据,删除新添加的节点即可 
								surrounding=0;
								break;//返回上一级 
							}
							else if(!strcmp(now->curriculum,newone->curriculum)&&!strcmp(now->semester,newone->semester))
							{
								now->score=newone->score;//补充成绩即可 
								printf("更改成功!\n");
								free(newone);//删除新添加项目即可 
								surrounding=0;
								break;//返回上一级 
							}
							else if(!strcmp(now->curriculum,newone->curriculum))
							{
								strcpy(now->semester,newone->semester);
								now->score==newone->score;
								printf("此同学%s时期%s课程分数%.2f更改成功!\n",now->semester,now->curriculum,now->score);
								surrounding=0;
								break;
							}
							now=now->next;
						}
						if(surrounding) printf("无相应的课程和时期,更改失败!\n");//无相应的课程以及学期 
						break;
					}
					break; 
			case 3:return;
			default:;
		}
	}
}

源码:

#include<stdio.h>
#include<conio.h>//调用函数getche() 
#include<stdlib.h>//调用函数malloc()和free() 
#include<string.h>//调用函数strcpy()和strcmp() 
#define Fault -100//由于第一个学生节点存储有学生信息,因此删除第一个学生节点信息时应完全改变其节点信息,用Fault来主要表示第一个学生节点存在与否  
#define Attemptingpassword 3//登录信息最多尝试次数 
#define Infileaccount "account.txt"//管理员以及学生登录时的账号读取文件 
#define Infilestu "Importing.txt"//输入输出学生信息文件 
#define Outfilestu "Importing.txt"
typedef struct curriculums
{
    char curriculum[20],semester[20];//课程以及相应的学期 
    float score;//课程分数 
    struct curriculums *next,*pre;//课程节点为双向链表 
}curriculums,*Curriculums;
typedef struct students
{
    char banji[10],name[10],number[15],gender[3];//学生基本信息:班级、名称、学号(唯一)以及性别 
    Curriculums curriculum;//课程指针 
    struct students *next,*pre;//学生节点为双向链表 
}students,*Students;
typedef struct loggers
{
    int users;//enum users{adm,nor}users;//区别管理员0与普通用户 1 
    char account[15],password[15];//账号以及密码 
    struct loggers *next;//账户链表为单向链表 
}loggers,*Loggers;
typedef struct one
{
	char name[10],number[15];
	float score;
}ones,*Ones;//班级课程排名辅助 
void initaccount(Loggers*); //初始化账号、密码和状态的链表 
void tablelog(Loggers,Students);//用户登录界面,鉴定有效次数以内用户是否登陆成功 
Students searchnumber(Students);//根据唯一学号寻找学生,并返回相应的节点 
Students searchname(Students,char*,int);//根据名称寻找学生,并用递归记载找到名称个数,达到输出重名学生的目的 
Students stuinfoget();//初始化并返回学生信息的双向链表第一个节点 
void impartstuinfo(Students);//管理员身份登陆退出后自动保存修改后的学生信息 
void DeleteTable(Students*);//管理员操作界面 
void deletesthroughnumber(Students*);//通过学号删除学生 
void freeall(Students*,Loggers*);//释放学生信息和账户登录信息两种双向链表 
void searchclasscurriculumrank(Students);//寻找某班某课程的排名情况 
void shower(Students);//展示所有学生信息 
void showerone(Students);//展示某一个存在的学生信息
void anew(Students*);//管理员新添加学生信息 
int Deliberation();//是否确认修改 
void changeable(Students*);//改变学生信息 
void CurriculumChange(Curriculums*);//更换课程信息 
float TemporaryScore;//用于班级课程排名 
int main()
{
    Loggers logger1=(Loggers)malloc(sizeof(loggers));
    if(!logger1){
    printf("申请登录信息以及学生信息失败!\n");exit(1);}
    tablelog(logger1,stuinfoget());
    return 0;
}
void CurriculumChange(Curriculums*origin)
{
	Curriculums now,newone;
	int todo,surrounding;
	while(1)
	{
		printf("请输入您想要进行的操作:1.添加课程\t2.更改课程\t3.返回:");
		while(fflush(stdin),scanf("%d",&todo)!=1||todo<1||todo>3) printf("请输入有效选项(1-3):");
		if(!(newone=(Curriculums)malloc(sizeof(curriculums))))
			{printf("申请课程信息节点失败!\n");exit(1);}
			surrounding=1;
		switch(todo)
		{
			case 1:printf("请输入新添加的课程信息(高数 大一 79.5)分数<=0退出:");
				   now=*origin;
					while(fflush(stdin),scanf("%s%s%f",newone->curriculum,newone->semester,&newone->score)==3)
					{
						if(newone->score<=0)
						{
							printf("课程成绩%.2f不符合要求,添加失败!\n",newone->score);
							free(newone);
							break;
						}
						while(now)
						{
							if(!strcmp(now->curriculum,newone->curriculum)&&!strcmp(now->semester,newone->semester)&&now->score==newone->score)
							{
								printf("此同学%s时期%s课程分数%.2f添加前存在,添加失败!\n",now->semester,now->curriculum,now->score);
								free(newone);
								surrounding=0;
								break;
							}
							else if(!strcmp(now->curriculum,newone->curriculum)&&!strcmp(now->semester,newone->semester))
							{
								now->score=newone->score;
								free(newone);
								surrounding=0;
								break;
							}
							now=now->next;
						}
						if(surrounding)
						{
							newone->next=(*origin)->next;
							newone->pre=(*origin);
							(*origin)->next=newone;
							printf("%s-%s-%.2f添加成功!\n",newone->curriculum,newone->semester,newone->score);
						}
						if(!(newone=(Curriculums)malloc(sizeof(curriculums))))
						{printf("申请课程信息节点失败!\n");exit(1);}
						printf("请输入新添加的课程信息(高数 大一 79.5)分数<=0退出:");
					}
					break;
			case 2:printf("请输入更改后的课程信息(高数 大一 79.5):");
					now=*origin;
					while(fflush(stdin),scanf("%s%s%f",newone->curriculum,newone->semester,&newone->score)==3)
					{
						if(newone->score<=0)
						{
							free(newone);
							printf("更改后的课程信息不符合要求,更改失败!\n");
							break;
						}
						while(now)
						{
							if(!strcmp(now->curriculum,newone->curriculum)&&!strcmp(now->semester,newone->semester)&&now->score==newone->score)
							{
								printf("此同学%s时期%s课程分数%.2f已存在!\n",now->semester,now->curriculum,now->score);
								free(newone);
								surrounding=0;
								break;
							}
							else if(!strcmp(now->curriculum,newone->curriculum)&&!strcmp(now->semester,newone->semester))
							{
								now->score=newone->score;
								printf("更改成功!\n");
								free(newone);
								surrounding=0;
								break;
							}
							else if(!strcmp(now->curriculum,newone->curriculum))
							{
								strcpy(now->semester,newone->semester);
								now->score==newone->score;
								printf("此同学%s时期%s课程分数%.2f更改成功!\n",now->semester,now->curriculum,now->score);
								surrounding=0;
								break;
							}
							now=now->next;
						}
						if(surrounding) printf("无相应的课程和时期,更改失败!\n");
						break;
					}
					break; 
			case 3:return;
			default:;
		}
	}
}
int Deliberation(){
	printf("您确定修改此信息吗(y/Y/n/N)?");
	char ch;
    while(((ch=getche())!='y')&&(ch!='Y')&&(ch!='n')&&(ch!='N'))
	{printf("\n请输入有效选项(y/Y/n/N):");continue;}
    printf("\n你输入的是%c\n",ch);
    if(ch=='y'||ch=='Y') printf("此数据修改成功!\n");
    else printf("抱歉,数据修改失败!\n");
    return((ch=='y'||ch=='Y')?1:0);
}
void changeable(Students* origin)
{
    char banji[10],name[10];
    int todo;
    while(1)
	{
    	printf("请输入您想要修改的序号:\n1.姓名\t2.班级\t3.成绩信息\t4.返回:");
    	while(fflush(stdin),scanf("%d",&todo)!=1||todo<1||todo>4) printf("请输入有效选项(1-4):");
    	switch(todo)
		{
    		case 1:printf("请输入修改后的姓名:");
    		while(fflush(stdin),scanf("%s",name)!=1) printf("请输入有效信息:");
			if(Deliberation()) strcpy((*origin)->name,name);break;
    		case 2:printf("请输入修改后的班级:");
    		while(fflush(stdin),scanf("%s",banji)!=1) printf("请输入有效信息:");
			if(Deliberation()) strcpy((*origin)->banji,banji);break;
    		case 3:CurriculumChange(&(*origin)->curriculum);break; 
    		case 4:return;
    		default:;
    	}
    }
}
void anew(Students* origin)
{
	Students now=(Students)malloc(sizeof(students)),forever=*origin;
    if(!now){printf("申请学生节点失败!\n");exit(1);}
    char banji[10],name[10],number[15],gender;
    Curriculums previous,curriculum;
	int i=1;
    while(i)
	{
    	printf("请输入学号:");
    	while(fflush(stdin),scanf("%s",now->number)!=1) printf("请输入有效信息:");
   		while(forever)
		{
    		if(!strcmp(now->number,forever->number))
			{
    			printf("学号应具有唯一性!\n");
    			break;
			}
			else if(!(forever->next)) i=0;
    		forever=forever->next;
		}
	}
    printf("请输入姓名:");
    while(fflush(stdin),scanf("%s",now->name)!=1) printf("请输入有效信息:");
    printf("请输入性别(f/m/F/M):");
    while(((gender=getche())!='f')&&(gender!='M')&&(gender!='m')&&(gender!='F')){printf("\n请输入有效选项(f/F/m/M):");continue;}
    printf("\n你输入的是%c\n",gender);
	(gender=='f'||gender=='F')?strcpy(now->gender,"女"):strcpy(now->gender,"男");
    printf("请输入班级:");
    while(fflush(stdin),scanf("%s",now->banji)!=1) printf("请输入有效信息:");
    now->next=(*origin)->next;
    now->pre=(*origin);
    (*origin)->next=now;
    printf("请输入学生课程信息(高数 大一 66.6):");
    if(!(curriculum=now->curriculum=(Curriculums)malloc(sizeof(curriculums))))
    {printf("请求课程信息失败!\n");exit(1);}
	curriculum->next=curriculum->pre=NULL;
	fflush(stdin); 
	scanf("%s%s%f",curriculum->curriculum,curriculum->semester,&curriculum->score);
	previous=curriculum;
	if(!(curriculum=(Curriculums)malloc(sizeof(curriculums))))
	{printf("请求课程信息失败!\n");exit(1);}
	printf("请输入下一门课程信息(分数<=0结束):");
	while(1)
	{
    	while(fflush(stdin),(scanf("%s%s%f",curriculum->curriculum,curriculum->semester,&curriculum->score)==3))
		{
    		if(curriculum->score<=0)
			{
				free(curriculum);
				return;
			}
    		curriculum->next=previous->next;
    		curriculum->pre=previous;
    		previous->next=curriculum;
    		if(!(curriculum=(Curriculums)malloc(sizeof(curriculums)))){
			printf("请求课程信息失败!\n");exit(1);}
			printf("请输入下一门课程信息(分数<=0结束):");
		}
	}printf("学生%s信息添加成功!\n",now->name);
}
void shower(Students origin)
{
	Students current=origin;
	Curriculums now;
	printf("班级\t    名称\t学号\t性别课程-学期-成绩\n");
	while(current)
	{
		now=current->curriculum; 
		printf("%s---%s---%s---%s-%s-%s-%.2f\t",current->banji,current->name,current->number,current->gender,now->curriculum,now->semester,now->score);
		while(now=now->next)
		printf("%s-%s-%.2f\t",now->curriculum,now->semester,now->score);
		printf("\n");
		current=current->next;
	}
	printf("数据输出成功!\n");
}
void showerone(Students origin)
{
	Students current=origin;
	Curriculums now;
	printf("班级\t    名称\t学号\t性别课程-学期-成绩\n");
	now=current->curriculum;
	printf("%s---%s---%s---%s-%s-%s-%.2f\t",current->banji,current->name,current->number,current->gender,now->curriculum,now->semester,now->score);
	while(now=now->next)
	printf("%s-%s-%.2f\t",now->curriculum,now->semester,now->score);
	printf("\n");
}
void searchclasscurriculumrank(Students origin){
	char banji[10],curriculum[20];
	int i=0,j,k,num;
	Students now=origin,primitive=origin;
	Curriculums current;
	ones a;
	Ones newone,previous=NULL,initial=NULL;
	printf("请输入班级和课程(计算机217 高数):");
	while(fflush(stdin),scanf("%s%s",banji,curriculum)!=2) printf("请输入有效信息:");
	while(now)
	{
		if(!strcmp(now->banji,banji))
		{
			current=now->curriculum;
			while(current)
			{
				if(!strcmp(current->curriculum,curriculum)) 
				{
					++i;break;
				}
				current=current->next;
			}
		}
		now=now->next;
	}
	if(!i)
	{
		printf("无此课程或班级!\n");
		return;
	}
	if(!(initial=newone=(Ones)malloc(sizeof(ones)*(num=i))))
	{printf("申请信息失败!\n");exit(1);} 
	while(primitive)
	{
		if(!strcmp(primitive->banji,banji))
		{
			current=primitive->curriculum;
			while(current)
			{
				if(!(strcmp(current->curriculum,curriculum)))
				{
					newone->score=current->score;
					strcpy(newone->number,primitive->number);
					strcpy((newone++)->name,primitive->name);
				}
				current=current->next;
			}
		}
		primitive=primitive->next;
	}
	previous=newone=initial;
	for(i=1;i<num;++i)
	{
		a=previous[i];
		j=i-1;
		while(j>=0&&previous[j].score<a.score)
		{
			previous[j+1]=previous[j];
			--j;
		}
		previous[j+1]=a;
	}
	for(i=0;i<num;++i)
	printf("%d--%s--%s:%.2f\n",i+1,previous[i].number,previous[i].name,previous[i].score);
	printf("成绩输出成功!\n");
} 
void freeall(Students* origin,Loggers* key)
{
	if(*origin)
	{
		Students current=*origin,previous;
		Curriculums now,pre;
		while(current)
		{
			now=current->curriculum; 
			while(now)
			{
				pre=now;
				now=now->next;
				free(pre);
			}
			previous=current;
			current=current->next;
			free(previous);
		}
	}
	Loggers p=*key,q;
	while(q=p,p=p->next)
		free(q);
	free(q);
	printf("数据释放成功!\n");
}
void deletesthroughnumber(Students* origin)
{
	if(!*origin) exit(1);
	if(!(*origin)->next&&!(*origin)->pre) exit(1);
	else if(!(*origin)->next) 
		(*origin)->pre->next=NULL;
	else if(!(*origin)->pre)
	{
		Curriculums previous,current=(*origin)->curriculum;
		strcpy((*origin)->banji,"");
		strcpy((*origin)->name,"");
		strcpy((*origin)->number,"");
		strcpy((*origin)->gender,"");
		strcpy(current->semester,"");
		strcpy(current->curriculum,"");
		current->score=Fault;
		while(current=current->next)
		{
			previous=current;
			current=current->next;
			free(previous);
		}
		(*origin)->curriculum->next=NULL;
		printf("删除成功!\n");
		return;
	}
	else
	{
   		(*origin)->pre->next=(*origin)->next;
    	(*origin)->next->pre=(*origin)->pre;
	}
	free(*origin);
    printf("删除成功!\n");
}
void impartstuinfo(Students q)
{
    FILE *fp=fopen(Outfilestu,"w");
    if(!fp){printf("写入文件%s打开失败!\n",Outfilestu);exit(1);}
    Students current=q;Curriculums now;
    while(current)
	{
    	if(strcmp(current->name,""))
		{
    		now=current->curriculum;
        	fprintf(fp,"#%s %s %s %s %s %s %.2f",current->banji,current->name,current->number,current->gender,now->curriculum,now->semester,now->score); 
        	while(now=now->next)
			fprintf(fp,"$ %s %s %.2f",now->curriculum,now->semester,now->score);
			fputc('\n',fp);
		}
        current=current->next;
    }
    	fclose(fp);
        printf("学生信息写入文件%s成功!\n",Outfilestu);
}
Students stuinfoget()
{
    FILE *fp=fopen(Infilestu,"r");
    if(!fp){printf("文件%s打开失败,学生信息读取失败!\n",Infilestu);exit(1);}
    Students current,previous=NULL,origin;
    Curriculums now,pre=NULL;
    char c=' ';
    while(!feof(fp))
	{
    	while(((c=='#')||((c=fgetc(fp))=='#'))&&c!=EOF)
		{
    		if(!(current=(Students)malloc(sizeof(students)))){printf("内存不足,申请学生信息失败!\n");exit(1);} 
			if(fscanf(fp,"%s%s%s%s",current->banji,current->name,current->number,current->gender)==4)
			{
      	  		current->next=current->pre=NULL;
      	  		if(!previous) origin=current; 
      	  		if(!(now=current->curriculum=malloc(sizeof(curriculums)))){
				printf("内存不足,申请学生%s课程信息失败!\n",current->name);exit(2);}
				if(fscanf(fp,"%s%s%f",now->curriculum,now->semester,&now->score)==3)
					now->next=now->pre=NULL;
				pre=now;
             	while((c=fgetc(fp))=='$') 
				{
             		if(!(now=malloc(sizeof(curriculums)))){
					printf("内存不足,申请学生%s课程信息失败!\n",current->name);exit(3);} 
                	if(fscanf(fp,"%s%s%f",now->curriculum,now->semester,&now->score)==3) 
                	{
						now->next=pre->next;
						now->pre=pre;
						pre->next=now;
					} 
					pre=now; 
				}
        	}
        	if(previous) 
			{
        		current->next=previous->next;
        		current->pre=previous;
        		previous->next=current;
			}
        	previous=current;
		}
	}
	fclose(fp);
    printf("学生信息读取成功!\n");
    return origin;
}
void DeleteTable(Students* origin)
{
    Students now;
	int todo;
    char number[15],name[10];
    while(1)
	{
    	printf("请输入您想要进行的操作:1.按学号删除学生\t2.按名称查询学生\t3.按学号查询学生\t4.添加学生信息\t5.按学号修改学生信息\t6.退出(1/2/3/4/5/6):");
    	while(fflush(stdin),scanf("%d",&todo)!=1||todo<1||todo>6) printf("请输入有效选项(1-6):");
    	switch(todo)
		{
        	case 1:if(!(now=searchnumber(*origin))) break;
               	deletesthroughnumber(&now);break;
        	case 2:printf("请输入待查找的名称(重庆):");
        	   	while(fflush(stdin),scanf("%s",name)!=1) ;
			   	searchname(*origin,name,0);break;
        	case 3:searchnumber(*origin);break;
        	case 4:anew(origin);break;
			case 5:if(!(now=searchnumber(*origin))) break;
				changeable(&now);break;
        	case 6:return;
        	default:;
        }
    }
}
Students searchnumber(Students pre)
{
    printf("请输入您想要查询的学生学号(12345678901):");
    char number[15];
	Students now=pre;
    while(fflush(stdin),scanf("%s",number)!=1) printf("请输入正确学号(12345678901):");
    while(now)
	{
    	if(!strcmp(now->number,number))
		{
        	showerone(now); 
        	return now; 
        }
    	else if(!(now->next))
		{
			printf("无学号为%s的学生!\n",number);
        	return NULL;
		}
        now=now->next;
	}
}
Students searchname(Students pre,char*name,int num)
{
    int number=num;
	Students now=pre;
    while(now)
	{
    	if(!strcmp(now->name,name))
		{
        	showerone(now);
        	searchname(now->next,name,++number);
        	return now;
        }
        else if(!(now->next)&&!number)
		{
			printf("无名称为%s的学生!\n",name);
        	return NULL;
    	}
    	now=now->next;
	}
}
void norsearch(Students q)
{
    int todo;
    char name[10];
    while(1)
	{
    	printf("请输入您想要进行的操作:1.按名称查找学生\t2.按学号查找学生\t3.查询某班级某门课程排名\t4.退出:");
    	while(fflush(stdin),scanf("%d",&todo)!=1||todo<1||todo>4) printf("请输入合理选项(1/2/3/4):");
    	switch(todo)
		{
        	case 1:printf("请输入待查找的名称:");
        	   	   while(fflush(stdin),scanf("%s",name)!=1) printf("请输入正确数据:");
			   	   searchname(q,name,0);
				   break;
        	case 2:searchnumber(q);break;
        	case 3:searchclasscurriculumrank(q);break;
			case 4:return;
        	default:;
    	}
    }
}
void initaccountes(Loggers* q){
    FILE *fp=fopen(Infileaccount,"r");
    if(!fp){printf("用户登陆信息文件打开失败!\n");exit(2);}
    (*q)->next=NULL;
    Loggers current=(Loggers)malloc(sizeof(loggers));
    if(!current){printf("初始化账户内存不够!\n");exit(3);}
    printf("登录账号\t密码   身份\n");
    while(fscanf(fp,"%s%s%d",current->account,current->password,&current->users)==3)
		{
    		printf("%s\t%s\t%d\n",current->account,current->password,current->users);
        	current->next=(*q)->next;
        	(*q)->next=current;
       	 	if(!(current=(Loggers)malloc(sizeof(loggers)))){
			printf("初始化账户内存不够!\n");exit(3);}
        }
    printf("用户登陆信息显示成功!\n用户登陆信息文件%s内容读取成功!\n",Infileaccount);
    fclose(fp);//关闭文件 
}
void tablelog(Loggers q,Students qq){
 	initaccountes(&q);
	shower(qq);
 	printf(" _____________________________________\n");
 	printf("|        欢迎来到学生管理系统         |\n");
 	printf("|_____________________________________|\n");
 	char account1[15],password1[15];
 	Loggers p,r;
 	int opportunity=Attemptingpassword,user,key=1;
 	while(key)
	{
  		printf("请依次正确输入您的账号,密码和用户类型(123456 abcdef 1普通用户/0管理员):");
  		while(fflush(stdin),scanf("%s%s%d",account1,password1,&user)!=3||user<0||user>1) printf("请输入正确数据格式以及状态(0/1):");
  		p=r=q;
 		while(p=p->next)
   		if(!strcmp(account1,p->account)&&!(strcmp(password1,p->password)))
    		if(user)
			{
				printf("普通用户账号登陆成功!\n");
				key=0; 
				norsearch(qq);
				freeall(&qq,&q);
				break;
			}
    		else
			{
				printf("管理员账号登陆成功!\n");
				key=0;
				DeleteTable(&qq);//进入管理员操作页面 
				impartstuinfo(qq);//保存管理员操作后的信息 
				freeall(&qq,&q);
				break;
			}
  		if(!p)
	  	{
   			r=q;
   			if(--opportunity)
			   {
   			 		while(r=r->next)
					{
     				if(!strcmp(account1,r->account))
				 		{
      					printf("密码错误!您还有%d次有效机会!\n",opportunity);break;
						}
      				else if(!strcmp(password1,r->password))
				  		{
      					printf("账号错误!您还有%d次有效机会!\n",opportunity);break;
						}
					}
    				if(!r)
					printf("账号密码错误!您还有%d次有效机会!\n", opportunity);
				}
   			else
			   {
			   printf("很抱歉,机会已耗尽,您的账户已被锁定,请稍后尝试\n",opportunity);
			   freeall(&qq,&q);
			   exit(1);
			   }
  		}
	}
}

  • 9
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值