问题描述
参加运动会有n个学校,学校编号为1~n。比赛分为m个男子项目,和w个女子项目。项目编号为男子1~m,女子m+1~m+w。不同的项目取前五名或前三名积分。取前五名的积分分别为:7、5、3、2、1;取前三名的积分分别为:5、3、2。哪些项目取前五名,哪些项目取前三名可自行设定。(m<=20,n<=20)
功能要求
(1)可以输入各个项目的前三名或前五名的成绩;
(2)能统计各学校总分;
(3)可以按学校编号或名称、学校总分、男女团体总分排序输出;
(4)可以按学校编号查询学校某个项目的情况;可以按项目编号查询前三名或前五名的学校。
(5)数据存入文件并能随时查询。
(6)规定
- 输入数据形式和范围:可以输入学校名称,运动项目名称。
- 输出形式:有中文提示,各学校分数为整数。
- 界面要求:有合理的提示,每个功能可以设立菜单,根据提示,可以完成相关的功能要求。
- 存储结构:根据系统功能要求袭击涉及,但是要求运动会的相关数据要存储在文件中。
- 测试数据:使用1、全部合法数据;2、整体非法数据;3、局部非法数据。进行测试,以保证程序的稳定性。
上代码:
#include <stdio.h>
#include <stdlib.h>
#define NAME 17 //字符数
#define NUMU 20
#define NUMP 20
#define H 5 //每一行输出的学校或项目数
FILE *fp;
const char wenjian[] = "system.txt"; //文件命名
typedef struct link
{
int gram[3][NUMP];//gram[0]存男生项目,gram[1]存女生项目,gram[2]存这个学校中男女在此项目上的总分
int sum[3];//sum[0]存男生总得分,sum[1]存女生总得分,sum[2]存学校总得分
}link;
typedef struct MESSAGE
{
int b[4]; // b[0-3]依次为(学校个数,项目个数,男生项目个数,女生项目个数
char xuexiao[NUMU][NAME];//学校名称
int sex[NUMU];//性别(区分男女子项目)
struct link spot[NUMU];//添加积分情况
int junction[NUMP];//决定取前三或前五
int count[NUMP][5];//项目的学校编号
char xiangmu[NUMP][NAME];//项目名称
} MESSAGE;
int junction[][5] = {{5, 3, 2, 0, 0}, {7, 5, 3, 2, 1}};
char sex[][3] = {"男", "女"};
char fenlei[][5] = {"男子", "女子", "学校"};
int gainint(int *p, int a, int b);//输入数据p,输入数据下限a,输入数据上限b
int gainchar(char A[], int min, int max);//输入字符A,输入字符数量下限min,输入字符数量上限max
int bijiao(char a[], char b[]);//等待进行匹配查找的字符串a,进行匹配查找的关键字b
void record(char school[][NAME], char game[][NAME], int b[], MESSAGE *temp);
int xianshi();
int jianyan(char b[], int T);//检验字符是否符合要求,T=0检验当前字符串是否全为汉字 T=1检验学校,T=2检验比赛
int jianyan2(char b[], int T);
void paixu(MESSAGE *temp, int select,FILE *fp);
char key[][3] = {"!", "。", "?", "《", "》", ",", "{", "}", "(", ")", "¥", "‘", "’", ":", ";", "—", "”", "“", "、", "·", "~", "\0"};
char school[][5] = {"大学", "学院", "华侨", "校区", "政法", "管理", "经济", "科学", "理工", "科技", "医科", "医药", "财经", "技术", "职业", "师范", "中国", "海洋", "石油", "民族", "外贸", "分校", "建筑", "工业", "外语", "\0"};
char program[][3] = {"跳", "滑", "冰", "射", "骑", "击", "跑", "拉", "道", "球", "举", "米", "水", "摔", "爬", "泳", "拔", "车", "踩", "接", "划", "体", "田", "人", "赛", "\0"};
int read(MESSAGE *message,FILE *fp)
{
if ((fp = fopen(wenjian, "r")) == NULL)
{
if ((fp = fopen(wenjian, "w+")) != NULL)
{
fclose(fp);
if ((fp = fopen(wenjian, "r")) == NULL)
return printf("文件读取失败!\n");
}
}
fread(message, sizeof(MESSAGE), 1, fp);
fclose(fp);
return 0;
}
int main()
{
MESSAGE SG = {0}, *message = &SG;
int i, j, k, select, choice, now, next;
if (read(message,fp))
{
printf("请按任意键进行下一步\n");
getch();
}
do
{
system("cls");
select = xianshi();
if (select == 1)
record(message->xuexiao, message->xiangmu, message->b, message);
else if (message->b[0])
{
if (select >= 2 && select <= 4)
{
fp = fopen(wenjian, "a+");
paixu(message, select - 2,fp);
fclose(fp);
}
else if (select == 5)
{
fp = fopen(wenjian, "a+");
for (k = 0; k < message->b[0]; k++) //输出学校名称选项 每五个一行
printf("%d:%-13s%c", k + 1, message->xuexiao[k], (k + 1) % H ? ' ' : '\n');
printf("\n输入学校前的编号[1,%d]:", message->b[0]);
choice = gainint(&choice, 1, message->b[0]) - 1;
next = 0;
while (next < message->b[1])
{
now = next;
if ((next + H) < (message->b[1]))
next = next + H;
else
next = message->b[1];
for (i = now; i < next; i++)
{
fprintf(fp,"(%s-%d)%-8s ", sex[message->sex[i]], message->junction[i], message->xiangmu[i]);
printf("(%s-%d)%-8s ", sex[message->sex[i]], message->junction[i], message->xiangmu[i]);
} //输出项目信息
fprintf(fp,"\n");
printf("\n");
for (j = 0; j < 3; j++)
{
fprintf(fp,"%-s: ", fenlei[j]);
printf("%-s: ", fenlei[j]);
for (k = now; k < next; k++)
{
if (j == message->sex[k] || j == 2)
{
fprintf(fp,"%02d分 \t", (message->spot + choice)->gram[j][k]);
printf("%02d分 \t", (message->spot + choice)->gram[j][k]);
}
else
{
fprintf(fp,"****** \t");
printf("****** \t");
}
}
fprintf(fp,"\n");
printf("\n");
}
fprintf(fp,"\n");
printf("\n");
}
fclose(fp);
}
else if (select == 6)
{
fp = fopen(wenjian, "a+");
for (i = 0; i < message->b[1]; i++)
{
printf("\t\t第%d个比赛项目: %-13s<%s子> 只录入前%d名\n", i + 1, message->xiangmu[i], sex[message->sex[i]], message->junction[i]);
fprintf(fp,"\t\t第%d个比赛项目: %-13s<%s子> 只录入前%d名\n", i + 1, message->xiangmu[i], sex[message->sex[i]], message->junction[i]);
for (j = 0; j < message->junction[i]; j++)
{
fprintf(fp,"\t第%d名:%-13s%02d分", j + 1, message->xuexiao[message->count[i][j]], junction[(message->junction[i]) / 4][j]);
printf("\t第%d名:%-13s%02d分", j + 1, message->xuexiao[message->count[i][j]], junction[(message->junction[i]) / 4][j]);
}
printf("\n\n");
fprintf(fp,"\n\n");
}
fclose(fp);
}
else if (select == 9)
{
printf("确认清空请按1 否则请按0:");
if (gainint(&choice, 0, 1))
for (k = 0; k < NUMP; k++) //对申请出来的结构体中的所有项目初始化
for (i = 0; i < 3; i++)
{
(message->spot + k)->sum[i] = 0; // sum[]初始化
for (j = 0; j < NUMP; j++)
(message->spot + k)->gram[i][j] = 0; //项目初始化
message->b[i] = 0;
}
/*if (write(message,fp))
return 0;*/
read(message,fp);
}
else if(select==7)
{
system(wenjian);
}
}
printf("\n请按任意键继续…\n");
getch();
} while (select != 8);
return 0;
}
int bijiao(char a[], char b[])
{
int i = 0, j = 0;
while (a[i] && b[j])
if (a[i++] == b[j])
{
j++;
}
else
{
i = i - j;
j = 0;
}
if (b[j] == '\0')
return i - j + 1;//若匹配成功则返回第一次匹配成功的下标
else
return 0;
}
int gainint(int *p, int a, int b)
{
do
{
*p = 0;
scanf("%d", p);
while (getchar() != '\n')
;
if (*p > b || *p < a)
printf("输入有误,请重新输入[%d--%d]:", a, b);
} while (*p > b || *p < a);
return *p;//返回输入数据
}
int gainchar(char A[], int min, int max)
{
int B, C;
do
{
A[max] = B = C = 0;
while ((A[B++] = getchar()) != '\n' && B < max)
;
if (A[B - 1] != '\n')
while (getchar() != '\n' && ++C)
;//如果输入的最后一个字符不是回车,那么将剩余长度计到C
else
A[--B] = 0;//否则把录进数组的回车删掉,即为成功输入字符。
if (C || B && B < min)
printf("录入的字符串长度为%d字节\n只录入(%d--%d)个字符!\n", B + C, min, max);
} while (C || B < min);
return B;//返回录入成功字符数量
}
int jianyan(char b[], int T) //检验b[]是否符合实际
{
int d = 0, i, LEN = -1, F;
while (b[++LEN])
;
for (i = 0; i < LEN; i++)
if (b[i] > 0) //汉字ascll编码每一个字节为负数
return printf("输入中含有非中文字符!");
for (i = 0; key[i][0]; i++)
{
F = bijiao(b, key[i]); //匹配中文标点符号
if (F && F % 2)
return printf("输入中含有非汉字中文字符!");
}
if (T == 1) //检验学校的名称
{
for (i = 0; school[i][0]; i++)
{
F = bijiao(b, school[i]);
if (F && F % 2)
d++;
}
if (!d)
return printf("查无此校~学校名称输入可能存在错误!");
}
if (T == 2) //检验比赛的名称
{
for (i = 0; program[i][0]; i++)
{
F = bijiao(b, program[i]);
if (F && F % 2)
d++;
}
if (!d)
return printf("没有发现相关比赛~项目名称输入可能存在错误!");
}
return 0;
}
int jianyan2(char b[], int T) //检验b[]是否符合实际
{
int d = 0, i, LEN = -1, F;
if (T == 2) //检验比赛的名称
{
for (i = 0; program[i][0]; i++)
{
F = bijiao(b, program[i]);
if (F )
d++;
}
if (!d)
return printf("没有发现相关比赛~项目名称输入可能存在错误!");
}
return 0;
}
void record(char school[][NAME], char game[][NAME], int b[], MESSAGE *temp) //记录数据;school为学校名,game为项目名,b(参考结构体中定义),temp信息结构体
{
char choose[][13] = {"录入学校数目", "总计项目数目", "男子项目数目"}; //提示用户输入内容
int scope[][3] = {{5, 1, 0}, {NUMU, NUMP, NUMU}}; //输入的各个内容的范围
int i, j, k, pan, count, choice, man;
scope[1][0] = NUMU - b[0]; //剩余录入的学校的数量(主要为后续加入数据设计)
scope[1][1] = NUMP - b[1]; //剩余录入的项目的数量(主要为后续加入数据设计)
if (b[0])
{
scope[0][0] = scope[0][1] = 0;
}//当用户已经进入此函数输入过一次后,改变条件将学校个数项目个数下限改为0
for (i = 0; i < 3; i++)
{
printf("\t%s(%d--%d)\n\t:", choose[i], scope[0][i], scope[1][i]);
gainint(&b[i], scope[0][i], scope[1][i]);
if (i == 1)
{
scope[1][2] = b[1]; //输入项目完毕后,改变男生项目的长度
if (!b[0] && !b[1])//输入为零时进行下一步
{
b[2] = b[1];
i++;
}
}
if (i == 2)
{
if (!b[0] || !b[1])
{
return;
}
b[3] = b[1] - b[2]; //男生输入完毕时,女生的项目=总项目-男生项目
}
}
for (i = NUMU - scope[1][0]; i < b[0] + NUMU - scope[1][0]; i++)
do
{
k = 0;
printf("请输入第%d个学校的名称(只录入%d-%d字符):\n", i + 1, 8, NAME);
gainchar(school[i], 8, NAME);
for (j = 0; j < i; j++) //对输入的学校名称进行查重
if (bijiao(school[j], school[i]) && bijiao(school[i], school[j])) //之前的学校和当前录入的学校重复
k++;
if (k)
printf("该学校已经录入!");
} while (jianyan(school[i], 1) || k);
b[0] += NUMU - scope[1][0]; //计算出目前的学校总数(主要为后续加入数据设计)
for (i = NUMP - scope[1][1]; i < b[1] + NUMP - scope[1][1]; i++) //录入项目
{
temp->sex[i] = (b[1] + NUMP - scope[1][1] - i) <= b[3]; //判断性别,0为男,1为女,先输入男
do
{
k = 0;
printf("请输入第%d个项目(%s)名称(只录入%d-%d字符):\n", i + 1, sex[temp->sex[i]], 4, NAME); //输入项目名称
gainchar(game[i], 4, NAME);
for (j = 0; j < i; j++)
if (bijiao(game[j], game[i]))
k++;
if (k)
printf("项目已录入成功!");
pan = (k || jianyan2(game[i], 2)); //区分分录入前三名还是前五名
if (!pan) //当输入满足要求时 继续询问项目的录入名次
do
{
printf("该项目录入成绩: 3:取前三 5:取前五:"); //询问录入的时前几名
gainint(&(temp->junction[i]), 3, 5); //将第i+1个项目的分数情况放在头节点的junction[i]数组里
} while ((temp->junction[i]) == 4); //只录入3和5
} while (pan); //当输入不满足要求时重新输入
system("cls");
for (k = 0; k < b[0]; k++) //输出学校名称选项 每五个一行
printf("%d:%-13s%c", k + 1, school[k], (k + 1) % H ? ' ' : '\n');
printf("\n\n获得 %s:(%s子)的前%d名(填学校前的编号):\n", game[i], sex[temp->sex[i]], temp->junction[i]);
for (j = 0; j < temp->junction[i]; j++) //每次录入的项目个数=temp->junction[i]
{
do
{
pan = 0;
printf("第%d名(%d-%d):", j + 1, 1, b[0]);
count = gainint(&count, 1, b[0]) - 1; //范围1-b[0]
(temp->count[i][j]) = count; // temp->count[i][j]中的数值就是第i个学校,名次为j
for (k = 0; k < j; k++) //检验名次是否录入重复
if (temp->count[i][k] == count)
pan = printf("一个学校只能获得一个名次!\n");
} while (pan);
choice = junction[(temp->junction[i]) / 4][j];
man = temp->sex[i];
(temp->spot + count)->gram[man][i] = choice; //把choice积分存入第count个学校的第i个项目的gram[man][i]里
(temp->spot + count)->gram[2][i] += choice; //修改第count个学校的该项目总分
(temp->spot + count)->sum[man] += choice; //修改第count个学校的男女团体总积分
(temp->spot + count)->sum[2] += choice; //修改学校的总积分
}
}
b[1] += NUMP - scope[1][1]; //修改录入的项目的总数量(主要为后续加入数据设计)
}
void paixu(MESSAGE *temp, int select,FILE *fp) //选择排序
{
int i, j, k, m, a, b, n, school[2][NUMU] = {0};
n = temp->b[0];
printf("升序请按0 降序请按1:");
gainint(&b, 0, 1);
for (i = 0; i < n; i++)
{
school[1][i] = i; //记录学校当前的位置编号
school[0][i] = (temp->spot + i)->sum[select];
}
printf("%s排名如下\t(以第%d列分数为准):\n\n", fenlei[select], select + 1);
fprintf(fp,"%s排名如下\t(以第%d列分数为准):\n\n", fenlei[select], select + 1);
for (i = 0; i < n - 1; i++)
{
k = i;
for (j = i + 1; j < n; j++)
{
if (b && school[0][j] > school[0][k])
k = j;
else if (!b && school[0][j] < school[0][k])
k = j;
}
if (k != i)
for (m = 0; m < 2; m++)
{
a = school[m][k];
school[m][k] = school[m][i];
school[m][i] = a;
}
}
printf("名次: 学校名称 男子 女子 学校总分\n");
fprintf(fp,"名次: 学校名称 男子 女子 学校总分\n");
for (i = 0; i < n; i++)
{
k = (b ? i + 1 : n - i); //计算排名的名次显示方向
j = school[1][i]; // 记录学校的编号
printf("第%02d:%-13s%02d分\t%02d分\t%02d分\n", k, temp->xuexiao[j], (temp->spot + j)->sum[0], (temp->spot + j)->sum[1], (temp->spot + j)->sum[2]);
fprintf(fp,"第%02d:%-13s%02d分\t%02d分\t%02d分\n", k, temp->xuexiao[j], (temp->spot + j)->sum[0], (temp->spot + j)->sum[1], (temp->spot + j)->sum[2]);
}
}
int xianshi()
{
int a;
system("mode con cols=130 lines=30"); //控制台 宽度130 高度30
printf("\t\t\t\t运动会分数统计\n");
printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n");
printf("\t* 功 能 表 积 分 规 则\n");
printf("\t* 1.添加学校及项目 *取前三名(1,2,3)\n");
printf("\t* 2.按男子团体总分排序输出 *积分分别为--5,3,2\n");
printf("\t* 3.按女子团体总分排序输出 \n");
printf("\t* 4.按学校总分排序输出 *取前五名(1,2,3,4,5)\n");
printf("\t* 5.按编号或名称查询学校情况 *积分分别为--7,5,3,2,1\n");
printf("\t* 6.显示比赛项目各学校名次情况 \n");
printf("\t* 7.读取文件 \n");
printf("\t* 8.保存信息并退出 \n");
printf("\t* 9.清空并恢复初始化界面 \n");
printf("\n");
printf("\t*注意:一个汉字占两个字符!!!\n");
printf("\t*注意:功能1可分多次选择!!!\n");
printf("\t*注意:录入项目时默认先男后女!!!\n");
printf("\t*注意:初次使用请先使用功能1录入数据!!!\n");
printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n\t");
printf("请输入您的选择(1-9):");
return gainint(&a, 1, 9);
}
界面:
文件输出: