链表操作实战之学生管理系统,由于使用VS2017IDE,有一些写法采用C++
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
using namespace std;
typedef struct STU
{
char arrStuNum[20]; // 学号
char arrStuName[20]; // 姓名
int iStuScore; // 学生分数
struct STU *next;
}STUNODE;
// 声明链表的头和尾
STUNODE* g_pHead = NULL;
STUNODE* g_pEnd = NULL;
// 添加一个学生的信息(从表尾)
void AddStuMSG(char *arrStuNum, char *arrStuName, int iStuScore);
// 添加一个学生的信息(从表头)
void AddStuLinkHead(char *arrStuNum, char *arrStuName, int iStuScore);
// 添加一个学生的信息(从指定位置)
void insertNode(STUNODE *pTemp, char *arrStuNum, char *arrStuName, int iStuScore);
// 清空链表
void FreeLinkData();
// 打印数据
void ShowStuData();
// 显示指令
void ShowOrder();
// 根据学号查找指定学生,返回结点的地址
STUNODE* FindStuByNum(char* arrStuNum);
// 删除指定的学生
void DeleteStuNode(STUNODE* pNode);
// 保存学生信息
void SaveStuFile();
// 读取文件中学生的信息
void ReadStuFile();
int main()
{
// 显示操作界面
ShowOrder();
int nOrder=-1;
char arrStuNum[20] = { '\0' };
char arrStuName[20] = { '\0' };
int iStuScore = -1;
bool flag = true;
STUNODE* ptemp;
// 读取文件中学生信息
ReadStuFile();
printf("加载数据库数据成功\n");
while (flag)
{
printf("请输入指令,输入0查看指令:\n");
scanf_s("%d", &nOrder);
switch (nOrder)
{
case 1:
// 添加一个学生的信息(尾添加)
printf("输入学号:");
cin >> arrStuNum;
printf("输入姓名:");
cin >> arrStuName;
printf("输入分数:");
cin >> iStuScore;
AddStuMSG(arrStuNum, arrStuName, iStuScore);
break;
case 11:
// 添加一个学生的信息(头添加)
printf("输入学号:");
cin >> arrStuNum;
printf("输入姓名:");
cin >> arrStuName;
printf("输入分数:");
cin >> iStuScore;
AddStuLinkHead(arrStuNum, arrStuName, iStuScore);
break;
case 111:
// 添加一个学生的信息(从指定位置)
printf("请输入要添加位置之前的学生的学号:\n");
cin >> arrStuNum;
ptemp = FindStuByNum(arrStuNum);
if (ptemp == NULL)
printf("无此学生信息\n");
printf("输入学号:");
cin >> arrStuNum;
printf("输入姓名:");
cin >> arrStuName;
printf("输入分数:");
cin >> iStuScore;
insertNode(ptemp, arrStuNum, arrStuName, iStuScore);
break;
case 2:
// 根据学号查找学生信息
printf("请输入要查找学生的学号:\n");
cin >> arrStuNum;
ptemp = FindStuByNum(arrStuNum);
if (ptemp != NULL)
printf("学号:%s,姓名:%s,分数%d\n", ptemp->arrStuNum, ptemp->arrStuName, ptemp->iStuScore);
else
printf("无此学生信息\n");
break;
case 3:
// 修改指定学生的信息
// 根据学号查找学生信息
printf("请输入要修改学生原来的学号:\n");
cin >> arrStuNum;
ptemp = FindStuByNum(arrStuNum);
if (ptemp != NULL)
{
// 修改学号
printf("输入修改的学号:\n");
cin >> arrStuNum;
strcpy_s(ptemp->arrStuNum, arrStuNum);
// 修改名字
printf("输入修改的姓名:\n");
cin >> arrStuName;
strcpy_s(ptemp->arrStuName, arrStuName);
// 修改分数
printf("输入修改的分数:\n");
cin >> iStuScore;
ptemp->iStuScore = iStuScore;
}
else
printf("无此学生信息\n");
break;
case 4:
// 保存学生信息
SaveStuFile();
printf("成功写入文件\n");
break;
case 5:
// 从文件读取数据到链表
ReadStuFile();
break;
case 6:
// 根据学号,删除指定的学生信息
printf("请输入要删除学生的学号\n");
cin >> arrStuNum;
ptemp = FindStuByNum(arrStuNum);
if (ptemp != NULL)
DeleteStuNode(ptemp);
break;
case 7:
// 从文件恢复删除的学生的信息
FreeLinkData();
g_pHead = NULL;
g_pEnd = NULL;
ReadStuFile();
break;
case 8:
// 显示链表内容
ShowStuData();
break;
case 9:
// 退出程序
flag = false;
break;
case 0:
// 显示指令
ShowOrder();
break;
default:
printf("输入指令不正确\n");
break;
}
}
// 释放链表
FreeLinkData();
return 0;
}
// 添加一个学生的信息
void AddStuMSG(char *arrStuNum, char *arrStuName, int iStuScore)
{
// 检验参数的合法性
if (arrStuNum == NULL || arrStuName == NULL || iStuScore < 0)
{
printf("学生信息输入错误\n");
return;
}
STUNODE *pTemp;
pTemp = (STUNODE*)malloc(sizeof(STUNODE));
strcpy_s(pTemp->arrStuNum, arrStuNum);
strcpy_s(pTemp->arrStuName, arrStuName);
pTemp->iStuScore = iStuScore;
pTemp->next = NULL;
// 接在链表上
if (g_pHead == NULL || g_pEnd == NULL)
{
g_pHead = pTemp;
}
else
{
g_pEnd->next = pTemp;
}
g_pEnd = pTemp;
}
// 从表头添加一个学生信息
void AddStuLinkHead(char *arrStuNum, char *arrStuName, int iStuScore)
{
// 检验参数的合法性
if (arrStuNum == NULL || arrStuName == NULL || iStuScore<0)
{
printf("学生信息输入错误\n");
return;
}
// 添加节点
STUNODE* pTemp = (STUNODE*)malloc(sizeof(STUNODE));
strcpy_s(pTemp->arrStuNum, arrStuNum);
strcpy_s(pTemp->arrStuName, arrStuName);
pTemp->iStuScore = iStuScore;
pTemp->next = NULL;
if (g_pHead == NULL || g_pEnd == NULL)
{
g_pEnd = pTemp;
}
else
{
pTemp->next = g_pHead;
}
g_pHead = pTemp;
}
// 从任意位置添加一个学生信息
void insertNode(STUNODE *pTemp, char *arrStuNum, char *arrStuName, int iStuScore)
{
// 创建节点
STUNODE* ptemp = (STUNODE*)malloc(sizeof(STUNODE));
strcpy_s(ptemp->arrStuNum, arrStuNum);
strcpy_s(ptemp->arrStuName, arrStuName);
ptemp->iStuScore = iStuScore;
ptemp->next = NULL;
// 在尾部插入
if (pTemp == g_pEnd)
{
g_pEnd->next = ptemp;
g_pEnd = ptemp;
}
else
{
ptemp->next = pTemp->next;
pTemp->next = ptemp;
}
}
//清空链表,从前往后清楚
void FreeLinkData()
{
STUNODE* pTemp = g_pHead;
while (g_pHead != NULL)
{
pTemp = g_pHead;
// 向后移动一个
g_pHead = g_pHead->next;
free(pTemp);
}
}
// 显示链表
void ShowStuData()
{
STUNODE* pTemp = g_pHead;
if (!pTemp)
{
printf("没有录入学生信息\n");
}
while (pTemp)
{
printf("学号:%s, 姓名:%s, 分数%d\n", pTemp->arrStuNum, pTemp->arrStuName, pTemp->iStuScore);
pTemp = pTemp->next;
}
}
// 显示指令
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("*** 8. 显示所有的学生的信息 ***\n");
printf("*** 9. 退出系统 ***\n");
printf("********************************************************\n");
}
// 根据学号查找指定学生,返回结点的地址
STUNODE* FindStuByNum(char* arrStuNum)
{
STUNODE* pTemp = g_pHead;
// 检查参数的合法性
if (arrStuNum == NULL)
{
printf("学号输入错误!\n");
return NULL;
}
// 判断链表是否为空
if (g_pHead == NULL || g_pEnd == NULL)
{
printf("链表为空\n");
return NULL;
}
// 遍历链表
while (pTemp)
{
// 字符串匹配函数
if(strcmp(pTemp->arrStuNum, arrStuNum) == 0)
return pTemp;
pTemp = pTemp->next;
}
printf("查无此结点\n");
return NULL;
}
// 删除指定节点
void DeleteStuNode(STUNODE* pNode)
{
// 只有一个节点
if (g_pHead == g_pEnd)
{
free(g_pHead);
g_pHead = NULL;
g_pEnd = NULL;
}
// 只有两个节点
else if (g_pHead->next == g_pEnd)
{
if (g_pHead == pNode)
{
free(g_pHead);
g_pHead = g_pEnd;
}
else
{
free(g_pEnd);
g_pHead->next = NULL;
g_pEnd = g_pHead;
}
}
// 节点数>=3
else
{
STUNODE *pTemp = g_pHead;
// 删除位置在头节点
if (g_pHead == pNode)
{
pTemp = g_pHead;
g_pHead = g_pHead->next;
free(pTemp);
pTemp = NULL;
return;
}
while (pTemp)
{
if (pTemp->next == pNode)
{
if (pNode == g_pEnd)
{
free(pNode);
g_pEnd = pTemp;
g_pEnd->next = NULL;
return;
}
else
{
// 记住节点
STUNODE *p = pNode;
pTemp->next = pNode->next;
free(p);
return;
}
}
pTemp = pTemp->next;
}
}
}
void SaveStuFile()
{
FILE* pFile = NULL;
STUNODE* pTemp = g_pHead;
char strBuf[30] = { 0 };
char strScore[10] = { 0 };
// 判断链表是否为空
if (g_pHead == NULL)
{
printf("没有学生\n");
return;
}
// 打开文件
fopen_s(&pFile,"dat.dat", "wb+");
if (pFile == NULL)
{
printf("没有学生\n");
return;
}
// 操作文件指针
while (pTemp)
{
// 复制学号
strcpy_s(strBuf, pTemp->arrStuNum);
strcat_s(strBuf, " ");
// 姓名
strcat_s(strBuf, pTemp->arrStuName);
strcat_s(strBuf, " ");
// 分数
_itoa_s(pTemp->iStuScore, strScore, 10);
strcat_s(strBuf, strScore);
fwrite(strBuf, 1, strlen(strBuf), pFile);
fwrite("\r\n", 1, strlen("\r\n"), pFile);
pTemp = pTemp->next;
}
// 关闭文件
fclose(pFile);
}
// 从文件读取数据到链表
void ReadStuFile()
{
FILE* pFile;
fopen_s(&pFile, "dat.dat", "rb+");
char strBuf[30] = { 0 };
char strStuNum[20] = { 0 };
char strStuName[20] = { 0 };
char strScope[10] = { 0 };
int nCount=0;
int j = 0;
if (pFile == NULL)
{
printf("文件打开失败\n");
return;
}
// 操作指针, 读取函数
while (fgets(strBuf, 30, pFile))
{
//printf("%s\n", strBuf);
for (int i = 0; strBuf[i] != '\r'; i++)
{
if (nCount == 0)
{
strStuNum[i] = strBuf[i];
if (strBuf[i] == ' ')
{
strStuNum[i] = '\0';
nCount++;
j = 0;
}
}
else if (nCount == 1)
{
strStuName[j++] = strBuf[i];
if (strBuf[i] == ' ')
{
j = 0;
nCount++;
}
}
else
{
strScope[j++] = strBuf[i];
}
}
nCount = 0;
strStuName[strlen(strStuName) - 1] = '\0';
AddStuMSG(strStuNum, strStuName, atoi(strScope));
}
fclose(pFile);
}