c博客作业06-结构体&文件

帅比萌擦擦* 提交于 2019-12-15 21:14:06

1.本章学习总结

1.1 学习内容总结

1.结构体如何定义、成员如何赋值

1.结构体的定义

  • 一般形式:
struct 结构名{
    类型名 结构名成员1;
    类型名 结构名成员2'
    ···
    类型名 结构名成员n;
};
  • 结构的嵌套定义:
/*设置结构体保存学生的学号,姓名,通行地址,以及计算机,英语,数学和平均成绩,其中通行地址包括,居住的城市,街道,门牌号,邮编*/
struct address {
   char city[10];
   char street[20];
   int code;
   int zip;
};
struct nest_student{
   int num;
   char name[10];
   struct address addr;
   int computer,english,math;
   double auerage;
};

注意:在注意嵌套的结构类型时,必须先定义成员的结构类型,在定义主结构类型。
2.结构体成员的赋值

  • 在c语言中,使用结构成员操作符"."来引用结构成员,格式为结构变量名.结构成员名
/*对学生的信息进行赋值*/
struct student{
   int num;
   char name[10];
   int computer,english,math;
   double average;
};
struct student s1,s2;

/*分别对s1的每个结构体成员赋值;*/
scanf("%d %s %d %d %d",&s1.num,s1.name,&s1.computer,&s1.english,&s1.math);
s1.average=(s1.computer+s1.math+s1.english)/3.0;

/*将s1中各个结构体成员的值赋给s2*/
s2.num=s1.num;
strcpy(s2.name,s1.name); //这里注意,对字符串的赋值,不可以直接写“s2.name=s1.name”,这样的写法是错误的,要用库函数strcpy()!
s2.math=s1.math;
s2.computer=s1.computer;
s2.english=s1.english;
s2.average=s1.average;
/*对于将两个相同类型的结构变量,把一个结构变量赋给另外一个结构变量,可以直接整体赋值,这样和分别对结构体成员的赋值的操作等效*/
s2=s1;

运行结果:

  • 定义结构指针变量,使用指向运算符->访问指针指向的结构成员,以此来给每个结构成员赋值;
struct student *p;
/*使结构指针变量p指向s1,从键盘上读取数据赋给p指向的s1*/
p=&s1;
scanf("%d %s %d %d %d",&p->num,p->name,&p->computer,&p->english,&p->math);
p->average=(p->computer+p->english+p->math)/3.0;

/*使结构指针变量p指向s2,再把s1中各个结构体成员的值赋给s2*/
p=&s2;
p->num=s1.num;
strcpy(p->name,s1.name);
p->math=s1.math;
p->computer=s1.computer;
p->english=s1.english;
p->average=s1.average;

运行结果:

2.结构体数组排序做法

1.选择排序

/*从大到小排序*/
struct student students[n];
struct student temp;
for i=0 to n-1//外循环
   for j=0 to n//内循环
      if(students[j]>student[i])//如果后面的数据比前面大,交换数据;
         temp=students[i];
         student[i]=student[j];
         student[j]=temp;
      end if
   end for
end for

运行结果:

2.冒泡排序法

struct student students[n];
struct student temp;
for i=1 to n
   for j=0 to n-i
      if(students[j+1]>student[j])
         temp=students[j];
         student[j]=student[j+1];
         student[j+1]=temp;
      end if
   end for
end for

运行结果:

3.结构体指针

1.概念

  • 就是指向结构类型变量的指针。
  • 一般形式struct 结构名 * 指针变量名

2.用结构指针访问结构成员

struct student *p;
p=&s1;
  • 用*p访问结构成员:

  • 用指向运算符->访问指针指向的结构成员:

3.结构指针作为函数参数
将学生的信息按平均分排名

虽然结构变量也可以做为函数参数,但是当结构成员数据很多时,在参数传递时过程就需要消耗很多空间,而使用结构指针作为函数参数只要传递一个地址值,可以提高传参效率。

4.共用体、枚举类型做法

1.共用体

  • 一般声明形式:
union 联合名
{
   成员声明
   成员声明
   ···
}变量列表
  • 联合中的所有成员共享同一块内存,内存长度为最长成员的长度。因为在后续的程序设计中,代码量越来越多,内存是非常宝贵的。

2.枚举

  • 一般声明形式:
