学习B站up主C3程序猿的视频后总结分享【学生管理系统】_哔哩哔哩_bilibili【学生管理系统】https://www.bilibili.com/video/BV1uW411Q7Cf?spm_id_from=333.999.0.0
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//学生结点
typedef struct _STU
{
char arrStuName[20];
char arrStuNum[100];
int iStuScore;
struct _STU* pNext;
}STUNODE;
//声明链表的头和尾
STUNODE* g_pHead = NULL;//全局变量用g_
STUNODE* g_pEnd = NULL;
void menu();//主菜单
void AddStuMSG(char* arrStuNum, char* arrStuName, int iStuScore);//添加一个学生的信息(尾添加)
void FreeLinkData();//清空链表
void ShowStuData();//打印数据
void AddStuMSGToLinkHead();//链表头添加一个结点(头添加)
STUNODE* FindStuByNum(char* arrStuNum);//查找指定学生信息
void InsertNode(STUNODE* pTemp, char* arrStuNum, char* arrStuName, int iStuScore);//特定位置插入结点 先连接再断开
void DeleteStuNode(STUNODE* pNode);//删除指定学生信息
void SaveStuToFile();//保存学生信息到文件中
void ReadStuFromFile();//读取文件中的文件信息
void FixStuByNum(STUNODE* pTemp,int target,char* strFixedData);//修改指定学生信息(学号,目标修改数据,用于替换的数)
int main()
{
int iOrder = -1;
char arrStuNum[20] = { '\0' };
char arrStuName[20] = { '\0' };
int iStuScore = -1;
int flag = 1;
//打印菜单
menu();
while(flag) {
printf("请输入指令\n");
scanf("%d", &iOrder);
switch (iOrder)
{
case 0:
//todo退出程序
flag = 0;
break;
case 1:
//todo 尾添加一个学生信息
printf("请输入学生姓名:");
scanf("%s", arrStuName);
printf("请输入学号:");
scanf("%s", arrStuNum);
printf("请输入学生分数:");
scanf("%d", &iStuScore);
AddStuMSG(arrStuNum, arrStuName, iStuScore);
fflush(stdin);
break;
case 2:
//todo 头添加一个学生信息
printf("请输入学生姓名:");
scanf("%s", arrStuName);
printf("请输入学号:");
scanf("%s", arrStuNum);
printf("请输入学生分数:");
scanf("%d", &iStuScore);
AddStuMSGToLinkHead(arrStuNum, arrStuName, iStuScore);
fflush(stdin);
break;
case 3:
{ //在switch中添加临时变量需要加花括号
//todo 指定位置添加学生信息
STUNODE* pTemp = NULL;
printf("请输入所插入位置之前的学号:");
scanf("%s", arrStuNum);
pTemp = FindStuByNum(arrStuNum);
fflush(stdin);
if (NULL != FindStuByNum(arrStuNum))
{
//todo 插入新学生信息结点
printf("请输入学生姓名:");
scanf("%s", arrStuName);
printf("请输入学号:");
scanf("%s", arrStuNum);
printf("请输入学生分数:");
scanf("%d", &iStuScore);
InsertNode(pTemp, arrStuNum, arrStuName, iStuScore);
}
fflush(stdin);
break;
}
case 4:
{
//todo 打印指定学生的信息
STUNODE* pTemp = NULL;
//输入一个学号
printf("请输入需要查找学生的学号:");
scanf("%s", arrStuNum);
//查找
pTemp = FindStuByNum(arrStuNum);
//打印
if (NULL != pTemp)
{
printf("姓名:%s,学号:%s,分数:%d\n", pTemp->arrStuName, pTemp->arrStuNum, pTemp -> iStuScore);
}
break;
}
case 5:
//todo 修改指定学生的信息
{
int target = -1; //学号:1, 姓名 : 2,成绩:3.
char strStuNum[20] = { 0 };
char strFixedData[20] = {0};
STUNODE* pTemp = NULL;
printf("请输入想要修改学生的学号:");
scanf("%s", strStuNum);
pTemp = FindStuByNum(strStuNum);
if (pTemp == NULL)
{
break;
}
else {
printf("请输入你想要修改的数据(1:学生学号,2:学生姓名,3:学生成绩):");
scanf("%d", &target);
printf("请输入你想要修改后的数据:");
scanf("%s", strFixedData);
FixStuByNum(pTemp, target,strFixedData);
printf("修改成功\n");
}
}
break;
case 6:
//todo 保存学生信息到文件中
SaveStuToFile();
break;
case 7:
//todo 读取文件中的文件信息
ReadStuFromFile();
break;
case 8:
{
//todo 删除指定学生信息
STUNODE* pTemp=NULL;
//输入一个学号
printf("请输入要删除学生的学号:");
scanf("%s", arrStuNum);
//查找
pTemp = FindStuByNum(arrStuNum);
//删除这个节点
if (NULL != pTemp)
{
//调用删除函数
DeleteStuNode(pTemp);
}
break;
}
case 9:
//todo 恢复删除学生的信息
//清空链表
FreeLinkData();
g_pHead = NULL;
g_pEnd = NULL;
//恢复结点
ReadStuFromFile();//从文件中恢复结点
printf("恢复成功\n");
break;
case 10:
//打印学生数据
ShowStuData();
break;
case 11:
//再次打印菜单
menu();
break;
default:
printf("无效指令!\n");
}
}
//释放链表
FreeLinkData();
return 0;
}
void menu()
{
printf("********************学生信息管理系统**********************\n");
printf("*********************本系统操作如下***********************\n");
printf("*** 1.增加一个学生信息(尾添加) ***\n");
printf("*** 2.增加一个学生信息(头添加) ***\n");
printf("*** 3.指定位置添加学生信息 ***\n");
printf("*** 4.打印指定学生信息(姓名,学号) ***\n");
printf("*** 5.修改指定学生的信息 ***\n");
printf("*** 6.保存学生的信息到文件中 ***\n");
printf("*** 7.读取文件中的学生信息 ***\n");
printf("*** 8.删除指定学生的信息 ***\n");
printf("*** 9.恢复删除的学生的信息 ***\n");
printf("*** 10.显示所有学生的信息 ***\n");
printf("*** 11.再次打印菜单 ***\n");
printf("*** 0.退出系统 ***\n");
printf("**********************************************************\n");
}
//do添加一个学生的信息
void AddStuMSG(char* arrStuNum, char* arrStuName, int iStuScore) //分数,学生名,学号 **数组做参数,其实是一个指针
{
//第一步 检验参数的合法性
if (NULL == arrStuNum || NULL == arrStuName || iStuScore < 0)
{
printf("学生信息输入错误\n");
return;
}
//第二步 逻辑处理
//1.创建一个结点
STUNODE* pTemp = malloc(sizeof(STUNODE));
//2.对结点内成员赋值
//pTemp->arrStuNum=arrStuNum; 这种写法是错误的,因为传进来的参数是地址。
strcpy(pTemp->arrStuNum, arrStuNum);
strcpy(pTemp->arrStuName, arrStuName);
pTemp->iStuScore = iStuScore;
pTemp->pNext = NULL;
//赋值完成
//3.将结点接在链表上(**使用尾连接)
if (NULL == g_pHead || NULL == g_pEnd) //添加的第一个结点
{
g_pHead = pTemp;
g_pEnd = pTemp;
}
else //直接在尾巴添加
{
g_pEnd->pNext = pTemp; //链接结点
g_pEnd = pTemp; //尾巴向后移动
}
}
//do清空链表
void FreeLinkData()
{
STUNODE* pTemp = g_pHead;
while (g_pHead != NULL)
{
pTemp = g_pHead; //记录结点
g_pHead = g_pHead->pNext; //头结点后移
free(pTemp); //删除结点
}
}
//do打印数据
void ShowStuData()
{
STUNODE* pTemp = g_pHead;
printf("学生姓名 学号 分数\n");
while (pTemp != NULL) {
printf("%-15s%-12s%-10d\n", pTemp->arrStuName, pTemp->arrStuNum, pTemp->iStuScore);
pTemp = pTemp->pNext;
}
}
//do链表头添加一个结点(头添加)
void AddStuMSGToLinkHead(char* arrStuNum, char* arrStuName, int iStuScore)
{
STUNODE* pTemp = malloc(sizeof(STUNODE));
//检测参数的合法性
if (NULL == arrStuName || NULL==arrStuName || iStuScore < 0)
{
printf("学生信息输入错误\n");
return;
}
strcpy(pTemp->arrStuNum, arrStuNum);
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;
}
}
//do 查找指定学生信息
STUNODE* FindStuByNum(char* arrStuNum)
{
STUNODE* pTemp = g_pHead;
if (NULL == arrStuNum)//检测输入
{
printf("学号输入错误\n");
return NULL;
}
if (NULL == g_pHead || NULL == g_pEnd)//链表为空
{
printf("学号输入错误\n");
return NULL;
}
else {//遍历链表
while (pTemp != NULL)
{
if (0==strcmp(pTemp->arrStuNum, arrStuNum))
{
return pTemp;
}
pTemp = pTemp->pNext;
}
}
printf("未查找到该生信息\n");
return NULL;
}
//do 特定位置插入结点
void InsertNode(STUNODE* pTemp, char* arrStuNum, char* arrStuName, int iStuScore)
{
//创建结点
STUNODE* pNewTemp = malloc(sizeof(STUNODE));
//成员赋值
strcpy(pNewTemp->arrStuNum, arrStuNum);
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;
}
}
//do 删除指定学生信息
void DeleteStuNode(STUNODE* pNode)
{
//只有一个结点
if (g_pHead == g_pEnd)
{
free(g_pHead);
g_pEnd = NULL;
g_pHead = NULL;
printf("信息删除成功!\n");
return;
}
else if(g_pHead->pNext==g_pEnd)//两个结点
{
if (g_pHead == pNode)
{
free(g_pHead);
g_pHead = g_pEnd;
printf("信息删除成功!\n");
return;
}
else {
free(g_pEnd);
g_pEnd = g_pHead;
g_pHead->pNext = NULL;//防止指针仍指向原地址导致错误
printf("信息删除成功!\n");
return;
}
}
else//常规情况(结点数>=3)
{
STUNODE* pTemp = g_pHead;
if (g_pHead == pNode)//判断头
{
pTemp = g_pHead;//记录头
g_pHead = g_pHead->pNext;
free(pTemp);
pTemp=NULL;
printf("信息删除成功!\n");
return;
}
while(pTemp != NULL)
{
if (pTemp->pNext == pNode)//头结点为目标结点的情况在之前已经判断过,此处从第二个结点开始判断
{
//删除
if (g_pEnd == pNode)//判断尾
{
free(pNode);
pNode = NULL;
g_pEnd = pTemp;
printf("信息删除成功!\n");
return;
}
else {
//记录要删除的节点
STUNODE* p = pTemp->pNext;
//
pTemp->pNext = pNode->pNext;//连接
free(p);
p=NULL;
printf("信息删除成功!\n");
return;
}
}
pTemp = pTemp->pNext;
}
}
}
//do 保存学生信息到文件中
void SaveStuToFile()
{
STUNODE* pTemp = g_pHead;
FILE* pFile = NULL;
char strBuf[60] = { 0 };
char strScore[10] = { 0 };
//判断链表是否为空
if (NULL == g_pHead)
{
printf("链表为空,未录入学生信息!\n");
return;
}
//打开文件
pFile = fopen("dat.dat", "wb+");//打开的文件地址,打开方式(此处为可读可写)
if (NULL == pFile)
{
printf("文件打开失败\n");
return;
}
//操作文件指针
while (pTemp)//遍历链表
{
//学号赋值
strcpy(strBuf, pTemp->arrStuNum);
strcat(strBuf, ".");//分隔文件中的元素,便于查看和读取
//姓名赋值
strcat(strBuf, pTemp->arrStuName);//在字符串末尾连接
strcat(strBuf, ".");
//分数赋值
_itoa(pTemp->iStuScore, strScore,10);
//组合字符串
strcat(strBuf, strScore);
fwrite(strBuf,1,strlen(strBuf),pFile);//程序中的字符串,目标数量,单个目标所占字节,指针
fwrite("\r\n", 1, strlen("\r\n"), pFile);
pTemp = pTemp->pNext;
}
//关闭文件
fclose(pFile);
}
//do 读取文件中的文件信息
void ReadStuFromFile()
{
FILE* pFile = fopen("dat.dat", "rb+");
char strBuf[60] = { 0 };
char strStuNum[20] = { 0 };
char strStuName[20] = { 0 };
char strStuScore[10] = { 0 };//不要忘记读入以后转化为整形
if (NULL == pFile)
{
printf("文件打开失败\n");
return;
}
//操作指针,读取文件
while (NULL != fgets(strBuf, 60, pFile))//一次读取一行,参数:文件中内容存放的地方,字符数组大小,文件地址 注意EOF返回值
{
int i = 0;
int iCount = 0;
int j = 0;
for (i = 0; strBuf[i] != '\r'; i++)//行写入
{
if (0 == iCount)//没有读到'.'
{
strStuNum[i] = strBuf[i];
if('.'==strBuf[i])
{
strStuNum[i] = '\0';
iCount++;
}
}
else if (1 == iCount)//读到第一个'.'
{
strStuName[j] = strBuf[i];
if('.' == strBuf[i])
{
strStuName[j] = '\0';
iCount++;
j = 0;
continue;//跳过循环,防止运行下面的j++
}
j++;
}
else//读到第二个'.'
{
strStuScore[j] = strBuf[i];
j++;
}
}
//插入到链表
AddStuMSG(strStuNum, strStuName, atoi(strStuScore));
}
fclose(pFile);
}
//do 修改指定学生信息(目标结点,目标修改数据,用于替换的数)
void FixStuByNum(STUNODE* pTemp, int target, char* strFixedData)
{
if (target == 3) {
pTemp->iStuScore = atoi(strFixedData);
}
else if (target == 2) {
strcpy(pTemp->arrStuName, strFixedData);
}
else {
strcpy(pTemp->arrStuNum, strFixedData);
}
}