1.本章学习总结
1.1学习内容总结
一:结构体
1.结构体的概念
结构类型是一种允许程序员把一些数据分量聚合成一个整体的数据类型。一个结构中包含每个数据类型的名字,这些数据分量称为结构成员或者结构分量。结构体与数据的区别在于数组中所有的元素的数据类型必须是相同的,而结构中的各成员数据类型可以不同
这里强调的是,结构变量其实和我们在用int,float,double变量是一样的,不同的只是结构变量可以含有多个成员
2.结构体的定义和赋值
定义法一:
定义法二:
定义法三:利用typedef()
利用typedef()就可以把很长的struct student 替换掉,节省时间。
赋值:
有两种方法,第一种是直接用变量名加‘,’加成员民进行赋值,另一种是新定义一个指针,然后用p->name这种方法进行赋值,不过需要注意的是,对字符串数组的赋值应该用到函数strcpy()进行赋值。
3.结构体数组排序做法
对于排序法,其实我们应该不陌生的就是冒泡排序法和选择排序法;
例子:比较平均成绩:
- 选择排序法
- 冒泡排序法
总的方法其实和一维数组排序是一样的,不过定义的是结构中间变量,不用涉及到成员。
4.结构指针
定义:
struct student s1={101."zhang"};
struct student *p;
p=&s1;
结构指针的值实际是结构变量的首地址,即第一个成员的地址,有了结构指针的定义,既可以通过结构变量s1直接访问结构成员,也可以通过结构指针变量p间接访问它所指向的结构变量中的各个成员。
具体形式:
(*p).num=101;//一定要加括号,因为优先级不一样
或
p->num=101;
或
s1.num=101;
另外,结构指针还可以作为函数参数传入函数,其具体定义是
函数定义:
int update(struct student*p,int n,int num);
函数调用:
update(students,n,num)//填的是结构数组名,结构其实本质也是数组,所以不加&号
有了struct student *p这样的指针,接着在函数中,就可以利用p->num,等进行修改。
具体实例:修改学生成绩
5.共用体,枚举类型。
共用体定义:
union 联合名
{
成员声明;
成员声明;
}变量列表;
共用体特点:
1.利用覆盖技术,讲几个变量相互覆盖,这种几个不同的变量共同占用一段内存的结构类型。
2.共用体变量的地址和它的成员都是同一地址。
3.共用体变量中起作用的成员都是最后一次存放的成员,存入一个新成员后,原有的成员就会失去作用。
作用:节省内存。
共用体应用:
枚举类型:
格式:
enum 枚举名{枚举1,枚举2...}变量列表
定义:
enum weekday{ sun,mou,tue,wed,thu,fri,sat };
enum weekday a,b,c;
或者为: enum weekday{ sun,mou,tue,wed,thu,fri,sat }a,b,c;
或者为: enum { sun,mou,tue,wed,thu,fri,sat }a,b,c;
规定:
1.枚举值是常量,不是变量,不能再程序中用赋值语句对它赋值,例如sun=5;
只能把枚举值赋值给枚举变量,例如,a=sum,是可以的。
2.枚举元素本身由系统定义了一个表示序号的数值,从0开始顺序定义为0.1.2,
如在上面例子中,sun值为0,mon为1;
二:文件
1.文件打开和关闭
fopen(),fclose()函数是用来打开文件和关闭文件的,如果打开失败,则会返回NULL,函数里放的是要打开的文件路径或者是文件名,参数mode字符串代表流形态。
形态字符串 | 特点 |
---|---|
r | r以只读的方式打开文件,该文件必须存在 |
r+ | r+以可读写方式打开,该文件必须存在 |
a+ | 打开读写文件文件不存在,则新建,存在。写入的数据会被加到文件尾后,文件原先内容会被保留(原来的EOF不保留) |
rw+ | rw+读写打开一个文本文件,允许读和写 |
w | w打开只写文件,若文件存在则文件长度轻为0,则该文件内容会消失,若文件不存在,则建立该文件 |
w+ | a以附加方式打开只写文件,若文件存在,则文件长度会被清零,文件内容会消失 |
a | 以附加的方式打开只写文件,若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后(原来的EOF符保留) |
at+ | 打开一个叫string的文件,a表示append,写入处理的时候接着原有文件写入,t表示打开文本文件,+表示可读写 |
wb | 只写打开或新建一个二进制文件。只允许写数据 |
wb+ | 读写打开或建立一个二进制文件。允许读和xie |
ab+ | 读写打开一个二进制文件,允许读或在文件末追加数据 |
rb+ | rb+读写打开一个二进制文件,允许读写数据 |
上述的形态自负床都可以再加一个b字符。如
rb,w+b或ab+等组合。加入b字符用来告诉函数库以二进制模式打开文件,如果不加b,表示默认加了t,即rt,wt,其中t表示以文本模式打开文件。
2.文件内容的读出和将数据写入文件
格式化方式读写文件:fscanf()函数和fprintf()函数
定义:
fscanf(文件指针,格式字符串,输入表);
fprintf(文件指针,格式字符串,输入表)
在文件打开后,
for(i=0;i<n;i++)
{
/*从文件读入成绩保存到变量中*/
fscanf(fp,"%ld%s%d",&num,stname,&score)
printf("%ld%s%d
",num,stname,score);
}
for(i=0;i<n;i++)
{
/*输入账号和密码*/
scanf("%s%s",username,password);
fprintf(fp,"%s%s
".username,password);/*写入文件*/
}
字符方式读写文件:fgetc(),fputc(),用于复制文件
在打开文件后,
while(!feof(fp1))
{
ch=fgetc(fp1);//从fp1所指示的文件中读取一个字符
if(ch!=EOF)
{
fputc(ch,fp2);//将字符ch写入fp2所指示的文件
}
}
打开文件时,fp1指针指向文件的首部,每次调用fgetc()函数成功执行后,fp1会自动向后移动一个位置,若读到文件末尾,则会读到一个无效的字符,返回EOF。
字符串方式文件读写函数fgets()fputs()
作用:
fputs()函数用来向指定的文本文件写入一个字符串
fgets()从文本文件中读取字符串
格式:
fputs(s,fp);
fgets(s,n,fp);//n是指定读入字符的个数
数据块方式文件读写函数fread()和frite()
这两个函数多用于读写二进制文本
格式:
fread(buffer,size,count,fp);
fwrite(buffer,size,count,fp);
buffer是一个存放文件内容的指针,size表示数据块的字节数,count表示要读写的数据块数
eg:
fread(fa,4,5,fp);
从fp所指的文件中,每次读入四个字节送入实数组fa中,连续读入无促,即读5个实数到fa中。
3.有关文件的函数
重定位文件首函数rewind()
rewind(FILE *fp);
指针移动控制函数fseek()
格式:
fseek(fp,offset,from);
offset表示文件偏移量,是long类型,offset可为负值,表示反向偏移,from表示从哪个位置开始计算偏移量,SEEK-SET,SEEK_CUR,SEEK_END,分别表欧式文件首部,当前位置。文件尾部。
获取指针当前位置函数ftell()
ftell(文件指针)
若函数出错,返回-1L
文件末尾检测函数feof()
feof(fp)
返回1表示已经文件结束位置,0表示文件为结束
1.2本章学习体会
这个章节的内容很多,并且联系到了文件,对这个概念之前是没有了解到的,所以学习的时候很吃力,再加上学习内容很多,又开始学习链表,这个章节的内容还不熟悉,就开始了另一个章节,可以说内心是奔溃的,太难了我。其实大部分是我自己的原因吧,因为一开始我就打退堂鼓,看到文件,想着这个一定很难,所以我就把预习这块内容推啊推,推到老师上完了才反应过来,嗯,我应该去看一下书本了,太难了我。从一开始就退缩,所以就不能跟上老师的步伐,所以我觉得这种心理是我应该去克服的。
代码量 |
---|
800多 |
2.综合作业——“我爱成语”系统
主要功能
**登陆系统,输入正确的用户名和密码,才能登陆系统
**成语游戏,从文件中随机抽一个成语。随机展示2个汉字,用户猜剩余汉字,如果答对,则得分,错误,则给出正确答案
*得分记录,和总得分的计算
**成语字典,输入成语。查询相应的成语解释
2.1文件介绍
头文件概括
头文件 | 介绍 |
---|---|
Idiom_Main.h | 这里面包含了基本的库函数和下面所有的自定义库函数 |
Idiom_Game.h | 关于游戏闯关函数的声明和定义成语和成语意思的结构体,还有关于成语处理的函数声明 |
Idiom_Dictionary.h | 关于查找的函数 |
checkValid.h | 有检验用户名和密码是否正确的函数和检验是否存在这个用户名的函数声明 |
Login_Idiom.h | 定义用户名和密码的结构体,还有登录和注册函数的声明 |
Printf.h | 输出成语的函数声明,界面的输出,菜单和选项的输出 |
Time.h | 随机数生成,倒计时,Sleep()函数让界面停止几秒。 |
Idiom_Rank.h | 定义用户名和用户得分的结构体,关于用户得分和记录的函数 |
Idiom_Main.h
代码如下:
Idiom_Game.h
代码如下:
Idiom_Dictionary.h
代码如下:
checkValid.h
代码如下:
Login_Idiom.h
代码如下:
Printf.h
代码如下:
Time.h
代码如下:
Idiom_Rank.h
代码如下:
2.函数实现文件的介绍
-
Idiom_Main.cpp
- cai()
-
Login_Main.cpp
- Login()
- Interface(3)
- Registe()
- Login()
-
Idiom_Game.cpp
- Idiom_Game()
- Time()
- GetData()
- Idiom_Hollow()
- Rank_Main()
- Idiom_Game()
-
Idiom_Hollow.cpp
- random()
- Printf_Idiom()
-
Idoim_Dictionary.cpp
- Idiom_Search()
- GetData()
- remind()
- Idiom_Search()
-
Idiom_Ranking.cpp
- Rank_Main()
- Rank_name()
- Total_Goal()
-
GetData.cpp
- GetData()
-
Printf.cpp
- Printf_Idiom()
- Rand()
- Interface()
- cai()
- List()
- Printf_Idiom()
-
checkValid.cpp
- checkUserValid()
- Search()
-
Time.cpp
- Time()
- Remind()
- random()
- Rand()
Idiom_Main.cpp
- main()函数里只有一个菜单
Login_Main.cpp
- 思路:登录界面,用结构体存储用户的姓名和密码,然后通过检验函数,检验用户名和密码是否有效,如果是注册界面,则用户输入姓名和密码,并且写入文件进行保存。
Idiom_Game.cpp
- 思路:这里,先打开成语文件,和记录用户得分的文件,然后提醒用户开始,记录开始的时间,然后进入闯关函数进行闯关,记录结束的时间进行计时,并且最后然后用户再次输入用户名以便用户记录得分情况
Idiom_Hollow.cpp
- 思路:这是挖空函数,调用了随机数函数,将成语中的随机两个字挖空,然后进入输出成语的阶段,供玩家答题。
Idoim_Dictionary.cpp
- 思路:玩家输入要查找的成语,然后在文件里进行匹配,并输入意思
Idiom_Ranking.cpp
- 思路:这是在每局游戏结束时,会将成绩与用户名进行捆绑,如果要知道游戏记录,只要打开文件即可
GetData.cpp
- 思路:这是对成语的数据处理,将成语和成语意思进行分离,以:为界。
Printf.cpp
- 思路:对随机抽出来的成语进行数据的处理,然后输出成语,然后将用户的答案与正确答案进行对比。同时,这里不止包含一个函数,还有菜单界面的输出等函数
checkValid.cpp
- 思路:打开文件,将用户的用户名和密码进行比对,并返回一个值
Time.cpp
- 思路:这里有随机数的生成,用户成语的处理,同时还有计时用的函数,和延迟函数。
2.2运行结果
1.登陆界面
2.游戏界面
3.查询界面
4.得分记录
2.3大作业总结
1.碰到的问题
Q1:发现程序运行时好像没有进入到我想让它进入的哪个函数
S1:发现时生成随机数时,两个有相同的概率,我没有加上条件判断,以至于好像没有进入函数,而是直接跳过,后来加了一个条件判断
Q2:在对成语进行成语和意思分离时,使用的指针到后面已经不知道飘哪里去了,然后我在调试去遍历的时候,仍然让它++。导致输出的都是烫烫烫
S2:我又定义了一个指针,存放原结构体的首地址。
Q3:本来我的成语文档里只有30个成语,后来为了多一点,就把同学已经弄好的成语加了一点上去,发现程序不能运行
S3:在这里,有两个问题,同学的成语清理的格式和我的有点不一样,可能导致我的程序读取错误。第二,一开始,我想的是数据越大越好,所以我定义了1000个结构体,发现程序运行不起来,原因就是超出了范围,也说明了一点。结构体其实也是挺占用空间的,后来我把数据改小了,又把成语的个数减少了,就可以了。
2.小结
本次作业的主要核心是对文件的使用还有对结构体的应用,作完这个试验后,由于先前对结构体和文件没有预习的结果,都得到了一个很好的复习,并且在对数据的处理上,也有了一个小小的提高,但是这次的作业也有一个不足之处,就是我没有将得到的分数进行一个排名,因为用户的数据不止一条,如何得到最后一条数据则是我有点犯难的地方,希望可以通过对同学代码的学习,让自己弥补这个不足。并且在这次的作业里,和上次的函数作业,虽然这次界面效果比上次好了点,但是其实并没有非常美观简洁,但是这次要求的将模块分出来,是使我受益非常大的地方,它让我在调试的时候,减少了非常的多的玛法,以前我总觉得分块这种东西非常麻烦,然后我有很懒,就会把东西都挤到一块去,后面受累的还是我,并且这次的函数起名也给了我很大的帮助,果然代码规范,起名规范,读代码的体验感就是很不一样。