enum 枚举名 {枚举值1,枚举值2,···}变量列表;
  • 每个枚举值应该是一个合法的标识符,或者是一个标识符后面跟上一个等号,再加上一个常量表达式。
  • 编译程序将从0开始逐个给枚举值赋值,如果某个枚举值标识符后面跟有等号和常量表达式,那么编译程序就将该常量表达式的值作为该枚举值的值,该枚举值后面的枚举值从这个枚举值开始逐个加1,重新编号。

5.文件读写,文件中数据如何读进结构体数组

C语言标库stdio.h中提供了一系列文件的读写操作函数:

函数 调用格式 功能
fgetc() fgetc(FILE*fp) 从fp指向的文件中得到一个字符
fputc() fputc(char ch ,FILE*fp) 把字符ch输入到fp指向的文件中去
fgets() fgets(charp,n,FILEfp) 从fp指向的文件中获取n个字符赋给指针p所指向的字符串
fputs() fputs(charp,FILEfp) 把p指向的字符串输到fp指向的文件中去
fscanf() fscanf(文件指针,格式字符串,输入表) 从文件中按照给定的控制格式读取数据
fprintf() fprintf(文件指针,格式字符串,输出表) 从文件中按照给定的控制格式读取数据保存到变量
fread() fread(buffer,size,count,fp) 从二进制文件中连续读入count个数据块(size个字节)到buffer所指向的变量中
fwrite() fwrite(buffer,size,count,fp) 向二进制文件中连续输出入count次buffer所指向的变量中数据块(size个字节)

1.2本章学习总结

  • 学习体会:c语言学到最后,学习的东西越来越多,虽然这学期我们就要结束c语言的课程,可一写题目才发现自己还有许多东西都还没有学习,很多东西也还一知半解,到了后面综合性越来越强,如果前面有落下的知识应该要及时去补上,否则这部分的内容理解起来就会有些困难。(没错就是我555)

  • 代码量:1890

2.综合作业--“我爱成语”

2.1.文件介绍

头文件介绍

头文件1.idiom.h

  • 结构体及功能
结构体 功能
IDIOM 从idiom.h文件中读取成语及其意思
RANK 从ranking.h文件中读取排名成绩和时间
  • 函数声明
函数 功能
void Theme() 主题
void Login(char*user) 登入界面
int IsUser(char* name_str, char* password_str) 判断是否为用户
void GetChoice(FILE* fp1, FILE* fp2, char* user) 得到用户的选择并进入该功能
int Game(FILE* fp1, FILE fp2 ,char user) 成语游戏
int GetIdiom(FILE* fp, IDIOM* idioms) 获得文件idiom.txt中的所有成语
void RightSentence() 夸奖的句子
void WorrySentence() 提示回答错误的句子
int Problems(int num,IDIOM *idioms) 随机得到一个成语,并判断是否正确
void PrintProblem(char* idiom) 随机挖空,输出题目
void ArrageRank(FILE* fp, char* user, int right) 在文件ranking.txt中更新排名
void GetTime(RANK*rank_ptr) 获取当前时间和日期的函数
void GetScore(int right, int count) 计算正确率并告知答题结束
int NowTime() 记录当前时间
void GetRank(FILE*fp) 获取排名
int FindIdiom(FILE*fp) 查找成语
int WriteNewIdiom(FILE*fp) 添加新成语
int CheckIdiom(FILE* fp, char* idiom) 查看文件中是否有相同的成语
int IsAgain() 判断是否要继续的函数
  • 代码截图

2.函数实现文件介绍。

1.idiomMain.cpp

  • 功能:只放一个主函数main,在主函数中打开文件,得到用户名字,这三个变量的使用率比较高,放入主函数中,比较容易传参。
  • 代码截图:

