#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//添加一个学生的信息(在链表尾部)
void AddStuMSG(char arrNum[10], char arrStuName[10], int iStuScore); //这里函数传递的参数之间用逗号隔开
//清空链表
void FreeLinkData();
//在链表头前面添加学生节点
void AddStuMSGToLinkHead(char arrNum[10], char arrStuName[10], int iStuScore);
//打印数据
void ShowStuData();
//显示指令
void ShowOrder(){
printf("**********************************\n");
printf(" ****学生管理系统****\n");
printf("1:增加一个学生信息(尾添加)\n");
printf("11:增加一个学生信息(头添加)\n");
printf("111:增加一个学生信息(指定位置添加)\n");
printf("2:查找指定学生的信息(姓名/学号)\n");
printf("3:修改指定学生的信息\n");
printf("4:保存业主的信息到文件中\n");
printf("5:读取文件中的业主信息\n");
printf("6:删除指定学生的信息\n");
printf("7:恢复删除的学生的信息\n");
printf("9:显示所有学生的信息\n");
printf("0:退出系统\n");
printf("**********************************\n");
}
//创建学生节点
typedef struct _STU{
char arrNum[10];//学号
char arrStuName[10];//姓名
int iStuScore;//分数
struct _STU *pNext;
}STUNODE;
//查找指定学生(在上一个学生的后面添加,返回上一学生的地址,参数是上一学生的学号)
STUNODE* FindStuBuNum(char*arrNum);
//指定位置插入节点
void InsertNode(STUNODE*pTemp,char arrNum[10], char arrStuName[10], int iStuScore);
//void InsertNode(stu)
//删除指定学生
void DeleteStuByNode(STUNODE*pNode);
//保存信息进文件
void SaveStuToFile();
//读取文件中的学生信息
void ReadStuFromFile();
//声明链表的头和尾,也就是定义指针,分别装着第一和最后节点的地址
STUNODE* g_pHead = NULL;//全局变量前面加个g
STUNODE* g_pEnd = NULL;
int main (void){
int iOrder = -1;//定义命令
char arrNum[10] = {0};//学号
char arrStuName[10] = {0};//姓名
int iStuScore = -1;//分数
int nFlag = 1;
void ReadStuFromFile();//系统一启动,就要读取上次的信息
printf("**********************************\n");
printf(" ****学生管理系统****\n");
printf("1:增加一个学生信息(尾添加)\n");
printf("11:增加一个学生信息(头添加)\n");
printf("111:增加一个学生信息(在指定位置添加)\n");
printf("2:查找指定学生的信息(姓名/学号)\n");
printf("3:修改指定学生的信息\n");
printf("4:保存学生的信息到文件中\n");
printf("5:读取文件中的学生信息\n");
printf("6:删除指定学生的信息\n");
printf("7:恢复删除的学生的信息\n");
printf("9:打印所有学生信息\n");
printf("0:退出系统\n");
printf("**********************************\n");
while(nFlag){
printf("请输入指令:(10:查看指令) ");
scanf("%d",&iOrder);//输入命令
switch(iOrder) {
case 1://尾添加
//TODO:添加一个学生的信息
printf("输入学号:");
scanf("%s",arrNum);
printf("输入姓名:");
scanf("%s",arrStuName);
printf("输入分数:");
scanf("%d",&iStuScore);//这里别忘了加取地址符号
AddStuMSG(arrNum,arrStuName,iStuScore); //调用添加信息函数
break;
case 11://头添加
//TODO:添加一个学生的信息
printf("输入学号:");
scanf("%s",arrNum);
printf("输入姓名:");
scanf("%s",arrStuName);
printf("输入分数:");
scanf("%d",&iStuScore);//这里别忘了加取地址符号
AddStuMSGToLinkHead(arrNum,arrStuName,iStuScore);
break;
case 111://在指定位置添加
{STUNODE*pTemp = NULL ;//在case里面声明变量的时候要用{}把声明语句括起来否则报错!!!!!!!!
//查找指定学生
printf("输入指定位置的学号:");
scanf("%s",arrNum);
pTemp = FindStuBuNum(arrNum);
//FindStuBuNum(arrNum);因为下面有NULL!=函数的判断,如果这里再引用一次的话就相当于引用了两次
if(NULL != pTemp){
//TODO,插入
printf("输入学号:");
scanf("%s",arrNum);
printf("输入姓名:");
scanf("%s",arrStuName);
printf("输入分数:");
scanf("%d",&iStuScore);//这里别忘了加取地址符号
InsertNode(pTemp,arrNum,arrStuName,iStuScore);
}
}
break;
case 2://查找并显示指定学生的信息
{//输入一个学号
printf("输入学号:");
scanf("%s",arrNum);
// 查找
STUNODE*pTemp = FindStuBuNum(arrNum);
//打印
if(NULL != pTemp){
printf("学号:%s,姓名:%s,分数:%d\n",pTemp->arrNum,pTemp->arrStuName,pTemp->iStuScore);
}
}
break;
case 3://修改指定学生的信息
{
printf("输入指定学生的学号:");
scanf("%s",arrNum);
// 查找
STUNODE*pTemp = FindStuBuNum(arrNum);
if(NULL != pTemp){
printf("a:修改学号,b:修改名字,c:修改分数");
getchar();//拿掉回车
char Change = 0;
scanf("%c",&Change);
if(Change == 'a'){
printf("请输入修改后的学号:");
getchar();//拿掉回车
//修改学号
scanf("%s",arrNum);
strcpy(pTemp->arrNum,arrNum);
}
if(Change == 'b'){
printf("请输入修改后的名字:");
getchar();//拿掉回车
//修改名字
scanf("%s",arrStuName);
strcpy(pTemp->arrStuName,arrStuName);
}
if(Change == 'c'){
printf("请输入修改后的分数:");
getchar();//拿掉回车
//修改分数
scanf("%d",&iStuScore);
pTemp->iStuScore = iStuScore;
}
}
}
break;
case 4://保存学生的信息
SaveStuToFile();
printf("保存成功\n");
break;
case 5:
ReadStuFromFile();
break;
case 6:{
printf("输入要删除的学生的学号:");
scanf("%s",arrNum);
// 查找
STUNODE*pTemp = FindStuBuNum(arrNum);
//删除这个节点
if(NULL != pTemp){
//调用删除学生的函数
DeleteStuByNode(pTemp);
printf("删除成功!");
}
}
break;
case 7:
//恢复,释放
FreeLinkData();
//g_pHead = NULL;
//g_pEnd = NULL;
//回复,添加节点
ReadStuFromFile();
break;
case 9:
ShowStuData();//调用打印函数
break;
case 0:
nFlag = 0;//这个是之前没有接触过的
break;
case 10:
//查看指令
ShowOrder();
break;
default:
printf("输入的指令不对\n");
}
}
//保存
SaveStuToFile();
//释放链表
FreeLinkData();
system("pause");
return 0;
}
//DO:添加一个学生的信息(这里我又忘了把函数弄在主函数之外)
void AddStuMSG(char arrNum[10], char arrStuName[10], int iStuScore){
//1.检验参数的合法性
if(NULL == arrNum || NULL == arrStuName || iStuScore < 0){
printf("学生信息输入错误\n");
return ;
}
//2.逻辑处理
//创建一个节点
STUNODE* pTemp = (STUNODE*)malloc(sizeof(STUNODE));
//节点成员赋初始值
strcpy(pTemp->arrNum ,arrNum);
strcpy(pTemp->arrStuName ,arrStuName);
pTemp->iStuScore = iStuScore;
pTemp->pNext = NULL;//不让指针变成野指针
//接在链表上
if(NULL == g_pHead ||NULL == g_pEnd)//其实判断一个就ok,因为只要有一个是空,那么另外一个也会是空
{//这里是一开始的情况,指针指向都是空
g_pHead = pTemp;
g_pEnd = pTemp;//只有一个节点,头和尾是一个地方
}else{
//不是空,则直接在尾巴上添加就ok。也就是pEnd指向下一个
g_pEnd->pNext = pTemp;//链接
g_pEnd = pTemp;//尾巴向后移动
}
}
//清空链表
void FreeLinkData(){
//声明一个中间节点
STUNODE*pTemp = g_pHead;
while(g_pHead != NULL){
//记录节点
pTemp = g_pHead;
//向后移动一个
g_pHead = g_pHead->pNext;
//删除节点
free(pTemp);
}
}
//打印链表
void ShowStuData(){
STUNODE *pTemp = g_pHead;
while(pTemp != NULL){
printf("学号:%s,姓名:%s,分数:%d\n",pTemp->arrNum,pTemp->arrStuName,pTemp->iStuScore);
//向下走一步
pTemp = pTemp->pNext;
}
}
//在链表头添加学生节点
void AddStuMSGToLinkHead(char arrNum[10], char arrStuName[10], int iStuScore){
//检验参数的合法性
if(NULL == arrNum || NULL == arrStuName || iStuScore < 0){
printf("学生信息输入错误\n");
return ;
}
//创建一个节点
STUNODE*pTemp = (STUNODE*)malloc(sizeof(STUNODE));
//成员赋值
strcpy(pTemp->arrNum ,arrNum);
strcpy(pTemp->arrStuName ,arrStuName);
pTemp->iStuScore = iStuScore;
pTemp->pNext = NULL;//不让指针变成野指针
//链接
if(NULL == g_pHead ||NULL == g_pEnd){
//链表为空
g_pHead = pTemp;
g_pEnd = pTemp;
} else{//链表一个十分重要的: 先连后断
//新节点的下一个指向原来的头
pTemp-> pNext = g_pHead;
//头向前挪动一个
g_pHead = pTemp;
}
}
//查找指定学生
STUNODE* FindStuBuNum(char*arrNum){
//检验参数的合法性
if(NULL == arrNum){
printf("学号输入错误!\n");
return NULL;
}
//遍历链表
//判断链表是否为空
if(NULL == g_pHead || NULL == g_pEnd){
printf("链表为空\n");
return NULL;
}
STUNODE*pTemp = g_pHead;
while(pTemp != NULL){
//用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数
if(0 == strcmp(pTemp->arrNum,arrNum)){
return pTemp;
}
pTemp = pTemp->pNext;
}
printf("查无此节点");
return NULL;
}
//指定位置插入节点
void InsertNode(STUNODE*pTemp,char arrNum[10], char arrStuName[10], int iStuScore){
//创建节点
STUNODE*pNewTemp = (STUNODE*)malloc(sizeof(STUNODE));
//成员赋值
strcpy(pNewTemp->arrNum ,arrNum);
strcpy(pNewTemp->arrStuName ,arrStuName);
pNewTemp->iStuScore = iStuScore;
pNewTemp->pNext = NULL;//不让指针变成野指针
//插入节点
//不需要检验参数的合法性,因为之前已经检验了
if(pTemp == g_pEnd){
//是尾节点,直接尾添加
g_pEnd->pNext = pNewTemp;
g_pEnd = pNewTemp;
} else{
//是中间节点
//先连
pNewTemp->pNext = pTemp->pNext;
pTemp->pNext = pNewTemp;
}
}
//删除指定学生
void DeleteStuByNode(STUNODE*pNode){
//1.只有一个节点
if(g_pHead == g_pEnd){
free(g_pHead);
g_pHead = NULL;//把这一块空间交还给操作系统之后,指针里面装着非法空间,相当于留着后手,所以不行。所以要赋空。
g_pEnd = NULL;
}
//只有两个节点,释放之后还要改变链表头和尾的位置
else if(g_pHead->pNext == g_pEnd){
if(g_pHead == pNode){
free(g_pHead);
g_pHead = g_pEnd;
}else{
free(g_pEnd);
g_pEnd = g_pHead;
g_pHead->pNext = NULL;//删除之后 pNext装着非法地址
}
}
else{//大于两个
STUNODE*pTemp = g_pHead;
//看头节点是不是要删除的
if(g_pHead == pNode){
//记录头
pTemp = g_pHead;
//头向下走一个
g_pHead = g_pHead->pNext;
free(pTemp);
pTemp = NULL;//都已经释放了,就不要再留后手了
return ;//结束
}
while(pTemp != NULL){
if(pTemp->pNext == pNode){
//进行删除
if(pNode == g_pEnd){//如果要删除的是尾
free(pNode);
pNode = NULL;
g_pEnd = pTemp;
g_pEnd->pNext = NULL; //尾节点下一个赋空
return ;
}else{//中间节点
//记住要删除的节点
STUNODE*pNewTemp = pTemp->pNext;// 也可以把pTemp->pNext换成pNode
//前一节点指向要删除节点的下一个
pTemp->pNext = pNode->pNext;
//释放节点
free(pNewTemp);
pNewTemp = NULL;
return ;
}
}
pTemp = pTemp->pNext;
}
}
}
//保存信息进文件
void SaveStuToFile(){
FILE*pFile = NULL;
STUNODE*pTemp = g_pHead;
char strBud[30] = {0};//存储一个学生的信息,全存到这个字符串里面
char strScore[10] = {0};//存储分数
//判断链表是否是空
if(NULL == g_pHead){
printf("没有学生\n");
return ;
}
//打开文件
pFile = fopen("dat.txt","w+");
if(NULL == pFile){
printf("文件打开失败");
return ;
}
//操作文件指针
while(pTemp){
//学号赋值进去
strcpy(strBud,pTemp->arrNum);
strcat(strBud,",");//后面那个参数是字符串,所以要用双引号
//姓名赋值进去
strcat(strBud,pTemp->arrStuName);//在后面接着连上
strcat(strBud,",");
//分数
itoa(pTemp->iStuScore,strScore,10);//十进制将int类型转换成字符串类型
strcat(strBud,strScore);
fwrite(strBud,1,strlen(strBud),pFile);
fwrite("\r\n",1,strlen("\r\n"),pFile);
pTemp = pTemp->pNext;//这一步尤为重要
}
//关闭文件
fclose(pFile);
}
//从文件中读取学生信息
void ReadStuFromFile(){
FILE*pFile = fopen("dat.txt","r");
if(NULL == pFile){
printf("文件打开失败\n");
return;
}
char strBuf[30] = {0};
char strNum[10] = {0};
char strStuName[10] = {0};
char strStuScore[10] = {0};
int nCount = 0;
//操作指针,读取函数
while(NULL != fgets(strBuf,30,pFile)){//30代表最大读取量 fgets是一行一行去读
int i = 0;//每次开始的时候要清空循环控制变量
nCount = 0;
int j = 0;
for(i = 0;strBuf[i] != '\r';i++){
int j = 0;
if(0 == nCount)//没到','
{
strNum[i] = strBuf[i];
if(',' == strBuf[i]){
strNum[i] = '\0';//不让这个位置变成逗号,而是\0
nCount++;
}
}
else if(1 == nCount)//第一个 ','
{
strStuName[j] = strBuf[i];
j++;
if(',' == strBuf[i]){
strStuName[i] = '\0';
nCount++;
j = 0;
continue;
}
}
else //第二个','
{
strStuScore[j] = strBuf[i];
j++;
}
}
//插入到链表
char arrNum[10] = {0};//学号
char arrStuName[10];//姓名
int iStuScore;//分数
AddStuMSG(arrNum,arrStuName,atoi(strStuScore));
}
fclose(pFile);
}
一个有很多我改不出来的bug的学生管理系统(虽然能运行)
最新推荐文章于 2024-08-24 22:01:16 发布