zoukankan      html  css  js  c++  java
  • c博客06-2019-结构体&文件

    1.本章学习总结

    1.1 学习内容总结

    整理结构体和文件这两章主要知识点,必须包含内容有:

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

    • 结构体一般形式
    struct  结构体名
        {
         数据类型   成员名1;
         数据类型   成员名2;
         :
         数据类型   成员名n;
         };
    
    • 结构体的定义及赋值
      • 先定义结构体类型再定义变量名,这是C语言中定义结构体类型变量最常见的方式。
          struct 结构体名
         {
                 成员列表;
         };
         struct 结构体名 变量名;
    
    - 在定义类型的同时定义变量。这种形式的定义的一般形式为:
    
    struct 结构体名
            {
                      成员列表;
            }变量名; 
    
    - 直接定义结构类型变量。其一般形式为:
    
    struct      //没有结构体名
             {
                       成员列表;
              }变量名;
    

    2.结构体数组排序做法

    • 结构体数组的排序方法与之前数组的排序方法差别并不大,这里列举一道学生信息按成绩排序的冒泡排序
    /*
    name:学生信息结构体  按总分排序 (降序)
    */
    
    
    #include<stdio.h>
    typedef struct {//结构体 定义时尽量放main()外面 
    	int grade;
    	int age;
    	char name[10];
    }Student;
    
    
    int main()
    {
    	int i, j;
    	Student temp;
    
    	Student student[3] = {/*分成多条初始化,更清晰*/ 
    	{600,18,"小明"},
    	{550,19,"小红"},
    	{700,20,"tom"},
    	};
    
    	  /*用结构体指针---提高效率*/
    	  /*冒泡排序*/
    
    	Student* p = student;
    	for (i = 1; i <= 2; i++)
    	{
    		for (j = 0; j <= 3 - i - 1; j++)//大-->小 
    		{
    			if ((p + j)->grade < (p + j + 1)->grade)
    			{
    				temp = *(p + j);
    				*(p + j) = *(p + j + 1);
    				*(p + j + 1) = temp;//注意 temp 的类型为Student 
    
    			}
    		}
    	}
    
    	/*以表的形式输出*/
    	printf("姓名    年龄    分数  
    
    ");//表头 
    	for (i = 0; i <= 2; i++)
    	{
    		printf("%-4s   %4d     %4d
    ", (p + i)->name, (p + i)->age, (p + i)->grade);
    	}
    
    	getchar();
    	return 0;
    }
    
    

    3.结构体指针怎么用
    在C语言使用中,随着知识的深入,我们结构体用到的机会很多。

    • 首先让我们定义结构体:
    struct stu
    {
    char name[20];
    long number;
    float score[4];
    };
    
    • 再定义指向结构体类型变量的指针变量:
    struct stu *p1, *p2 ;
    
    • 定义指针变量p 1、p 2,分别指向结构体类型变量。引用形式为:指针变量→成员;
    #include<stdio.h>
    #include <stdlib.h> //使用m a l l o c ( ) 需要
    struct data //定义结构体
    {
    	int day, month, year;
    };
    struct stu //定义结构体
    {
    	char name[20];
    	long num;
    	struct data birthday; //嵌套的结构体类型成员
    };
    int main() //定义m a i n ( ) 函数
    {
    	struct stu* student; //定义结构体类型指针
    	student = malloc(sizeof(struct stu)); //为指针变量分配安全的地址 
    	printf("Input name,number,year,month,day:/n");
    	scanf("%s", student->name); //输入学生姓名、学号、出生年月日
    	scanf("%ld", &student->num);
    	scanf("%d%d%d", &student->birthday.year, &student->birthday.month,
    		&student->birthday.day);
    	printf("/nOutputname,number,year,month,day/n");
    	/*打印输出各成员项的值*/
    	printf("%20s%10ld%10d//%d//%d/n", student->name, student->num,
    		student->birthday.year, student->birthday.month,
    		student->birthday.day);
    }
    

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

    • 共用体是一种多变量共享存储空间的构造类型,它允许几种不同的变量共用同一存储空间。
    • 共用体和结构体的区别:
      • 1.结构体每一位成员都用来表示一种具体事务的属性,共用体成员可以表示多种属性(同一存储空间可以存储不同类型的数据)。
      • 2.结构体总空间大小,等于各成员总长度,共用体空间等于最大成员占据的空间。
      • 3.共用体不能赋初值。

    枚举类型

    • 枚举类型是指变量的值可以全部列出,定义一个枚举变量后,变量的值确定在定义之中。
    • 它和结构体、共用体的区别在于,枚举元素是常量,只能在定义阶段赋值。

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

    • 对文件的读和写是最常用的文件操作。在C语言中提供了多种文件读写的函数:
      • 字符读写函数 :fgetc和fputc
      • 字符串读写函数:fgets和fputs
      • 数据块读写函数:freed和fwrite
      • 格式化读写函数:fscanf和fprinf
    • 打开文件函数为fopen(),具体形式为
    fopen(“文件名”,“文件打开方式”);
    
    • 文件打开方式,具体有
    r	打开只读文件
    w	打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件
    a	以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留
    r+	打开可读写的文件
    w+	打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件
    a+	以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留
    

    1.2 本章学习体会

    学习感受
    学到现在,新的东西越来越多,平时觉得缺漏并不多,但是一到大作业时才发现自己的不足之处还有很多。这个学期很快就要结束了,我们的C语言课程也要迎来结束,在这个时候,查缺补漏才更为重要。在这两周学习的文件与结构体中,一开始确实感觉很难,但是运用时候,发现函数真的变得简洁了很多,尤其是多文件编程,好几百行代码在一个文件中的情况载用不会出现了。但是在结构体的运用中,尤其结构体数组和指针,老师讲的时候感觉指向的地址都很明了,但是自己在写的时候经常出错,果然还是练习的不够多...到期末了,各种各样的考试、总结和复习接踵而至,这两周对代码量也有所疏忽,希望能尽快赶上!

    2.综合作业--“我爱成语”(8分)

    本次作业要编写一个成语游戏。用户登录后,系统随机出若干个成语,如果答对则得分。用户得分写入成绩文件。系统能对用户成绩排名
    

    主要功能:

    • 登陆:需要输入正确用户名和 密码,才能登陆系统。错误提示错误的信息。
    • 成语游戏:从成语文件中随机抽一个成语,随机展示2个汉字,用户猜剩余汉字。如果答对,则得分。错误,给相应信息。
    • 排名:系统跟用户得分排名。
    • 退出。

    要求:

    • 本次作业必须建工程实现C的多文件。其中结构体定义、函数定义等都要封装在自定义头文件中。一个模块对应一个.h文件和.c文件。数据定义和数据实现分离。
    • 用户登录、排名信息的数据请封装结构体实现。
    • 涉及3个数据文件:user.txt、ranking.txt、idiom.txt
    • 尽量减少全局变量使用,数据传递通过地址、参数等传递。学会利用函数形参、返回值实现独立功能。
    • 菜单界面友好,任何一步都能随时推出,程序也 不会崩溃。程序界面要有清屏。
    • 尽量写一个函数调试一个函数,保证函数能读写文件数据再做下面内容。

    数据说明:

    • user.txt :用户名、密码
    • ranking.txt:用户名,答题总分数、最后答题时间。注意:答题分数是每次分数的积累,如答对一题5分,下一次同一个用户名再玩,这里数据能累加或更新。
    • idiom.txt:成语、成语解释。注意:给大家数据还包含数字,建议对数据预处理下,把数据改造成规范格式。成语:成语解释。出现其他如【】、数字等都过滤掉。数据统一格式才好读写。

    扩展功能

    • 本题可以做一个成语字典,用户输入成语,可以查询相应成语解释。这个查询可以是模糊查询,就是用户只输入一个汉字也可以查询所有相关的成语内容。
    • 游戏玩法可以多样,比如也可以做成语接龙,你写一个成语,根据最后一个汉字,系统能接龙下一个成语。如果是人机互玩,不是接龙规则,可提示。

    2.1.文件介绍

    头文件介绍


    • 头文件1:idiom.h
      功能介绍:定义了多个函数;IDIOM结构体:用于读取成语内容并储存;USER结构体:用于读取登录所需的账号与密码并储存。

    2.函数实现文件介绍。


    • 文件1:main.c。
      功能:令程序正常进行
      思路:在设计时,想主函数尽可能的简洁,因此大部分功能都使用了函数进行单独封装。

    • 文件2:users.c
      功能:读取并储存账号与密码,实现登录功能。
      思路:与林丽老师上课讲过的一样,同时借鉴了课堂派上的内容,定义了USER结构体来实现登录系统。

    • 文件3:Change.c
      功能:作为连接系统,打开并读取成语文件,是竟然两个主要功能的连接口,同时也可以有切换登录用户的功能。
      思路:因为老师说过一般打开文件都在主函数中打开,避免多次开关文件导致运行时间过长,因此一开始是把该函数的内容放在主函数中,但是后来为了实现切换登录用户的功能,写了这样一个函数。(个人能力有限)

    • 文件4:GetIdiomsData.c
      功能:最关键的将成语文件的成语内容与注释内容分开储存,并返回成语的个数number。
      思路:定义了IDIOM结构体数组来进行分别储存成语名与注释。

    • 文件5:Issue.c
      功能:出题系统,进行成语随机挖去两个空出题。同时在函数末尾进行一个继续或返回的选择。
      思路:在一开始进行写代码时,想通过遍历来随机出题,但是代码太长而且极易崩溃,让我挺头疼的。后来借鉴了同学的思路与代码,直接运用随机数来进行选择输出的成语和抹除的两个位置,同时运用复制函数,也避免了再重新定义一个数组。

    • 文件6:Search.c
      功能:查找系统,当用户输入文件中有的成语,输出该成语的意思。
      思路:因为成语名和注释已经分别储存了,且对应的成语和注释下标一样,所以只要利用循环遍历进行寻找即可。

    • 文件7:ListMenu.c
      功能:菜单函数
      思路:对用户进行提醒

    • 文件8:Choice.c
      功能:输入选择的功能并返回输入的选项choose
      思路:通过输入来进入不同的功能。

    • 文件9:End.c
      功能:结束函数,代表程序的结束
      思路:当用户选择退出时可以跳出,最后来到这个函数

    2.2.运行结果

    1.登录界面

    2.游戏界面



    3.查找界面


    2.3大作业总结

    1.碰到问题及解决办法

    • 首先是在出题函数,这个函数几乎花掉了一整个晚上的时间来写,删了许多次。一开始是定义了一共新的指针,令它直接等于随机出来的成语名,结果发现抹去字符后新定义的指针也一起被改变了,后来改用了复制函数才解决。其次是我之后删去了新指针,而是用了idiom[num + 2].IdiomName来储存。这样做其实是有弊端的,因为我事先知道我定义的数组内容远大于成语个数num,所以idiom[num + 2].IdiomName中其实是没有内容的,当时为了节约时间,也觉得这样可以避免重新定义指针占用更多的空间,就这么定义了。
    • 这次第一次使用清屏函数,刚刚开始老是用错地方,把有用的内容清掉。后来还是要一次一次调试慢慢改过来。
    • 这次大量使用了while(1)循环,没有写好条件容易造成死循环,每次写完都要经过多次调试才能确保没有问题。
    • 在读取文件内容时,因为不是操作不是很熟练,好多次没有加终止符号,再加上之前没有调好的while(1)循环,结果跳出来满屏的,吓了一跳,后来发现是在分离储存成语与注释的时候,在成语名赋值结束的末尾忘记加了。
    • 在写了很多次排名函数后都出现了运行错误或者引发异常的情况,不知道怎么处理,所以后面就先删去了排名函数,先完成其他功能。但是到现在还行没写出来,后续应该会慢慢地完善功能。

    2.小结

    • 一开始布置大作业时真的是不知从何下手。一共两周的时间,前一周基本都在构思作业思路,陆陆续续写了一些代码,这一周在林丽老师又复习过一次文件,已经机房课的指导后逐渐有了一些想法。但这周又碰到英语的4级考试 ,所以之前一直都是只完成了框架,大部分的内容是在这两天写出来的。
    • 个人感觉,相对于上一次,这一次写大作业的感觉要好得多,对于函数的运用也熟练了起来。但是对于新学习的知识,比如文件的运用,结构体的运用等还是不够熟练。(果然还是能力限制了我的发挥...)
    • 个人在运用指针的时候还是很生疏,以后还是要多练习指针内容。
    • 这一次对于一些新内容,比如清屏函数的运用多了起来。
  • 相关阅读:
    生成客户端信任的证书文件
    postgresql Streaming Replication监控与注意事项
    采用pacemaker+corosync实现postgresql双机热备、高可用方案
    51nod1305(简单逻辑)
    51nod1091(贪心)
    51nod1009(1的数目)
    51nod1102(数塔)
    51nod1459(带权值的dijkstra)
    51nod1265(判断四个点是否共面)
    51node1264(判断线段相交)
  • 原文地址:https://www.cnblogs.com/caihaoweideboke/p/12045575.html
Copyright © 2011-2022 走看看