1.本章学习总结
1.1 学习内容总结
1.结构体定义
关键字:struct
定义举例
typedef struct
{
char name[20];
char mean[200];
}IDIOM;
赋值:使用.引用结构体成员,再根据该成员的数据类型进行赋值。
赋值举例
strcpy(idiom[num].name, c);
strcpy(idiom[num].mean , (c+i+1));
2.结构体数组排序
定义结构体数组:IDIOM idiom[100];
排序:利用下标进行数组遍历,根据要求对成员进行比较,再进行排序。
for (j = 0; j < userNum; j++)
{
for (k = 0; k < userNum - 1 - j; k++)
{
if (information[h[k]].max < information[h[k + 1]].max)
{
t = h[k];
h[k] = h[k + 1];
h[k + 1] = t;
}
}
}
3.结构体指针怎么用
定义:IDIOM* idiom;
动态申请空间:idiom = (IDIOM*)malloc(200 * sizeof(IDIOM));
作为函数参数:int Get_Idiom_Date(IDIOM *idiom, FILE* fp);
4.共用体
使用同一段内存单元存放不同类型的变量,或者说使几个不同的变量共享同一段内存的结构,称为“共用体”类型的结构,声明与定义如下:
union Data{
int n;
char ch;
double f;
};
union Data a, b, c;
共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。共用体占用的内存等于最长的成员占用的内存。
5.枚举
所谓“枚举”就是把可能的值一一列举出来,变量的值只限于列举出来的值的范围内。
枚举类型的定义形式为:enum typeName{ valueName1, valueName2, valueName3, ...... };
枚举值默认从 0 开始,往后逐个加 1(递增)。
可以给第一个名字指定值:enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
这样枚举值就从 1 开始递增
枚举是一种类型,通过它可以定义枚举变量:enum week a, b, c;
也可以在定义枚举类型的同时定义变量:enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun } a, b, c;
有了枚举变量,就可以把列表中的值赋给它:
enum week{ Mon = 1, Tues, Wed, Thurs, Fri, Sat, Sun };
enum week a = Mon, b = Wed, c = Sat;
枚举在编译阶段将名字替换成对应的值。
6.文件读写
1.文件的打开函数:fopen(char *filename,char *type);
filename:要打开文件的文件名指针,一般用双引号括起来的文件名表示,也可使用路径名。
type:对打开文件的操作方式。
"r" 打开,只读;
"w" 打开,文件指针指到头,只写;
"a" 打开,指向文件尾,在已存在文件中追加;
"rb" 打开一个二进制文件,只读;
"wb" 打开一个二进制文件,只写;
"ab" 打开一个二进制文件,进行追加 ;
"r+" 以读/写方式打开一个已存在的文件;
"w+" 以读/写方式建立一个新的文本文件 ;
"a+" 以读/写方式打开一个文件文件进行追加 ;
"rb+" 以读/写方式打开一个二进制文件;
"wb+" 以读/写方式建立一个新的二进制文件 ;
"ab+" 以读/写方式打开一个二进制文件进行追加 ;
当用fopen()成功的打开一个文件时,该函数将返回一个FILE指针,如果文件打开失败,将返回一个NULL指针。
2.关闭文件函数:int fclose(FILE *fp);
该函数将关闭FILE指针对应的文件,并返回一个整数值。若成功地关闭了文件,则返回一个0值,否则返回一个非0值。
3.文件的读写
1.一次只读写文件中的一个字符
fgetc(fp);
fputc(c,fp);
putchar(c);
getc(fp);
putc(c,fp);
2.读写文件中字符串的函数
fgets(s,n,fp);
gets(fp);
fprintf(fp,char *format,variable-list);
fputs(s,fp);
puts(s);
fscanf(fp,char *format,variable-list);
1.2本章学习体会
学习感受
学会了结构体的一系列操作,以及对文件的基本操作,对于这些内容可以说是基本掌握了,并在大作业中得到了很好的运用。但是对于链表的学习不尽人意,需要进行加强学习。
代码量
920行(加上大作业)
2.综合作业--“我爱成语”
2.1.文件介绍
1.头文件介绍
idiom.h
定义头文件
#include
#include
#include
#include
#include
定义成语结构体
typedef struct
{
char name[20];
char mean[200];
}IDIOM;
定义用户结构体
typedef struct
{
int no;//用户序号
char UserName[20];
char password[20];
}USER;
定义成绩结构体
typedef struct
{
int No;//用户序号
int frequency;//答题次数
int achievement;//总成绩
double average;//平均成绩
int max;//最高成绩
}INFORMATION;
读取文件并存入结构体
int Get_Idiom_Date(IDIOM *idiom, FILE* fp);
int Get_User_Date(USER *user, FILE *fp, INFORMATION* information, FILE* fpInformation);
用户登录及注册
int LoginInterface(USER *user,int *userNum, FILE *fpUser,INFORMATION* information, FILE* fpInformation);
int Login(USER *user, int userNum);
int Register(FILE* fpUser, USER* user, int* userNum, INFORMATION* information, FILE* fpInformation);
int loginCheck(USER *user, USER login, int userNum);
成语字典及成语游戏
void dictionary(IDIOM* idiom, int num);
void fillGame(USER* user, IDIOM* idiom, int idiomNum, INFORMATION* information, int userNo, int userNum);
void fillIdiom(USER* user, IDIOM* idiom, int idiomNum, INFORMATION* information, int userNo);
排名及向文件写入成绩数据
void record(INFORMATION* information, int userNum, FILE* fpInformation);
void rank(USER* user, IDIOM* idiom, int idiomNum, INFORMATION* information, int userNo,int userNum);
主菜单及功能函数
void wait();
void menu(IDIOM* idiom, USER* user, int idiomNum, INFORMATION* information, int userNo, int userNum);
2.函数实现文件介绍
文件1:main.cpp
主要用于定义各种变量,打开和关闭文件,动态申请和释放空间,调用函数。
#include "idiom.h"
void checkFile(FILE* fp);
int main()
{
srand(time(NULL));
FILE* fp;
FILE* fpUser;
FILE* fpInformation;
IDIOM* idiom;
USER* user;
INFORMATION* information;
int idiomNum;//成语数量
int userNum;//用户数量
int userNo;//用户序号
idiom = (IDIOM*)malloc(200 * sizeof(IDIOM));
user = (USER*)malloc(20 * sizeof(USER));
information = (INFORMATION*)malloc(20 * sizeof(INFORMATION));
fpUser = fopen("user.txt", "a+");//打开用户文件
checkFile(fpUser);
fp = fopen("idiom.txt", "a+");//打开成语文件
checkFile(fp);
fpInformation = fopen("information.txt", "r+");
checkFile(fpInformation);
printf("\33[32m欢迎来到成语世界!\n\33[0m");
userNum = Get_User_Date(user, fpUser, information, fpInformation);
printf("userNum=%d\n", userNum);
idiomNum = Get_Idiom_Date(idiom, fp);
userNo=LoginInterface(user,&userNum, fpUser,information,fpInformation);
printf("userNum=%d\n", userNum);
printf("userNo=%d\n", userNo);
menu(idiom,user,idiomNum,information,userNo,userNum);
record(information, userNum, fpInformation);
free(idiom);
free(user);
free(information);
fclose(fp);
fclose(fpUser);
fclose(fpInformation);
return 0;
}
void checkFile(FILE* fp)
{
if (fp == NULL)
{
printf("file open false");
exit(0);
}
}
文件2:user.cpp
用于将user.txt文件中的数据写入用户结构体中,将information.txt文件中的数据写入成绩结构体中,为接下来的注册、登录、排名做准备。
#include "idiom.h"
int Get_User_Date(USER user[], FILE* fpUser, INFORMATION* information, FILE* fpInformation)
{
char c1[40];
int i = 0;
int Num;
Num = 0;
int f=0;
while (!feof(fpUser))
{
fscanf(fpUser, "%s", c1);
user[Num].no = Num;
for (i = 0; c1[i] != '\n' && c1[i] != '\0'; i++)
{
if (c1[i] == '.')
{
c1[i] = '\0';
break;
}
}
strcpy(user[Num].UserName , c1);
strcpy(user[Num].password , (c1 + i + 1));
Num++;
}
Num = 0;
while (!feof(fpInformation))
{
fscanf(fpInformation, "%s", c1);
information[Num].No = Num;
information[Num].frequency = 0;
information[Num].achievement = 0;
information[Num].average = 0;
information[Num].max = 0;
for (i = 1; c1[i] != '\n' && c1[i] != '\0'; i++)
{
if (c1[i] == '#')
{
f++;
}
if (c1[i] != '#')
{
switch (f)
{
case 1:
information[Num].frequency = information[Num].frequency*10+c1[i]-'0';
break;
case 2:
information[Num].achievement = information[Num].achievement * 10 + c1[i] - '0';
break;
case 3:
information[Num].average = information[Num].average * 10 + c1[i] - '0';
break;
case 4:
information[Num].max = information[Num].max * 10 + c1[i] - '0';
break;
}
}
}
Num++;
f = 0;
}
return Num-1;
}
文件3:idiom.cpp
1.将idiom.txt文件中的数据写入成语结构体中
2.成语字典函数
3.成语游戏函数
#include "idiom.h"
int Get_Idiom_Date(IDIOM *idiom, FILE* fp)
{
char c[200];
int i = 0;
int num = 0;
while (!feof(fp))
{
fgets(c, 200, fp);
for (i = 0; c[i] != '\n' && c[i] != '\0'; i++)
{
if (c[i] == ':')
{
c[i] = '\0';
break;
}
}
strcpy(idiom[num].name, c);
strcpy(idiom[num].mean , (c+i+1));
num++;
}
return num;
}
void dictionary(IDIOM* idiom, int idiomNum)
{
char userInput[20];
char c3;
index3:
printf("\33[33m欢迎使用成语字典!\n\33[0m");
printf("\33[34m请输入你要查询的成语:\33[0m");
scanf("%s", userInput);
getchar();
int i=0;
for (i; i < idiomNum; i++)
{
//printf("%s\n", idiom[i].name);
if (strcmp(idiom[i].name, userInput) == 0)
{
printf("\33[32m%s:%s\n\33[0m", idiom[i].name, idiom[i].mean);
break;
}
}
if(i==idiomNum) printf("\33[31m很抱歉,系统内没有这个成语!\n\33[0m");
printf("\33[33m请选择:\n\33[0m");
printf("\33[32m1.继续查询\n\33[0m");
printf("\33[32m2.返回主菜单\n\33[0m");
scanf("%c", &c3);
getchar();
switch(c3)
{
case'1':
system("cls");
goto index3;
break;
case'2':
return;
}
}
void fillGame(USER* user, IDIOM* idiom, int idiomNum, INFORMATION* information,int userNo, int userNum)
{
char c4;
index5:
printf("\33[35m欢迎进行成语填空游戏!\n\33[0m");
printf("\33[33m请选择:\n\33[0m");
printf("\33[32m1.开始游戏\n\33[0m");
printf("\33[32m2.查询排名\n\33[0m");
printf("\33[32m3.返回主菜单\n\33[0m");
scanf("%c", &c4);
getchar();
switch (c4)
{
case '1':
wait();
system("cls");
fillIdiom(user,idiom,idiomNum,information,userNo);
system("cls");
goto index5;
break;
case '2':
wait();
system("cls");
rank(user, idiom, idiomNum, information, userNo, userNum);
system("cls");
goto index5;
break;
case '3':
return;
default:
system("cls");
printf("\33[31m选择无效,请重新选择!\n\33[0m");
goto index5;
}
}
void fillIdiom(USER* user, IDIOM* idiom, int idiomNum, INFORMATION* information, int userNo)
{
static int h[100];
int num,Tnum,Cnum=0,Rnum=0,grade;
int n1,n2;
int i,j,k,t;
char word[5][3];
char wordInput[10];
char Name[20];
char c5,c6;
index8:
printf("\33[33m\n请选择题目数量:\n\33[0m");
printf("\33[32m\n1.10题(每题10分)\n\33[0m");
printf("\33[32m\n2.20题(每题5分)\n\33[0m");
printf("\33[32m\n3.25题(每题4分)\n\33[0m");
scanf("%c", &c6);
getchar();
switch (c6)
{
case '1':
Tnum = 10;
system("cls");
printf("\33[32m\n选择成功!\n\33[0m");
wait();
system("cls");
break;
case '2':
Tnum = 20;
system("cls");
printf("\33[32m\n选择成功!\n\33[0m");
wait();
system("cls");
break;
case '3':
Tnum = 25;
system("cls");
printf("\33[32m\n选择成功!\n\33[0m");
wait();
system("cls");
break;
default:
system("cls");
printf("\33[31m选择无效,请重新选择!\n\33[0m");
goto index8;
}
index6:
do
{
num = rand() % idiomNum;
} while (h[num] > 0);
h[num]++;
strcpy(Name, idiom[num].name);
k = 0;
for (i = 1; i < 5; i++)
{
for (j = 0; j < 2; j++)
word[i][j] = Name[k++];
word[i][j] = '\0';
}
do
{
n1 = rand() % 4 + 1;
n2 = rand() % 4 + 1;
} while (n1 == n2);
if (n1 > n2)
{
t = n1;
n1 = n2;
n2 = t;
}
for (i = 1; i <= 4; i++)
{
if (i == n1 || i == n2)
printf("\33[32m__ \33[0m");
else
printf("\33[32m%s \33[0m",word[i]);
}
Cnum++;
printf("\33[33m\n请输入完整的成语:\33[0m");
scanf("%s", wordInput);
getchar();
wordInput[9] = '\0';
if (strcmp(wordInput, Name) == 0)
{
Rnum++;
printf("\33[32m回答正确!\n\33[0m");
}
else
{
printf("\33[31m回答错误!正确答案是:%s\n\33[0m",Name);
}
if (Cnum == Tnum) goto index9;
index7:
printf("\33[33m请选择:\n\33[0m");
printf("\33[32m1.继续答题\n\33[0m");
printf("\33[32m2.结束本次答题\n\33[0m");
scanf("%c", &c5);
getchar();
switch (c5)
{
case '1':
system("cls");
goto index6;
break;
case '2':
goto index9;
default:
system("cls");
printf("\33[31m选择无效,请重新选择!\n\33[0m");
goto index7;
}
index9:
printf("\33[32m您的最终成绩为:\33[0m");
grade = Rnum * (100 / Tnum);
information[userNo].frequency++;
information[userNo].achievement +=grade ;
if (grade > information[userNo].max)
{
information[userNo].max = grade;
}
information[userNo].average = information[userNo].achievement*1.0/ information[userNo].frequency;
if(grade<60)
printf("\33[31m%d\33[0m",grade);
else
printf("\33[33m%d\33[0m", grade);
index10:
printf("\33[33m\n请选择:\n\33[0m");
printf("\33[32m1.重新答题\n\33[0m");
printf("\33[32m2.返回菜单\n\33[0m");
scanf("%c", &c5);
getchar();
switch (c5)
{
case '1':
system("cls");
goto index8;
break;
case '2':
return;
default:
system("cls");
printf("\33[31m选择无效,请重新选择!\n\33[0m");
goto index10;
}
}
文件4:interface.cpp
1.用户注册和登录
2.调用菜单函数
3.菜单函数调用其他函数
#include "idiom.h"
int LoginInterface(USER *user, int *userNum, FILE *fpUser, INFORMATION* information, FILE* fpInformation)
{
char c;
int NO;
index1:
printf("\33[34m请选择登录或注册:\n\33[0m");
printf("\33[32m1.登录\n\33[0m");
printf("\33[32m2.注册\n\33[0m");
printf("\33[33m请选择:\33[0m");
scanf("%c", &c);
switch (c)
{
case '1':
system("cls");
NO=Login(user,*userNum);
break;
case '2':
NO=Register(fpUser,user,userNum,information,fpInformation);
break;
default:
system("cls");
printf("\33[31m选择无效,请重新选择!\n\33[0m");
goto index1;
}
return NO-1;
}
int Login(USER *user, int userNum)
{
char InputAccountNumber[20];
char InputPassword[20];
int NO;
USER login;
index2:
printf("\33[33m您正在登陆:\n\33[0m");
printf("\33[34m请输入账号:\33[0m");
scanf("%s", login.UserName);
getchar();
printf("\33[34m请输入密码:\33[0m");
scanf("%s", login.password);
getchar();
if (NO=loginCheck(user, login, userNum))
{
system("cls");
printf("\33[34m登录成功!\n\33[0m");
wait();
return NO-1;
}
else
{
system("cls");
printf("\33[31m账号或密码错误!请重新输入\n\33[0m");
goto index2;
}
}
int loginCheck(USER *user, USER login,int userNum)
{
int i;
char file[42];
char input[42];
strcpy(input,login.UserName);
strcat(input, login.password);
for (i = 0; i < userNum; i++)
{
strcpy(file, user[i].UserName);
strcat(file, user[i].password);
if (strcmp(input, file) == 0)
{
return i+1;
}
}
return 0;
}
int Register(FILE *fpUser, USER* user,int *userNum, INFORMATION* information, FILE* fpInformation)
{
user[*userNum].no=*userNum;
printf("\33[33m您正在注册:\n\33[0m");
printf("\33[34m请输入账号(20个字符以内):\33[0m");
scanf("%s",user[*userNum].UserName);
getchar();
printf("\33[34m请输入密码(20个字符以内):\33[0m");
scanf("%s", user[*userNum].password);
getchar();
information[*userNum].No = *userNum;
information[*userNum].frequency = 0;
information[*userNum].achievement = 0;
information[*userNum].average = 0;
information[*userNum].max = 0;
fprintf(fpUser, "\n%s.", user[*userNum].UserName);
fprintf(fpUser, "%s", user[*userNum].password);
(*userNum)++;
system("cls");
printf("\33[34m注册成功!\33[0m");
wait();
return (*userNum);
}
void wait()
{
printf("\33[32m请等待!\n\33[0m");
printf("\33[32m3\n\33[0m");
Sleep(1000);
printf("\33[32m2\n\33[0m");
Sleep(1000);
printf("\33[32m1\n\33[0m");
Sleep(1000);
system("cls");
}
void menu(IDIOM* idiom, USER* user, int idiomNum, INFORMATION* information, int userNo, int userNum)
{
char c2;
index4:
printf("\33[33m请选择:\n\33[0m");
printf("\33[32m1.成语字典\n\33[0m");
printf("\33[32m2.成语填空游戏\n\33[0m");
printf("\33[32m3.退出本系统\n\33[0m");
scanf("%c", &c2);
getchar();
switch (c2)
{
case '1':
wait();
system("cls");
dictionary(idiom,idiomNum);
system("cls");
goto index4;
break;
case '2':
wait();
system("cls");
fillGame(user,idiom,idiomNum,information,userNo,userNum);
system("cls");
goto index4;
break;
case '3':
return;
default:
system("cls");
printf("\33[31m选择无效,请重新选择!\n\33[0m");
goto index4;
}
}
文件5:rank.cpp
1.将用户进行排序,可按不同条件排序
2.将用户成绩写入文件中
#include "idiom.h"
void rank(USER* user, IDIOM* idiom, int idiomNum, INFORMATION* information, int userNo,int userNum)
{
int i,j,k,t,type=3;
char c;
int h[25];
for (j = 0; j < userNum; j++)
{
h[j] = j;
}
for (j = 0; j < userNum; j++)
{
for (k = 0; k < userNum - 1-j; k++)
{
if (information[h[k]].max < information[h[k+1]].max)
{
t = h[k];
h[k] = h[k+1];
h[k+1] = t;
}
}
}
index11:
printf("%d\n", userNo);
printf("\33[33m*******************排行榜*******************\33[0m");
switch (type)
{
case 1:
printf("\33[33m(按平均分排行)\n\33[0m");
break;
case 2:
printf("\33[33m(按答题次数排行)\n\33[0m");
break;
case 3:
printf("\33[33m(按最高分排行)\n\33[0m");
break;
}
printf("\33[32m名次 账户 最高分 答题次数 平均分\n\33[0m");
for (i = 0; i < userNum; i++)
{
switch (i+1)
{
case 1:
printf("\33[33m1 %7s%8d%8d%16.2lf\33[0m", user[h[i]].UserName,information[h[i]].max, information[h[i]].frequency
, information[h[i]].average);
break;
case 2:
printf("\33[35m2 %7s%8d%8d%16.2lf\33[0m", user[h[i]].UserName,information[h[i]].max, information[h[i]].frequency
, information[h[i]].average);
break;
case 3:
printf("\33[34m3 %7s%8d%8d%16.2lf\33[0m", user[h[i]].UserName, information[h[i]].max, information[h[i]].frequency
, information[i].average);
break;
default:
printf("\33[35m%d %7s%8d%8d%16.2lf\33[0m",i+1,user[h[i]].UserName,information[h[i]].max, information[h[i]].frequency
, information[h[i]].average);
}
if (h[i] == userNo)
printf("\33[31m <--你的位置\n\33[0m");
else
printf("\n");
}
index12:
printf("\33[33m请选择:\n\33[0m");
printf("\33[32m1.按平均分排行\n\33[0m");
printf("\33[32m2.按答题次数排行\n\33[0m");
printf("\33[32m3.按最高分排行\n\33[0m");
printf("\33[32m4.返回菜单\n\33[0m");
scanf("%c", &c);
getchar();
switch (c)
{
case '1':
system("cls");
type = 1;
for (j = 0; j < userNum; j++)
{
for (k = 0; k < userNum - 1 - j; k++)
{
if (information[h[k]].average < information[h[k + 1]].average)
{
t = h[k];
h[k] = h[k + 1];
h[k + 1] = t;
}
}
}
goto index11;
case '2':
system("cls");
type = 2;
for (j = 0; j < userNum; j++)
{
for (k = 0; k < userNum - 1 - j; k++)
{
if (information[h[k]].frequency < information[h[k + 1]].frequency)
{
t = h[k];
h[k] = h[k + 1];
h[k + 1] = t;
}
}
}
goto index11;
case '3':
system("cls");
type = 3;
for (j = 0; j < userNum; j++)
{
for (k = 0; k < userNum - 1 - j; k++)
{
if (information[h[k]].max < information[h[k + 1]].max)
{
t = h[k];
h[k] = h[k + 1];
h[k + 1] = t;
}
}
}
goto index11;
case '4':
return;
default:
system("cls");
printf("\33[31m选择无效,请重新选择!\n\33[0m");
goto index12;
}
}
void record(INFORMATION* information, int userNum, FILE* fpInformation)
{
int i;
rewind(fpInformation);
for (i = 0; i < userNum; i++)
{
if(i==0) fprintf(fpInformation, "%d", information[i].No);
else fprintf(fpInformation, "\n%d", information[i].No);
fprintf(fpInformation, "#%d", information[i].frequency);
fprintf(fpInformation, "#%d", information[i].achievement);
fprintf(fpInformation, "#%.0lf", information[i].average);
fprintf(fpInformation, "#%d", information[i].max);
}
}
2.2.运行结果
登录界面
游戏界面
排行界面
2.3大作业总结
1.碰到问题及解决办法
1.函数无法使用参数
因为该函数是在子函数内被调用的,所以该函数的参数必须子函数有。
2.栈溢出
因为使用了结构体数组,占用内存太多。改为结构体指针,再动态申请空间。
3.返回上一级
原本使用while来实现的,但后来改为用goto语句。
2.小结
这次大作业把所有已学知识都运用上了,对自己的能力是一个极大的考验与提升,对于一个程序的框架也有了更深入的认识,同时也提高了自己的编程水平。