2.List.cpp

  • void Theme()
    • 功能:放在开头的一个小界面,保存有清屏和再输出小界面的功能。
    • 代码截图:
  • void PrintLine()
    • 功能:输入分割线,用于分割题目。
    • 代码截图:
  • void Login(char* user)
    • 功能:登入界面,读取用户输入的用户名和密码,并将登陆成功的用户名传回主函数,这样便于主函数传给下一个函数。
    • 代码截图:
  • int IsUser(char* name, char* password)
    • 功能:判断是否为用户,如果输入不正确将一直无法继续下一个步骤,直到输入正确的用户名和密码。这里打开文件user.txt,将从Login函数中得到的用户名和密码与文件中的用户和账号作比较,因为没有其他功能会用到这个文件,所以用完文件后就可以直接关闭文件,减小计算机的负担。
    • 代码截图:
  • void ChoiceMenu()
    • 功能:选择菜单,给用户提示,供用户选择。
    • 代码截图:
  • void GetChoice(FILE * fp1,FILE * fp2,char * user)
    • 功能:获取用户的选择,并进入相应的分支,对输入错误的选项将会使用户重复输入。这里在选择进入哪个分支的部分加入了循环结构,并把执行每个功能的函数类型都设置为int型,可返回一个数值,这样可以供用户选择是否要继续执行该选择。
    • 代码截图:

3.idiom.cpp

  • int IsAgain()
    • 功能:判断用户是否要继续执行该选择,如果得到0的话就退回到函数GetChoice()函数中去;
    • 代码截图:
  • int Game(FILE * fp1,FILE * fp2, char* user)
    • 功能:用户进入该功能进行猜成语游戏,包含提示游戏开始,记录正确率,答题时间,可中途退出的功能。
    • 代码截图:
  • int FindIdiom(FILE * fp)
    • 功能:查找成语功能。
    • 代码截图:
  • int CheckIdiom(FILE * fp,char* idiom)
    • 功能:检查是否有相同的成语,这个是查找成语功能的一部分,我把它封装出来,这样可以供下面的添加函数功能使用。
    • 代码截图:
  • void GetRank(FILE * fp)
    • 功能:得到排名,并输出排名。
    • 代码截图:
  • int WriteNewIdiom(FILE* fp)
    • 功能:添加新的成语
    • 代码截图:

3.Game.cpp

  • int GetIdiom(FILE* fp, IDIOM* idioms)
    • 功能:获取文件idiom.txt的所有成语,保存到结构体数组IDIOM idioms[]中,并返回成语的总数量;
    • 代码截图:
  • void RightSentence()
    • 功能:输出夸奖的语句。
      -代码截图:
  • void WorrySentence()
    • 功能:输出提示错误的语句。
    • 代码截图:
  • int Problems(int num,IDIOM * idioms)
    • 功能:随机得到一个成语并输出题目,得到用户答案判断是否正确。
    • 代码截图:

  • void PrintProblem(char* problem)
    • 功能:随机去掉两个字,输出题目;
    • 代码截图:
  • int NowTime()
    • 功能:保存当前时间。
    • 代码截图:
  • void ArrageRank(FILE* fp, char* user, int right)
    • 功能:将文件ranking.txt文件中的数据重新排序,更新排名。
    • 代码截图:

  • void GetTime(RANK* rank_ptr)
    • 功能:得到答题结束的时间,运用了函数localtime()可以得到当前的本地时间,但是有个小问题,得到的月份比实际要小1,时间也需要加上1900。
    • 代码截图:
  • void GetScore(int right, int count)
    • 功能:得到正确率并输出。
    • 代码截图:

2.2.运行结果









2.3大作业总结

Q1:首先是多个函数都使用了文件指针,如果某个函数的文件指针已经指到文件尾部了,下一个函数调用的时候就会出问题,
A1:所以在所有调用文件指针时,都使用fseek(fp,0,0)使得指针指向文件头/尾。
Q2:刚开始对题目的输出处理,总是无法输出正常的汉字。
A2:单个汉字占两个字节,如果想要输出一个汉字只使用一个%c或者两个%c是不可以实现的,应该要把单个汉字作为字符串处理,于是我利用了printf("%.*s",problem+2);来控制输出的汉字个数;
Q3:对文件中排名的处理,不知道如何获取当前的日期和时间,本以为c语言的内容已经学习了很多了,没想到除了上课学习的还有许多需要我们去拓展的。~~革命还尚未成功啊啊~~
A3:我上网去查找了,知道了函数localtime()将从time()函数中获得的从1970年1月1日到现在返回的秒数转换为当前的年,月,份,时,分,秒形式;但是实际年份还要加上1900,月份要加上1;
Q4:多个文件函数之间的传参比单个文件函数的传参的难度要大太多了,写到后面发现需要前面的参数,然后去修修改改真的真的好难TAT
A4:要写一个框架,标出每个功能需要的参数,整理好了再敲代码!!
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!