在复习链表的时候,翻回了之前做过的一个选手评分系统,顺便分享记录一下,免得以后找不到了,毕竟那是第一次做c语言项目。这篇文章可能很长,代码量1000多行,顺便说一下,下面的代码解释基本都是以注释方式解释。
1.项目整体介绍
2.项目功能实现
3.项目全部代码
4.总结项目,做出评价
else if (strcmp(arrPassword, "0") == 0)
{
printf("---------------------------感谢你的使用-----------------------------\n");
exit(0);
}
else //密码错误
{
int nChoose;
printf("密码错误,你可以选择继续登录(输入1)或者退出该系统(输入其他任意数字)\n");
scanf("%d", &nChoose);
if (nChoose == 1)
continue;
else
printf("---------------------------感谢你的使用-----------------------------\n");
exit(0);
}
至于这里为什么有两个退出的选择,是因为一个是直接退出,一个是在假如输入密码错误之后,给出选择,继续输入密码或者直接退出系统。用到exit(0)。
case 1:
{
printf("------------------------输入一个选手信息----------------------------\n");
//人数++
recordPl++;
printf("该选手的名字是:\n");
scanf("%s", arrPlname);
printf("该选手的编号是:\n");
scanf("%s", arrPlNum);
printf("10位评委的打分(请一次输入10个分数)\n");
for (i = 0; i < 10; i++)
{
scanf("%lf", &dbPlScore[i]);
}
//调用函数添加
AddPlayerMSG(arrPlname, arrPlNum, dbPlScore);
break;
}
void AddPlayerMSG(char arrPlayername[10], char arrPlayNum[10], double* p_score)
//参数就是几个信息:分别为选手名字,选手编号,选手得分,这里得分传入地址是因为传入的是一个一维数组
{
//传入信息进行添加
if (arrPlayername == NULL && arrPlayNum == NULL || p_score == NULL)
{
//判断信息的合理性,避免给一个null的信息
printf("选手信息输入错误.\n");
return;
}
//开辟空间,准备插入到链表中
struct PlayerNode* pTemp = malloc(sizeof(struct PlayerNode));
if (pTemp != NULL)
//表面申请空间成功
{
//传入信息到申请的节点中
strcpy(pTemp->arrPlayername, arrPlayername);
strcpy(pTemp->arrPlayerNumber, arrPlayNum);
for (i = 0; i < 10; i++)
{
pTemp->dbstudent[i] = *(p_score + i);
}
pTemp->pNext = NULL;
//作为第一个节点
if (NULL == g_pEnd || NULL == g_pHead)
{
//新节点是头也是尾
g_pEnd = pTemp;
g_pHead = pTemp;
return;
}
//作为新增其他节点
else
{
//这里节点不是顺序添加,而是依据编号来添加,也就是说添加进链表的数据是已经排好序的
struct PlayerNode* pT1, * pT2;
//记住头节点,避免头节点在移动的过程中会丢失
pT1 = g_pHead;
pT2 = NULL;
//当需要插入的节点的编号比头节点大
while (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) > 0 && pT1->pNext != NULL)
{
//这时候就是一个遍历操作,一直遍历到比要插入的节点pTemp的编号大的那个节点,此时pT1指向的就是比编号pTemp大的那个节点
pT2 = pT1;
pT1 = pT1->pNext;
}
//如果找到了,就在pT1前面加
if (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) <= 0)
{
//找到的是头节点
if (g_pHead == pT1)
{
pTemp->pNext = g_pHead;
g_pHead = pTemp;
return;
}
//找到的节点不是头节点
else
{
pT2->pNext = pTemp;
pTemp->pNext = pT1;
return;
}
}
//找不到比插入节点pTemp编号更大的,此时pT1指向了尾节点,那么就让pT1来指向pTemp就好了
else
{
pT1->pNext = pTemp;
pTemp->pNext = NULL;
g_pEnd = pTemp;
}
}
}
}
在整个添加函数中,pT1是始终出现在其中的,原理很简单,遍历 — 找编号比要插入的节点要大的 — 插入节点。只是在这个过程中有一特殊情况要处理,比如pTemp比任何节点都要大或者比任何节点都要小。当然,如果pTemp刚好是在尾节点的话,别忘了pTem的下一个指向NULL,否则会出大问题。~~~真的。
case 3:
{
recordPl--;
printf("-------------------------删除退赛选手的信息-----------------------------\n");
//删除退赛的选手的信息
struct PlayerNode* pT = NULL;
printf("请输入要删除的选手的编号:\n");
scanf("%s", arrPlNum);
//这个函数也不多介绍了,就是一个普通的遍历操作,返回找到的节点,找不到就返回null
pT = FindPlayByNum(arrPlNum);
//判断pT是否找到
if (NULL != pT) //找到了
{
//存数据进文档
SavePlayToFileByOne(pT);
//调用函数
DeletePlayerMSG(pT);
}
break;
}
重点是下面的两个函数
void SavePlayToFileByOne(struct PlayerNode*pT)
{
//下面的有一些变量也可以不用管,简单说明一下,RecordDelete是记录删除的人数
RecordDelete++;
int i = 0;
struct PlayerNode* pTemp=pT;
FILE* pFile = NULL;
//写入文件,当删除的人数是1的时候
if (RecordDelete == 1)
{
//用写的形式打开文件
pFile = fopen("DeleteStudentDate.dat", "w");
if (NULL == pFile)
{
printf("文件打开失败.\n");
return;
}
//保存姓名编号:这里要注意格式,因为接下来的读取文件会用到
fprintf(pFile, "%s : %s ", pTemp->arrPlayerNumber, pTemp->arrPlayername);
//保存选手得分
fprintf(pFile, "%s", "得分: ");
for (i = 0; i < 10; i++)
{
fprintf(pFile, "%.2f ", pTemp->dbstudent[i]);
}
//注意:我这里是直到把信息全部写入文件才换行,也就是说姓名,编号,得分全是在一行的,至于为什么,下面会解释
fprintf(pFile, "\n");
//关闭文件
fclose(pFile);
printf("已将删除的选手的信息传入文档,如果需要恢复,请输入指令10\n");
}
//当删除的人数大于二,用接着写,防止原来的信息被擦除
if (RecordDelete >= 2)
{
pFile = fopen("DeleteStudentDate.dat", "a+");
if (NULL == pFile)
{
printf("文件打开失败.\n");
return;
}
//保存姓名编号
fprintf(pFile, "%s : %s ", pTemp->arrPlayerNumber, pTemp->arrPlayername);
//保存选手得分
fprintf(pFile, "%s", "得分: ");
for (i = 0; i < 10; i++)
{
fprintf(pFile, "%.2f ", pTemp->dbstudent[i]);
}
fprintf(pFile, "\n");
//关闭文件
fclose(pFile);
printf("已将删除的选手的信息传入文档,如果需要恢复,请输入指令10\n");
}
}
//删除节点函数,这里假如能调用删除函数,那么就肯定是找到了节点,否则if条件进不来
void DeletePlayerMSG(struct PlayerNode* pNode)
{
//只有一个节点,那找到的节点肯定是头节点啦
if (g_pHead == g_pEnd)
{
free(g_pHead);
g_pHead = NULL;
g_pEnd = NULL;
return;
}
//两个节点
else if (g_pHead->pNext == g_pEnd)
{
if (g_pHead == pNode) //找到的是头节点
{
free(g_pHead);
g_pHead = g_pEnd;
return;
}
else
{
free(g_pEnd);
g_pEnd = g_pHead;
g_pEnd->pNext = NULL; //一定要赋值NULL
return;
}
}
//节点多于3个
else
{
struct PlayerNode* pTemp = g_pHead;
//头删除
if (g_pHead == pNode)
{
pTemp = g_pHead; //记住头
g_pHead = g_pHead->pNext;
free(pTemp);
pTemp = NULL;
return;
}
//不是头
while (pTemp != NULL)
{
//遍历找到要删除的节点的前一个,画个图就很好懂了,因为要对next操作
if (pTemp->pNext == pNode)
{
//如果要删除的节点是尾节点
if (pTemp->pNext == g_pEnd)
{
free(g_pEnd);
g_pEnd = pTemp;
g_pEnd->pNext = NULL;
return;
}
//删除的不是尾节点
else
{
//记住要删除的节点
struct PlayerNode* pT = pTemp->pNext;
if (pT != NULL)
{
pTemp->pNext = pT->pNext;
free(pT);
pT = NULL;
return;
}
}
}
pTemp = pTemp->pNext;
}
}
}
这里第二个删除函数其实很好理解,不多说明,代码都有注释。第一个函数存入文件的函数。我分别是用了w 和 a+ 来写入文件,考虑到文件会被擦除的风险就这样处理了。但是我不清楚a+在第一次写入文件的时候会不会和w的处理一样,如果一样,那么这里的代码可以简化为都用a+的,少了几十行代码。然后关于输入格式的问题,我在上面是用了 fprintf 来输入,主要的原因也是为了控制输入的格式,等要读取文件的时候用 fscanf 就会比较轻松。这一点文件读取是一个问题,在下面的输入文件读取文件中会细说。
case 4:
{
printf("--------------------------排序----------------------------\n");
//判断是否需要排序
if (g_pHead == NULL || g_pHead == g_pEnd)
{
printf("数据过少,不需要排序,请添加选手信息.\n");
break;
}
struct PlayerNode* pT1, * pT2;
pT1 = g_pHead;
//这里就相当于一个冒泡排序
while (pT1 != NULL && pT1->pNext->pNext != NULL)
{
pT2 = pT1->pNext;
while (pT2 != NULL)
{
if (Average(pT1) < Average(pT2)) //比较平均分
{
ExPlayerNode(pT1, pT2); //交换节点
}
pT2 = pT2->pNext;
}
pT1 = pT1->pNext;
}
if (pT1->pNext->pNext == NULL)
{
pT2 = pT1->pNext;
ExPlayerNode(pT1, pT2);
}
printf("已按成绩高低从大到小排序\n");
break;
}
void ExPlayerNode(struct PlayerNode* pNode1, struct PlayerNode* pNode2)
{
char arrExchangeName[20] = {
0 };
char arrExchangeNum[20] = {
0 };
int i;
double nTempscore;
for (i = 0; i < 10; i++) //交换节点的分数
{
nTempscore = pNode1->dbstudent[i];
pNode1->dbstudent[i] = pNode2->dbstudent[i];
pNode2->dbstudent[i] = nTempscore;
}
//交换学号
strcpy(arrExchangeNum, pNode1->arrPlayerNumber);
strcpy(pNode1->arrPlayerNumber, pNode2->arrPlayerNumber);
strcpy(pNode2->arrPlayerNumber, arrExchangeNum);
//交换名字
strcpy(arrExchangeName, pNode1->arrPlayername);
strcpy(pNode1->arrPlayername, pNode2->arrPlayername);
strcpy(pNode2->arrPlayername, arrExchangeName);
return;
}
case 8:
{
printf("---------------------------保存信息进文件----------------------------\n");
SavePlayToFile();
break;
}
case 9:
{
printf("---------------------------输出最初和最终的结果----------------------------\n");
PrintOriAndFinal();
break;
}
case 10:
{
char PointNum[20] = {
0 };
printf("输入你需要找回的选手的姓名:\n");
scanf("%s", PointNum);
ReadFileToFindDelte(PointNum);
break;
}
void SavePlayToFile()
{
//看标题就知道是写入文件啦,就是这名字起的有些不好
//这里的存入文件有两个,一个是初始文件,一个是排名后的文件
int a[1000] = {
0 };
int i, j = 0;
for (i = 0; i < recordPl; i++)
{
a[i] = i + 1;
}
//两个指针分别操作两个文件的存入
struct PlayerNode* pTemp1 = g_pHead;
struct PlayerNode* pTemp2 = g_pHead;
int nFileOrder = 0;
printf("---------写入文件---------\n");
printf("~~1、初始存入\n~~2、排序后存入:\n~~3、取消该指令\n");
printf("~~~请输入存储类型(1、2或3):\n");
//输入指令,1就是初始存入,2就是排名后存入
scanf("%d", &nFileOrder);
FILE* pFile = NULL;
FILE* pFile1 = NULL;
//判断链表是否为NULL
if (g_pHead == NULL)
{
printf("----没有选手信息----\n");
return;
}
//写入文件
switch (nFileOrder)
{
case 1:
{
//初始文件的意思就是你输入了信息,但没有排序,这就是初始文件
pFile = fopen("playerOriginal.dat", "w");
if (NULL == pFile)
{
printf("文件打开失败.\n");
return;
}
while (pTemp2 != NULL)
{
//保存姓名编号,用fscanf,这里好处就体现出来了,如果是字节输入输出,那么就会产生问题,首先就是不能控制好格式,可以想想怎么控制得了想要的数据的字节,要知道每个人的名字不一样,分数也不一样,编号更不一样,有的长有的短。而用fscanf是为了控制格式,便于输出。
fprintf(pFile, "%s : %s ", pTemp2->arrPlayerNumber, pTemp2->arrPlayername);
//保存选手得分
fprintf(pFile, "%s", "得分: ");
for (i = 0; i < 10; i++)
{
fprintf(pFile, "%.2f ", pTemp2->dbstudent[i]);
}
fprintf(pFile, "\n");
pTemp2 = pTemp2->pNext;
}
//关闭文件
fclose(pFile);
printf("----------已输入文件---------\n");
break;
}
case 2:
{
pFile1 = fopen("playerGrade.dat", "w");
if (NULL == pFile1)
{
printf("文件打开失败.\n");
return;
}
while (pTemp2 != NULL)
{
//保存姓名编号
fprintf(pFile1, "%s : %s ", pTemp2->arrPlayerNumber, pTemp2->arrPlayername);
//保存选手得分
fprintf(pFile1, "%s ", "得分:");
for (i = 0; i < 10; i++)
{
fprintf(pFile1, "%.2f ", pTemp2->dbstudent[i]);
}
fprintf(pFile1, "%s%d", "排名: ", a[j++]);
fprintf(pFile1, "%s", "\n");
pTemp2 = pTemp2->pNext;
i++;
}
//关闭文件
fclose(pFile1);
printf("----------已输入文件---------\n");
break;
}
case 3:
{
break;
}
}
}
这里就简单截图来看看这样的输入文件是什么格式
编号涉及个人信息,就不给出来了。这样看是不是就比较有顺序一点。
void PrintOriAndFinal()
{
//打印最初的和最终的文件内容
int j = 0, k = 0; //循环变量
double SavePlayer[1000] = {
0 }; //存储数据
FILE* pFile = NULL; //输出原始文件
FILE* pFile1 = NULL; //输出排名后的文件
pFile = fopen("playerOriginal.dat", "r");//当然是用r打开了
pFile1 = fopen("playerGrade.dat", "r");
//字符串用来存储读出的数据,估计估计自己一行有多少字符串,然后设大一点,就okok了
char str1[200] = {
0 };
char str2[200] = {
0 };
printf("~~~~~~~~~~~~~~~~~~~~~排列后的数据~~~~~~~~~~~~~~~~~~~~~:\n");
//这里因为不要求什么读取文件到链表中,所以直接一行一行读取就行了
while (fgets(str1, 200, pFile1) != NULL)
{
k = 0;
printf(str1);//输出读取的字符串
//注意,这里清空字符串是为了防止上一次读出的数据有残留
//设想一下,读出的字符串是不是有时候长度不一,那么不请空有什么影响?影响大了,首先输出就有问题,万一长度不一样,你想想,新读出的字符串能保证覆盖原有字符串吗?不可能吧,那么输出的时候就会有影响了。
while (str1[k] != '\0') //清空
{
str1[k] = 0;
k++;
}
}
printf("~~~~~~~~~~~~~~~~~~~~~初始数据~~~~~~~~~~~~~~~~~~~~~:\n");
while (fgets(str2, 200, pFile) != NULL)
{
k = 0; //赋值为0
printf("%s\n", str2);
while (str2[k] != '\0') //清空
{
str2[k] = 0;
k++;
}
}
}
//找回删除的选手信息
void ReadFileToFindDelte(char* PointNum)
{
int Filerecord = 0; //记录观察是否找回
int j = 0, k = 0; //循环变量
FILE* pFile = NULL;
pFile = fopen("DeleteStudentDate.dat", "r");
if (pFile == NULL)
{
printf("打开文件失败!\n");
return;
}
char c = 0; //装其他字符
char d = 0; //装其他字符
char str1[100] = {
0 }; //读出编号
char str2[100] = {
0 }; //读出姓名
char str3[100] = {
0 }; //读出其他字符
char str4[100] = {
0 }; //读出其他字符
char str5[100] = {
0 }; //读出其他字符
double FileDate[10] = {
0 }; //读出文件数据
//这里就有意思了,这也就是为什么前面用fprintf的原因,看!这格式不久有用了吗,看那个文件,四个%s分别读出四个字符串,第一个字符串就是我们要的编号。为什么?因为这个读出是遇到空格停下,所以看文件,格式是:字符串1 :字符串3 字符串4 得分....,字符串2去哪了?字符串2就是那个":",在这里面:也是一个字符串。
//那么再来说说其他读出的函数,首先排除了fread,根据字节读出太难控制了。然后是fgets,也许你会说,我可以把姓名,编号,分数放在不同行。但是那样会不会太难看了,首先你的分数就要10行了,一个文件这么放数据,先不说代码有什么问题,首先规范整洁就是一个1大问题。然后就是代码读出的问题了,我也是试过这么干,但是每次读出字符串最后总会乱码,原因我也不清楚,可能是因为没清空字符串导致,但是读出了又要考虑清空,好麻烦的,而且万一你的名字和编号读在同一行,怎么分开也是个大问题,虽然算法可以搞定需求,但是写代码不就是为了简洁有效吗,那为什么不直接fscanf。
while (fscanf(pFile, "%s%s%s%s%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", str1, str2, str3, str4, &FileDate[0], &FileDate[1], &FileDate[2], &FileDate[3], &FileDate[4], &FileDate[5], &FileDate[6], &FileDate[7], &FileDate[8], &FileDate[9]) != EOF)
{
//判断是不是需要的选手,你可能注意到了,这里str3装着的是名字,所以这是按名字恢复
if (strcmp(str3, PointNum) == 0)
{
struct PlayerNode* pTemp = malloc(sizeof(struct PlayerNode));
strcpy(pTemp->arrPlayerNumber, str1);
strcpy(pTemp->arrPlayername, str3);
for (j = 0; j < 10; j++)
{
pTemp->dbstudent[j] = FileDate[j];
}
pTemp->pNext = NULL;
//这里就是第一个函数的操作了,加进链表,只是这里多了字符串清空
//作为第一个节点
if (NULL == g_pEnd || NULL == g_pHead)
{
g_pEnd = pTemp;
g_pHead = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
Filerecord++;
recordPl++;
printf("已找回!\n");
continue;
}
//作为新增其他节点
else
{
struct PlayerNode* pT1, * pT2;
pT1 = g_pHead;
pT2 = NULL;
//当需要插入的节点的编号比头节点大
while (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) > 0 && pT1->pNext != NULL)
{
pT2 = pT1;
pT1 = pT1->pNext;
}
//找到了,在pT1前面加
if (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) <= 0)
{
//找到的是头节点
if (g_pHead == pT1)
{
pTemp->pNext = g_pHead;
g_pHead = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
Filerecord++;
recordPl++;
printf("已找回!\n");
continue;
}
//找到的节点不是头节点
else
{
pT2->pNext = pTemp;
pTemp->pNext = pT1;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
Filerecord++;
recordPl++;
printf("已找回!\n");
continue;
}
}
//找不到比插入节点编号更大的
else
{
pT1->pNext = pTemp;
pTemp->pNext = NULL;
g_pEnd = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
Filerecord++;
recordPl++;
printf("已找回!\n");
continue;
}
}
}
//不是就继续读
else
{
continue;
}
}
if (Filerecord == 0)
printf("你需要恢复的选手不存在,请检查名字是否输入错误\n");
}
总体说一下吧,这里的文件操作特别需要注意格式,否则,代码100行,调试2小时不是梦!!!
简述:首先,你肯定不想要一个一个信息输入吧,那么提前把数据输入文件,然后一键读取,多方便
case 15:
{
int nOrderFile = 0;
printf("-------------------------------------------从文件中读取选手信息构成链表-------------------------------------------------------\n");
printf("***你是否需要从文件中读取信息到链表中然后继续操作(选择读取之后链表将会同步更新上一次存的初始数据)***\n");
printf("¥¥¥1.选择继续\n¥¥¥2.退出\n请输入指令:");
scanf("%d", &nOrderFile);
if (nOrderFile == 1)
{
ReadFromFile();
break;
}
else
{
break;
}
}
void ReadFromFile()
{
int j = 0, k = 0; //循环变量
FILE* pFile = NULL;
pFile = fopen("playerOriginal.dat", "r");
if (pFile == NULL)
{
printf("打开文件失败!\n");
return;
}
char c = 0; //装其他字符
char d = 0; //装其他字符
char str1[100] = {
0 }; //读出编号
char str2[100] = {
0 }; //读出姓名
char str3[100] = {
0 }; //读出其他字符
char str4[100] = {
0 }; //读出其他字符
char str5[100] = {
0 }; //读出其他字符
double FileDate[10] = {
0 }; //读出文件数据
while (fscanf(pFile, "%s%s%s%s%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", str1, str2, str3, str4, &FileDate[0], &FileDate[1], &FileDate[2], &FileDate[3], &FileDate[4], &FileDate[5], &FileDate[6], &FileDate[7], &FileDate[8], &FileDate[9]) != EOF)
{
recordPl++;
struct PlayerNode* pTemp = malloc(sizeof(struct PlayerNode));
strcpy(pTemp->arrPlayerNumber, str1);
strcpy(pTemp->arrPlayername, str3);
for (j = 0; j < 10; j++)
{
pTemp->dbstudent[j] = FileDate[j];
}
pTemp->pNext = NULL;
//作为第一个节点
if (NULL == g_pEnd || NULL == g_pHead)
{
g_pEnd = pTemp;
g_pHead = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
continue;
}
//作为新增其他节点
else
{
struct PlayerNode* pT1, * pT2;
pT1 = g_pHead;
pT2 = NULL;
//当需要插入的节点的编号比头节点大
while (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) > 0 && pT1->pNext != NULL)
{
pT2 = pT1;
pT1 = pT1->pNext;
}
//找到了,在pT1前面加
if (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) <= 0)
{
//找到的是头节点
if (g_pHead == pT1)
{
pTemp->pNext = g_pHead;
g_pHead = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
continue;
}
//找到的节点不是头节点
else
{
pT2->pNext = pTemp;
pTemp->pNext = pT1;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
continue;
}
}
//找不到比插入节点编号更大的
else
{
pT1->pNext = pTemp;
pTemp->pNext = NULL;
g_pEnd = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
continue;
}
}
}
printf("已从文件中读取信息!");
return;
}
这不跟上面恢复删除的选手所用的读取方法是一样的?所以就不多说了
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
//清空链表
void FreeLinkDate(void);
//输出管理员的界面
void Adminiprint(void);
//输出学生使用的界面
void Playerprint(void);
//输出所有的选手的信息(包含排名)
void ShowPlayerDateAddRank(void);
//添加选手信息
void AddPlayerMSG(char arrPlayername[10], char arrPlayNum[10], double* p_score);
//查看所有选手的数据
void ShowDate(void);
//查找指定编号的选手
struct PlayerNode* FindPlayByNum(char* PlayerNum);
//删除指定选手的信息
void DeletePlayerMSG(struct PlayerNode* pNode);
//修改指定选手的函数
void ChangePlayerDate(struct PlayerNode* pT);
//查看排名
struct PlayerNode* LookPointedPlayer_Rank(char* arrApointer);
//求节点平均值(去掉最高最低分)
double Average(struct PlayerNode* pTemp);
//交换节点数据
void ExPlayerNode(struct PlayerNode* pNode1, struct PlayerNode* pNode2);
//保存信息到文件
void SavePlayToFile();
//输出初始文件和最终文件
void PrintOriAndFinal();
//从文件中读取
void ReadFromFile();
//将删除的选手存入文件
void SavePlayToFileByOne(struct PlayerNode* pT);
//从文件中找到删除的选手并恢复
void ReadFileToFindDelte(char* PointNum);
struct PlayerNode
{
char arrPlayername[20];
char arrPlayerNumber[20];
double dbstudent[10];
struct PlayerNode* pNext;
};
//声明全局变量头和尾
struct PlayerNode* g_pHead;
struct PlayerNode* g_pEnd;
//循环控制符
int i;
//记录有多少位选手
int recordPl;
//记录有多少位删除的选手
int RecordDelete;
int main(void)
{
printf("|----------------------------------------------------------|\n");
printf("| |\n");
printf("| |\n");
printf("| |\n");
printf("| 选手密码:******** 管理员密码:123456789 |\n");
printf("|*************** 欢迎使用选手评分系统 *****************|\n");
printf("|**** 请根据你的身份选择管理员登录或者选手输入密码登录 ****|\n");
printf("| |\n");
printf("| |\n");
printf("| |\n");
printf("|----------------------------------------------------------|\n");
int nOrderAdmini = -1; //管理员指令
int nOrderPlay = -1; //选手指令
char arrPassword[20] = {
0 }; //密码
char arrPlname[20] = {
0 }; //选手名字
char arrPlNum[20] = {
0 }; //编号
double dbPlScore[10] = {
0 }; //分数
int nFlag = 1; //退出循环的标示
while (1)
{
printf("1、输入密码登陆.\n2、输入0退出系统.\n请根据需要输入密码或指令0:\n");
printf("|-----------------------------------------------------------|\n");
printf("|------选手密码:********\t管理员密码:123456789-------|\n");
printf("|-----------------------------------------------------------|\n");
scanf("%s", arrPassword); //输入密码
if (strcmp(arrPassword, "123456789") == 0) //判断是否是管理员系统
{
printf("你已经登录管理员系统\n");
Adminiprint();
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
printf("~~~~~~PS:如果需要从文件中读取初始学生,请选择指令15,然后继续操作(建议一开始选择)~~~~~~\n");
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
nFlag = 1;
while (nFlag)
{
printf("请输入指令(请不要输入字符,输入11查看指令):");
scanf("%d", &nOrderAdmini);
switch (nOrderAdmini)
{
case 1:
{
printf("------------------------输入一个选手信息----------------------------\n");
//人数++
recordPl++;
printf("该选手的名字是:\n");
scanf("%s", arrPlname);
printf("该选手的编号是:\n");
scanf("%s", arrPlNum);
printf("10位评委的打分(请一次输入10个分数)\n");
for (i = 0; i < 10; i++)
{
scanf("%lf", &dbPlScore[i]);
}
//调用函数添加
AddPlayerMSG(arrPlname, arrPlNum, dbPlScore);
break;
}
case 2:
{
printf("-----------------------查找指定选手信息---------------------------\n");
//查找指定编号的选手的信息
struct PlayerNode* pT = NULL;
printf("请输入要查找的选手的编号:\n");
scanf("%s", arrPlNum);
pT = FindPlayByNum(arrPlNum);
if (pT != NULL)
{
printf("已找到");
printf("\n");
printf("该选手的编号和名字是:\n");
printf("%s:%s\n", pT->arrPlayerNumber, pT->arrPlayername);
printf("该选手的得分情况是:\n");
printf("分数1 分数2 分数3 分数4 分数5 分数6 份数7 分数8 分数9 分数10\n");
for (i = 0; i < 10; i++)
{
printf("%.2f ", pT->dbstudent[i]);
}
printf("\n");
}
break;
}
case 3:
{
recordPl--;
printf("-------------------------删除退赛选手的信息-----------------------------\n");
//删除退赛的选手的信息
struct PlayerNode* pT = NULL;
printf("请输入要删除的选手的编号:\n");
scanf("%s", arrPlNum);
pT = FindPlayByNum(arrPlNum);
//判断pT是否找到
if (NULL != pT) //找到了
{
//存数据进文档
SavePlayToFileByOne(pT);
//调用函数
DeletePlayerMSG(pT);
}
break;
}
case 4:
{
printf("--------------------------排序----------------------------\n");
//判断是否需要排序
if (g_pHead == NULL || g_pHead == g_pEnd)
{
printf("数据过少,不需要排序,请添加选手信息.\n");
break;
}
struct PlayerNode* pT1, * pT2;
pT1 = g_pHead;
while (pT1 != NULL && pT1->pNext->pNext != NULL)
{
pT2 = pT1->pNext;
while (pT2 != NULL)
{
if (Average(pT1) < Average(pT2)) //比较平均分
{
ExPlayerNode(pT1, pT2); //交换节点
}
pT2 = pT2->pNext;
}
pT1 = pT1->pNext;
}
if (pT1->pNext->pNext == NULL)
{
pT2 = pT1->pNext;
ExPlayerNode(pT1, pT2);
}
printf("已按成绩高低从大到小排序\n");
break;
}
case 5:
{
printf("------------------------查看排序----------------------------\n");
printf("~~~建议按分数从高到低排序后查看,你是否确定你已经排好序了?\n");
printf("如果选择继续,请输入1,否则输入其他任意数字退出\n");
int recordPoint;
scanf("%d", &recordPoint);
if (recordPoint == 1)
{
ShowPlayerDateAddRank();
break;
}
else
{
break;
}
}
case 6:
{
printf("---------------------------查看所有选手的数据---------------------------\n");
//查看所有选手的数据
ShowDate();
break;
}
case 7:
{
printf("------------------------查看指定选手的排名--------------------------\n");
int nRank = 0; //排名
struct PlayerNode* pTemp;
pTemp = g_pHead;
printf("请输入你想查找的选手的编号:\n");
char arrApointerNum[20]; //需要查找的选手
scanf("%s", arrApointerNum);
struct PlayerNode* pFindByNum = LookPointedPlayer_Rank(arrApointerNum);
if (pFindByNum == NULL)
break;
else
{
while (pTemp != NULL)
{
//排名加一
nRank++;
//循环查找排名
if (pTemp == pFindByNum)
{
printf("该选手的排名是:%d\n", nRank);
nRank = 0;
break;
}
pTemp = pTemp->pNext;
}
nRank = 0;
break;
}
}
case 8:
{
printf("---------------------------保存信息进文件----------------------------\n");
SavePlayToFile();
break;
}
case 9:
{
printf("---------------------------输出最初和最终的结果----------------------------\n");
PrintOriAndFinal();
break;
}
case 10:
{
char PointNum[20] = {
0 };
printf("输入你需要找回的选手的姓名:\n");
scanf("%s", PointNum);
ReadFileToFindDelte(PointNum);
break;
}
case 11:
{
printf("---------------------------显示指令界面---------------------------\n");
Adminiprint();
break;
}
case 12:
{
printf("-----------------------------退出系统------------------------------\n");
printf("---------------------------感谢你的使用-----------------------------\n");
exit(0);
break;
}
case 13:
{
recordPl = 0;
printf("-----------------------------删除所有选手的信息-----------------------------\n");
FreeLinkDate();
printf("~~~~已完全删除~~~~\n");
break;
}
case 14:
{
char arrChangeNum[20] = {
0 };
printf("-----------------------------修改指定选手的数据(根据编号)-----------------------------\n");
printf("输入需要修改的选手的编号:");
scanf("%s", arrChangeNum);
struct PlayerNode* ChangeDate = FindPlayByNum(arrChangeNum);
if (ChangeDate == NULL)
{
break;
}
else
{
printf("找到了!\n");
ChangePlayerDate(ChangeDate);
break;
}
}
case 15:
{
int nOrderFile = 0;
printf("-------------------------------------------从文件中读取选手信息构成链表-------------------------------------------------------\n");
printf("***你是否需要从文件中读取信息到链表中然后继续操作(选择读取之后链表将会同步更新上一次存的初始数据)***\n");
printf("¥¥¥1.选择继续\n¥¥¥2.退出\n请输入指令:");
scanf("%d", &nOrderFile);
if (nOrderFile == 1)
{
ReadFromFile();
break;
}
else
{
break;
}
}
case 16:
{
printf("当前链表中的选手的个数:%d\n", recordPl);
break;
}
case 0:
{
printf("------------------------------退出登录------------------------------\n");
printf("你已经退出登录,若要继续登录操作,请输入密码,否则输入0退出系统!\n");
//标识符赋值0
nFlag = 0;
break;
}
default:
{
printf("你输入的参数指令不合法\n");
break;
}
}
}
}
else if (strcmp(arrPassword, "********") == 0) //判断是否是选手系统
{
int nPlayerFlag = 1;
printf("你已经登录选手系统\n\n");
Playerprint();
while (nPlayerFlag)
{
printf("请输入指令(请不要输入字符):");
scanf("%d", &nOrderPlay);
switch (nOrderPlay)
{
case 1:
{
//查找指定编号的选手的信息
struct PlayerNode* pT = NULL;
printf("请输入你的编号:\n");
scanf("%s", arrPlNum);
pT = FindPlayByNum(arrPlNum);
if (pT != NULL)
{
printf("已找到");
printf("\n");
printf("该选手的编号和名字是:\n");
printf("%s:%s\n", pT->arrPlayerNumber, pT->arrPlayername);
printf("该选手的得分情况是:\n");
printf("分数1 分数2 分数3 分数4 分数5 分数6 分数7 分数8 分数9 分数10\n");
for (i = 0; i < 10; i++)
{
printf("%.2f ", pT->dbstudent[i]);
}
printf("\n");
}
break;
}
case 2:
{
int nRank = 0; //排名
struct PlayerNode* pTemp;
pTemp = g_pHead;
printf("请输入你的编号:\n");
char arrApointerNum[20]; //需要查找的选手
scanf("%s", arrApointerNum);
struct PlayerNode* pFindByNum = LookPointedPlayer_Rank(arrApointerNum);
if (pFindByNum == NULL)
break;
else
{
while (pTemp != NULL)
{
//排名加一
nRank++;
//循环查找排名
if (pTemp == pFindByNum)
{
printf("该选手的排名是:%d\n", nRank);
nRank = 0;
break;
}
pTemp = pTemp->pNext;
}
nRank = 0;
break;
}
}
case 3:
{
printf("你已经退出登录,若要继续登录操作,请输入密码,否则输入0退出系统,谢谢配合!\n");
//标识符赋值0
nPlayerFlag = 0;
break;
}
case 4:
{
exit(0);
break;
}
default:
{
printf("输入指令有误!请重新输入.");
break;
}
}
}
}
else if (strcmp(arrPassword, "0") == 0)
{
printf("---------------------------感谢你的使用-----------------------------\n");
exit(0);
}
else //密码错误
{
int nChoose;
printf("密码错误,你可以选择继续登录(输入1)或者退出该系统(输入其他任意数字)\n");
scanf("%d", &nChoose);
if (nChoose == 1)
continue;
else
printf("---------------------------感谢你的使用-----------------------------\n");
exit(0);
}
}
FreeLinkDate(); //释放链表
system("pause>0");
return 0;
}
void FreeLinkDate(void)
{
if (NULL == g_pHead)
{
printf("链表为空,无需清空\n");
}
struct PlayerNode* pTemp = g_pHead; //记住头
while (g_pHead != NULL)
{
pTemp = g_pHead;
g_pHead = g_pHead->pNext; //头指向下一个
free(pTemp); //释放节点
}
}
void Playerprint(void)
{
printf("------------------------------------------------------------------\n");
printf("------------------------------------------------------------------\n");
printf("********************** 比赛评分系统(学生专用) *********************\n");
printf("*********************** 本系统操作指令如下 *************************\n");
printf("*** 1.查看成绩 ***\n");
printf("*** 2.查看排名 ***\n");
printf("*** 3.退出登陆 ***\n");
printf(" 4.退出系统 ***\n");
printf("******************************************************************\n");
printf("------------------------------------------------------------------\n");
printf("------------------------------------------------------------------\n");
}
void Adminiprint(void)
{
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("*** 12.退出系统 ***\n ");
printf("*** 13.删除所有选手的信息 ***\n ");
printf("*** 14.修改指定选手的信息 ***\n ");
printf("*** 15.从文件中读取信息进链表 ***\n ");
printf("*** 16.查看当前链表中有多少个选手 ***\n ");
printf("*** 0.退出登陆 ***\n ");
printf("*****************************************************************************\n");
}
void AddPlayerMSG(char arrPlayername[10], char arrPlayNum[10], double* p_score)
{
if (arrPlayername == NULL && arrPlayNum == NULL || p_score == NULL)
{
printf("选手信息输入错误.\n");
return;
}
struct PlayerNode* pTemp = malloc(sizeof(struct PlayerNode));
if (pTemp != NULL)
{
strcpy(pTemp->arrPlayername, arrPlayername);
strcpy(pTemp->arrPlayerNumber, arrPlayNum);
for (i = 0; i < 10; i++)
{
pTemp->dbstudent[i] = *(p_score + i);
}
pTemp->pNext = NULL;
//作为第一个节点
if (NULL == g_pEnd || NULL == g_pHead)
{
g_pEnd = pTemp;
g_pHead = pTemp;
return;
}
//作为新增其他节点
else
{
struct PlayerNode* pT1, * pT2;
pT1 = g_pHead;
pT2 = NULL;
//当需要插入的节点的编号比头节点大
while (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) > 0 && pT1->pNext != NULL)
{
pT2 = pT1;
pT1 = pT1->pNext;
}
//找到了,在pT1前面加
if (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) <= 0)
{
//找到的是头节点
if (g_pHead == pT1)
{
pTemp->pNext = g_pHead;
g_pHead = pTemp;
return;
}
//找到的节点不是头节点
else
{
pT2->pNext = pTemp;
pTemp->pNext = pT1;
return;
}
}
//找不到比插入节点编号更大的
else
{
pT1->pNext = pTemp;
pTemp->pNext = NULL;
g_pEnd = pTemp;
}
}
}
}
void ShowDate(void)
{
struct PlayerNode* pTemp = g_pHead; //防止头改变
if (g_pHead == NULL)
{
printf("该链表无数据!");
}
while (pTemp != NULL)
{
printf("\n");
printf("该选手的编号和名字是:\n");
printf("%s:%s\n", pTemp->arrPlayerNumber, pTemp->arrPlayername);
printf("该选手的得分情况是:\n");
printf("分数1 分数2 分数3 分数4 分数5 分数6 分数7 分数8 分数9 分数10\n");
for (i = 0; i < 10; i++)
{
printf("%.2f ", pTemp->dbstudent[i]);
}
printf("\n该选手的平均分是:%.2f", Average(pTemp));
printf("\n");
pTemp = pTemp->pNext;
}
printf("\n");
return;
}
struct PlayerNode* FindPlayByNum(char* PlayerNum)
{
struct PlayerNode* pTemp = g_pHead;
//检查参数合法性
if (PlayerNum == NULL)
{
printf("选手编号输入错误,请检查编号输入\n");
return NULL;
}
if (NULL == g_pHead || NULL == g_pEnd)
{
printf("链表为空,请检查");
return NULL;
}
while (pTemp != NULL)
{
//比较是否是需要的节点
if (0 == strcmp(pTemp->arrPlayerNumber, PlayerNum))
{
return pTemp;
}
pTemp = pTemp->pNext;
}
//没找到
printf("没找到选手的编号,请检查是否输入错误.\n");
return NULL;
}
void DeletePlayerMSG(struct PlayerNode* pNode)
{
//只有一个节点
if (g_pHead == g_pEnd)
{
free(g_pHead);
g_pHead = NULL;
g_pEnd = NULL;
return;
}
//两个节点
else if (g_pHead->pNext == g_pEnd)
{
if (g_pHead == pNode) //找到的是头节点
{
free(g_pHead);
g_pHead = g_pEnd;
return;
}
else
{
free(g_pEnd);
g_pEnd = g_pHead;
g_pEnd->pNext = NULL; //一定要赋值NULL
return;
}
}
//节点多于3个
else
{
struct PlayerNode* 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 (pTemp->pNext == g_pEnd)
{
free(g_pEnd);
g_pEnd = pTemp;
g_pEnd->pNext = NULL;
return;
}
//删除的不是尾节点
else
{
//记住要删除的节点
struct PlayerNode* pT = pTemp->pNext;
if (pT != NULL)
{
pTemp->pNext = pT->pNext;
free(pT);
pT = NULL;
return;
}
}
}
pTemp = pTemp->pNext;
}
}
}
void ChangePlayerDate(struct PlayerNode* pT)
{
int j = 0; //循环变量
int ChangeScoreNum; //要修改第几个得分
int ChangeOrder; //操作指令
int ChangeOrderScore; //修改分数的指令
char ChangeName[20] = {
0 };
printf("请输入你要修改的数据:\n");
printf("~~~1.修改姓名\n~~~2.修改得分\n~~~3.退出修改\n");
scanf("%d", &ChangeOrder);
switch (ChangeOrder)
{
case 1:
{
printf("请输入修改后的姓名:\n");
scanf("%s", ChangeName);
strcpy(pT->arrPlayername, ChangeName);
printf("~~~已修改完毕~~~");
break;
}
case 2:
{
printf("|----------------------------------------------------------------------------------------------------------------------------------------------------|\n");
printf("|该选手的编号和名字是: |\n");
printf(" %s:%s \n", pT->arrPlayerNumber, pT->arrPlayername);
printf(" 该选手的得分情况是:\n");
for (j = 0; j < 10; j++)
{
printf(" Score%d:", j + 1);
printf("%.2f ", pT->dbstudent[j]);
}
printf("\n");
printf("|----------------------------------------------------------------------------------------------------------------------------------------------------|");
printf("\n");
printf("请输入你要修改一个还是全部得分\n");
printf("~~~10.全部\n");
printf("~~~01.一个\n");
scanf("%d", &ChangeOrderScore);
if (ChangeOrderScore == 10)
{
printf("请重新输入得分:\n");
for (j = 0; j < 10; j++)
{
printf("Score %d:", j + 1);
scanf("%lf", &pT->dbstudent[j]);
printf("~~~~~~~已修改~~~~~~~\n");
}
}
if (ChangeOrderScore == 01)
{
printf("请输入你要修改第几个得分(1-10):");
scanf("%d", &ChangeScoreNum);
printf("请输入修改后的得分:");
scanf("%lf", &pT->dbstudent[ChangeScoreNum - 1]);
printf("~~~~~~~已修改~~~~~~~\n");
}
break;
}
case 3:
{
break;
}
}
return;
}
void ShowPlayerDateAddRank(void)
{
int j = 1;
struct PlayerNode* pTemp = g_pHead; //防止头改变
if (g_pHead == NULL)
{
printf("该链表无数据!");
}
while (pTemp != NULL)
{
printf("\n");
printf("该选手的编号和名字是:\n");
printf("%s:%s\n", pTemp->arrPlayerNumber, pTemp->arrPlayername);
if (j <= recordPl)
{
printf("排名:%d\n", j++);
}
printf("该选手的得分情况是:\n");
printf("分数1 分数2 分数3 分数4 分数5 分数6 分数7 分数8 分数9 分数10\n");
for (i = 0; i < 10; i++)
{
printf("%.2f ", pTemp->dbstudent[i]);
}
printf("\n该选手的平均分是:%.2f", Average(pTemp));
printf("\n");
pTemp = pTemp->pNext;
}
printf("\n");
return;
}
void SavePlayToFile()
{
int a[1000] = {
0 };
int i, j = 0;
for (i = 0; i < recordPl; i++)
{
a[i] = i + 1;
}
struct PlayerNode* pTemp1 = g_pHead;
struct PlayerNode* pTemp2 = g_pHead;
int nFileOrder = 0;
printf("---------写入文件---------\n");
printf("~~1、初始存入\n~~2、排序后存入:\n~~3、取消该指令\n");
printf("~~~请输入存储类型(1、2或3):\n");
scanf("%d", &nFileOrder);
FILE* pFile = NULL;
FILE* pFile1 = NULL;
//判断链表是否为NULL
if (g_pHead == NULL)
{
printf("----没有选手信息----\n");
return;
}
//写入文件
switch (nFileOrder)
{
case 1:
{
pFile = fopen("playerOriginal.dat", "w");
if (NULL == pFile)
{
printf("文件打开失败.\n");
return;
}
while (pTemp2 != NULL)
{
//保存姓名编号
fprintf(pFile, "%s : %s ", pTemp2->arrPlayerNumber, pTemp2->arrPlayername);
//保存选手得分
fprintf(pFile, "%s", "得分: ");
for (i = 0; i < 10; i++)
{
fprintf(pFile, "%.2f ", pTemp2->dbstudent[i]);
}
fprintf(pFile, "\n");
pTemp2 = pTemp2->pNext;
}
//关闭文件
fclose(pFile);
printf("----------已输入文件---------\n");
break;
}
case 2:
{
pFile1 = fopen("playerGrade.dat", "w");
if (NULL == pFile1)
{
printf("文件打开失败.\n");
return;
}
while (pTemp2 != NULL)
{
//保存姓名编号
fprintf(pFile1, "%s : %s ", pTemp2->arrPlayerNumber, pTemp2->arrPlayername);
//保存选手得分
fprintf(pFile1, "%s ", "得分:");
for (i = 0; i < 10; i++)
{
fprintf(pFile1, "%.2f ", pTemp2->dbstudent[i]);
}
fprintf(pFile1, "%s%d", "排名: ", a[j++]);
fprintf(pFile1, "%s", "\n");
pTemp2 = pTemp2->pNext;
i++;
}
//关闭文件
fclose(pFile1);
printf("----------已输入文件---------\n");
break;
}
case 3:
{
break;
}
}
}
void PrintOriAndFinal()
{
int j = 0, k = 0; //循环变量
double SavePlayer[1000] = {
0 }; //存储数据
FILE* pFile = NULL; //输出原始文件
FILE* pFile1 = NULL; //输出排名后的文件
pFile = fopen("playerOriginal.dat", "r");
pFile1 = fopen("playerGrade.dat", "r");
char str1[200] = {
0 };
char str2[200] = {
0 };
printf("~~~~~~~~~~~~~~~~~~~~~排列后的数据~~~~~~~~~~~~~~~~~~~~~:\n");
while (fgets(str1, 200, pFile1) != NULL)
{
k = 0;
printf(str1);
while (str1[k] != '\0') //清空
{
str1[k] = 0;
k++;
}
}
printf("~~~~~~~~~~~~~~~~~~~~~初始数据~~~~~~~~~~~~~~~~~~~~~:\n");
while (fgets(str2, 200, pFile) != NULL)
{
k = 0; //赋值为0
printf("%s\n", str2);
while (str2[k] != '\0') //清空
{
str2[k] = 0;
k++;
}
}
}
void ReadFromFile()
{
int j = 0, k = 0; //循环变量
FILE* pFile = NULL;
pFile = fopen("playerOriginal.dat", "r");
if (pFile == NULL)
{
printf("打开文件失败!\n");
return;
}
char c = 0; //装其他字符
char d = 0; //装其他字符
char str1[100] = {
0 }; //读出编号
char str2[100] = {
0 }; //读出姓名
char str3[100] = {
0 }; //读出其他字符
char str4[100] = {
0 }; //读出其他字符
char str5[100] = {
0 }; //读出其他字符
double FileDate[10] = {
0 }; //读出文件数据
while (fscanf(pFile, "%s%s%s%s%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", str1, str2, str3, str4, &FileDate[0], &FileDate[1], &FileDate[2], &FileDate[3], &FileDate[4], &FileDate[5], &FileDate[6], &FileDate[7], &FileDate[8], &FileDate[9]) != EOF)
{
recordPl++;
struct PlayerNode* pTemp = malloc(sizeof(struct PlayerNode));
strcpy(pTemp->arrPlayerNumber, str1);
strcpy(pTemp->arrPlayername, str3);
for (j = 0; j < 10; j++)
{
pTemp->dbstudent[j] = FileDate[j];
}
pTemp->pNext = NULL;
//作为第一个节点
if (NULL == g_pEnd || NULL == g_pHead)
{
g_pEnd = pTemp;
g_pHead = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
continue;
}
//作为新增其他节点
else
{
struct PlayerNode* pT1, * pT2;
pT1 = g_pHead;
pT2 = NULL;
//当需要插入的节点的编号比头节点大
while (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) > 0 && pT1->pNext != NULL)
{
pT2 = pT1;
pT1 = pT1->pNext;
}
//找到了,在pT1前面加
if (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) <= 0)
{
//找到的是头节点
if (g_pHead == pT1)
{
pTemp->pNext = g_pHead;
g_pHead = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
continue;
}
//找到的节点不是头节点
else
{
pT2->pNext = pTemp;
pTemp->pNext = pT1;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
continue;
}
}
//找不到比插入节点编号更大的
else
{
pT1->pNext = pTemp;
pTemp->pNext = NULL;
g_pEnd = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
continue;
}
}
}
printf("已从文件中读取信息!");
return;
}
void SavePlayToFileByOne(struct PlayerNode* pT)
{
RecordDelete++;
int i = 0;
struct PlayerNode* pTemp = pT;
FILE* pFile = NULL;
//写入文件
if (RecordDelete == 1)
{
pFile = fopen("DeleteStudentDate.dat", "w");
if (NULL == pFile)
{
printf("文件打开失败.\n");
return;
}
//保存姓名编号
fprintf(pFile, "%s : %s ", pTemp->arrPlayerNumber, pTemp->arrPlayername);
//保存选手得分
fprintf(pFile, "%s", "得分: ");
for (i = 0; i < 10; i++)
{
fprintf(pFile, "%.2f ", pTemp->dbstudent[i]);
}
fprintf(pFile, "\n");
//关闭文件
fclose(pFile);
printf("已将删除的选手的信息传入文档,如果需要恢复,请输入指令10\n");
}
if (RecordDelete >= 2)
{
pFile = fopen("DeleteStudentDate.dat", "a+");
if (NULL == pFile)
{
printf("文件打开失败.\n");
return;
}
//保存姓名编号
fprintf(pFile, "%s : %s ", pTemp->arrPlayerNumber, pTemp->arrPlayername);
//保存选手得分
fprintf(pFile, "%s", "得分: ");
for (i = 0; i < 10; i++)
{
fprintf(pFile, "%.2f ", pTemp->dbstudent[i]);
}
fprintf(pFile, "\n");
//关闭文件
fclose(pFile);
printf("已将删除的选手的信息传入文档,如果需要恢复,请输入指令10\n");
}
}
void ReadFileToFindDelte(char* PointNum)
{
int Filerecord = 0; //记录观察是否找回
int j = 0, k = 0; //循环变量
FILE* pFile = NULL;
pFile = fopen("DeleteStudentDate.dat", "r");
if (pFile == NULL)
{
printf("打开文件失败!\n");
return;
}
char c = 0; //装其他字符
char d = 0; //装其他字符
char str1[100] = {
0 }; //读出编号
char str2[100] = {
0 }; //读出姓名
char str3[100] = {
0 }; //读出其他字符
char str4[100] = {
0 }; //读出其他字符
char str5[100] = {
0 }; //读出其他字符
double FileDate[10] = {
0 }; //读出文件数据
while (fscanf(pFile, "%s%s%s%s%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", str1, str2, str3, str4, &FileDate[0], &FileDate[1], &FileDate[2], &FileDate[3], &FileDate[4], &FileDate[5], &FileDate[6], &FileDate[7], &FileDate[8], &FileDate[9]) != EOF)
{
//判断是不是需要的选手
if (strcmp(str3, PointNum) == 0)
{
struct PlayerNode* pTemp = malloc(sizeof(struct PlayerNode));
strcpy(pTemp->arrPlayerNumber, str1);
strcpy(pTemp->arrPlayername, str3);
for (j = 0; j < 10; j++)
{
pTemp->dbstudent[j] = FileDate[j];
}
pTemp->pNext = NULL;
//作为第一个节点
if (NULL == g_pEnd || NULL == g_pHead)
{
g_pEnd = pTemp;
g_pHead = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
Filerecord++;
recordPl++;
printf("已找回!\n");
continue;
}
//作为新增其他节点
else
{
struct PlayerNode* pT1, * pT2;
pT1 = g_pHead;
pT2 = NULL;
//当需要插入的节点的编号比头节点大
while (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) > 0 && pT1->pNext != NULL)
{
pT2 = pT1;
pT1 = pT1->pNext;
}
//找到了,在pT1前面加
if (strcmp(pTemp->arrPlayerNumber, pT1->arrPlayerNumber) <= 0)
{
//找到的是头节点
if (g_pHead == pT1)
{
pTemp->pNext = g_pHead;
g_pHead = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
Filerecord++;
recordPl++;
printf("已找回!\n");
continue;
}
//找到的节点不是头节点
else
{
pT2->pNext = pTemp;
pTemp->pNext = pT1;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
Filerecord++;
recordPl++;
printf("已找回!\n");
continue;
}
}
//找不到比插入节点编号更大的
else
{
pT1->pNext = pTemp;
pTemp->pNext = NULL;
g_pEnd = pTemp;
//清空,排除干扰
for (k = 0; str1[k] != '\0'; k++)
{
str1[k] = 0;
}
for (k = 0; str3[k] != '\0'; k++)
{
str3[k] = 0;
}
for (k = 0; k < 10; k++)
{
FileDate[k] = 0;
}
Filerecord++;
recordPl++;
printf("已找回!\n");
continue;
}
}
}
//不是就继续读
else
{
continue;
}
}
if (Filerecord == 0)
printf("你需要恢复的选手不存在,请检查名字是否输入错误\n");
}
struct PlayerNode* LookPointedPlayer_Rank(char* arrApointer)
{
if (g_pHead == NULL && arrApointer == NULL)
{
printf("该链表没有节点或你输入的格式不对,请检查!\n");
return NULL;
}
//记住头
struct PlayerNode* pTemp = g_pHead;
while (NULL != pTemp)
{
if (strcmp(pTemp->arrPlayerNumber, arrApointer) == 0)
{
printf("~~~~找到了~~~~\n");
return pTemp;
}
pTemp = pTemp->pNext;
}
printf("~~~~没找到该编号对应的选手~~~~\n");
return NULL;
}
double Average(struct PlayerNode* pTemp)
{
double score[10] = {
0.0 };
int i = 0, j = 0;
double ScoreTemp, Scoresum = 0.0;
for (i = 0; i < 10; i++)
{
score[i] = pTemp->dbstudent[i];
}
for (i = 0; i < 9; i++)
{
for (j = i + 1; j < 10; j++)
{
if (score[j] > score[i])
{
ScoreTemp = score[j];
score[j] = score[i];
score[i] = ScoreTemp;
}
}
}
for (i = 1; i < 9; i++)
{
Scoresum += score[i];
}
return Scoresum * 1.0 / 8;
}
void ExPlayerNode(struct PlayerNode* pNode1, struct PlayerNode* pNode2)
{
char arrExchangeName[20] = {
0 };
char arrExchangeNum[20] = {
0 };
int i;
double nTempscore;
for (i = 0; i < 10; i++) //交换节点的分数
{
nTempscore = pNode1->dbstudent[i];
pNode1->dbstudent[i] = pNode2->dbstudent[i];
pNode2->dbstudent[i] = nTempscore;
}
//交换学号
strcpy(arrExchangeNum, pNode1->arrPlayerNumber);
strcpy(pNode1->arrPlayerNumber, pNode2->arrPlayerNumber);
strcpy(pNode2->arrPlayerNumber, arrExchangeNum);
//交换名字
strcpy(arrExchangeName, pNode1->arrPlayername);
strcpy(pNode1->arrPlayername, pNode2->arrPlayername);
strcpy(pNode2->arrPlayername, arrExchangeName);
return;
}
说实话,这个项目还是有很多不足的,比如有些功能重复了,有些代码根本没必要,比如那个清空字符串的,完全可以弄成一个函数,还有代码的格式规范,我觉得都是一个很大的问题。但其中也有文件操作,链表操作,对于一个c语言的小项目够用了。如果你有什么看法,欢迎评论,也可以提出哪里有优化。