c博客06-结构体&文件

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<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>

定义成语结构体

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欢迎来到成语世界!
33[0m");
	userNum = Get_User_Date(user, fpUser, information, fpInformation);
	printf("userNum=%d
", userNum);
	idiomNum = Get_Idiom_Date(idiom, fp);
	userNo=LoginInterface(user,&userNum, fpUser,information,fpInformation);
	printf("userNum=%d
", userNum);
	printf("userNo=%d
", 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] != '
' && c1[i] != ''; i++)
		{
			if (c1[i] == '.')
			{
				c1[i] = '';
				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] != '
' && c1[i] != ''; 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] != '
' && c[i] != ''; i++)
		{
			if (c[i] == ':')
			{
				c[i] = '';
				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欢迎使用成语字典!
33[0m");
	printf("33[34m请输入你要查询的成语:33[0m");
	scanf("%s", userInput);
	getchar();
	int i=0;
	for (i; i < idiomNum; i++)
	{
		//printf("%s
", idiom[i].name);
		if (strcmp(idiom[i].name, userInput) == 0)
		{
			printf("33[32m%s:%s
33[0m", idiom[i].name, idiom[i].mean);
			break;
		}
	}
	if(i==idiomNum) 	printf("33[31m很抱歉,系统内没有这个成语!
33[0m");
	printf("33[33m请选择:
33[0m");
	printf("33[32m1.继续查询
33[0m");
	printf("33[32m2.返回主菜单
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欢迎进行成语填空游戏!
33[0m");
	printf("33[33m请选择:
33[0m");
	printf("33[32m1.开始游戏
33[0m");
	printf("33[32m2.查询排名
33[0m");
	printf("33[32m3.返回主菜单
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选择无效,请重新选择!
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
请选择题目数量:
33[0m");
	printf("33[32m
1.10题(每题10分)
33[0m");
	printf("33[32m
2.20题(每题5分)
33[0m");
	printf("33[32m
3.25题(每题4分)
33[0m");
	scanf("%c", &c6);
	getchar();
	switch (c6)
	{
	case '1':
		Tnum = 10;
		system("cls");
		printf("33[32m
选择成功!
33[0m");
		wait();
		system("cls");
		break;
	case '2':
		Tnum = 20;
		system("cls");
		printf("33[32m
选择成功!
33[0m");
		wait();
		system("cls");
	    break;
	case '3':
		Tnum = 25;
		system("cls");
		printf("33[32m
选择成功!
33[0m");
		wait();
		system("cls");
		break;
	default:
		system("cls");
		printf("33[31m选择无效,请重新选择!
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] = '';
	}
	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
请输入完整的成语:33[0m");
	scanf("%s", wordInput);
	getchar();
	wordInput[9] = '';
	if (strcmp(wordInput, Name) == 0)
	{
		Rnum++;
		printf("33[32m回答正确!
33[0m");
	}
	else
	{
		printf("33[31m回答错误!正确答案是:%s
33[0m",Name);
	}
	if (Cnum == Tnum) goto index9;
	index7:
	printf("33[33m请选择:
33[0m");
	printf("33[32m1.继续答题
33[0m");
	printf("33[32m2.结束本次答题
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选择无效,请重新选择!
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%d33[0m",grade);
	else
		printf("33[33m%d33[0m", grade);
	index10:
	printf("33[33m
请选择:
33[0m");
	printf("33[32m1.重新答题
33[0m");
	printf("33[32m2.返回菜单
33[0m");
	scanf("%c", &c5);
	getchar();
	switch (c5)
	{
	case '1':
		system("cls");
		goto index8;
		break;
	case '2':
		return;
	default:
		system("cls");
		printf("33[31m选择无效,请重新选择!
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请选择登录或注册:
33[0m");
	printf("33[32m1.登录
33[0m");
	printf("33[32m2.注册
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选择无效,请重新选择!
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您正在登陆:
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登录成功!
33[0m");
		wait();
		return NO-1;
	}
	else
	{
		system("cls");
		printf("33[31m账号或密码错误!请重新输入
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您正在注册:
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, "
%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请等待!
33[0m");
	printf("33[32m3
33[0m");
	Sleep(1000);
	printf("33[32m2
33[0m");
	Sleep(1000);
	printf("33[32m1
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请选择:
33[0m");
	printf("33[32m1.成语字典
33[0m");
	printf("33[32m2.成语填空游戏
33[0m");
	printf("33[32m3.退出本系统
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选择无效,请重新选择!
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
", userNo);
	printf("33[33m*******************排行榜*******************33[0m");
	switch (type)
	{
	case 1:
		printf("33[33m(按平均分排行)
33[0m");
		break;
	case 2:
		printf("33[33m(按答题次数排行)
33[0m");
		break;
	case 3:
		printf("33[33m(按最高分排行)
33[0m");
		break;
	}
	printf("33[32m名次    账户    最高分    答题次数    平均分
33[0m");
	for (i = 0; i < userNum; i++)
	{
		switch (i+1)
		{
		case 1:
			printf("33[33m1   %7s%8d%8d%16.2lf33[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.2lf33[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.2lf33[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.2lf33[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   <--你的位置
33[0m");
		else
			printf("
");
	}
	index12:
	printf("33[33m请选择:
33[0m");
	printf("33[32m1.按平均分排行
33[0m");
	printf("33[32m2.按答题次数排行
33[0m");
	printf("33[32m3.按最高分排行
33[0m");
	printf("33[32m4.返回菜单
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选择无效,请重新选择!
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, "
%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.小结

这次大作业把所有已学知识都运用上了,对自己的能力是一个极大的考验与提升,对于一个程序的框架也有了更深入的认识,同时也提高了自己的编程水平。

原文地址:https://www.cnblogs.com/chenlr/p/12046329.html