《结构体和共用体》PPT课件.ppt_第1页
《结构体和共用体》PPT课件.ppt_第2页
《结构体和共用体》PPT课件.ppt_第3页
《结构体和共用体》PPT课件.ppt_第4页
《结构体和共用体》PPT课件.ppt_第5页
已阅读5页,还剩92页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

,本章学习C语言的三种数据类型(构造类型):结构体类型,共用体类型,枚举类型。,第7章结构体与共用体,第7章结构体与共用体,7.1结构体类型和结构体类型变量,7.2结构体数组,7.3指向结构体类型数据的指针,7.4内存的动态分配与单链表,7.5共用体,7.6位段,7.7枚举类型,7.8typedef语句,7.1结构体类型和结构体类型变量,7.1.1结构体类型及其定义,7.1.2结构体类型变量的定义,7.1.3结构体类型变量及其成员的引用,7.1.4结构体变量的初始化,7.1.1结构体类型及其定义,数组属于构造类型,数组中的各元素必须属于同一个数据类型。但是在实际生活中,我们经常会遇到有若干各不同类型的数据组合成一个有机的整体。这些组合在一个整体中的数据是互相联系的。例如,要描述一个学生的相关信息:,C语言允许用户自己指定这样一种包含若干个类型不同(当然也可以相同)的数据项的数据结构,它称为结构体(structure)。组成结构体的数据项成为结构体成员。在其他高级语言中称其为“记录”。,结构体是一种构造数据类型,其用途是把不同类型的数据组合成一个整体,当作一个新的数据类型来使用。,在C语言中,用如下方式定义structstudentcharnum10;charname20;charsex;charbirthday8;floatscore3;chartel12;,声明结构体类型时所必须使用的关键字,结构体类型的名称,结构体成员列表,包括每个结构体成员的类型及名称,分号不可少,在structstudent类型起作用的范围内,structstudent和系统提供的标准类型(如int、char、float、double等)一样具有同样的地位和作用,都可以用来定义变量的类型。,定义一个结构体类型的一般形式为:struct结构体名类型标识符成员1;类型标识符成员2;类型标识符成员n;,成员的类型可为除该结构体类型外的任何一种类型,如基本类型、指针类型和结构体类型。,若定义结构体类型structdate如下:structdateintyear;intmonth;intday;则结构体类型structstudent中的成员birthday就可定义为structdatebirthday;这样birthday是结构体类型structdate的变量。,三种形式的定义方法,分别是:,7.1.2结构体类型变量的定义,1.先声明结构体类型再定义结构体变量,一般形式是:struct结构体名变量名表;如structstudentstud1,stud2;structdatedate_1;定义了3个结构体类型的变量stud1,stud2和date_1,前两个是structstudent类型的结构体变量,后者是structdate类型结构体变量。,2.在声明结构体类型的同时定义变量,一般形式是:struct结构体名成员表列变量名表;如:structdateintyear;intmonth;intday;date_2,dd;同样可定义date_2,dd为structdate类型的变量。,3.直接定义结构体类型变量,其一般形式为:struct成员表列;变量名表;即不出现结构体名。如structcharnum10;charname20;charsex;structdatebirthday;floatscore3;chartel12;stud3,stud4;定义了2个结构体类型的变量stud3,stud4。,由于结构体类型的变量是一种构造类型的变量,可引用的对象有两个:变量名代表变量的整体,成员名代表变量的各个成员,二者均可在程序中引用。引用时注意以下规则:,7.1.3结构体类型变量及其成员的引用,1变量成员的引用方法(成员运算符“.”):,如前例在结构体类型structstudent下定义的两个变量stud1,stud2,二变量中的每个成员均可引用,且所引用的成员变量与其所属类型的普通变量一样可进行该类型所允许的任何运算。,例如:aver=(stud1.score0+stud1.score1+stud1.score2)/3;strcpy(,Wangzhe);stud2.score1=stud1.score1;n=dd.year-date_1.year;date_1.year+;day=stud3.birthday.day-;scanf(%s%c%f,,在C语言的运算符中,取成员运算符“”优先级最高,故以上语句均为对引用之后的成员变量进行操作。若结构体定义是嵌套的,则只能引用最低级的成员(用若干“”运算符,逐级引用到最低级)。如stud3.birthday.year是合法的,而stud3.year是非法的。,2.结构体类型变量可以整体引用来赋值。如stud2stud1;即将变量stud1的所有成员的值一一赋给变量stud2的各成员。结构体型变量只能对逐个成员进行输入或输出,不可进行整体的输入输出,如:,printf(%s%s%c%f%f%f%s,stud2);是错误的。,3.结构体类型变量占用的一段存贮单元的首地址称为该结构体类型变量的地址,其每个成员占用的若干单元的首地址称为该成员的地址,两个地址均可引用。如:printf(%o,intmonth;intday;dd=1997,7,1;,structstudentcharnum10;charname20;charsex;structdatebirthday;floatscore3;chartel12;,main()structstudentstud=04010538,F,1983,5,28,86.5,45,97strcpy(,Liulihua);scanf(%f%f,程序执行结果如下:7890.513345678900(键盘输入)04010538Liulihuas198352886.578.090.513345678900199871,7.2结构体数组,7.2.1结构体数组的定义,7.2.2结构体数组的初始化,7.2.3结构体数组的应用,7.2.1结构体数组的定义,结构体数组就是所有元素都是同一类型的结构体数据的数组。结构体数组中的各元素在内存中是连续存放的。定义结构体数组的方法和定义结构体变量的方法相同,也有三种方式。如,structstudentstud510;structchengjiintnum;charname10;floats5;floataver;stu20;定义了两个结构体数组stud5和stu。,结构体数组也可在定义时赋值,即初始化。方法与结构体和数组的初始化相同。如structchengjistu=121,wangfeng,50,60,76,85,90,0,122,lihui,67,87,71,85,58,1,123,gaolu,77,81,67,75,62,2;见图,7.2.2结构体数组的初始化,例7-2学生信息structchengji的结构体类型,为求4个学生的5门功课成绩的平均分并输出。程序如下:,7.2.3结构体数组的应用,main()inti,j;floatsum;structchengjiintnum;charname10;floats5;floataver;stu=111,zhangsan,67,89,76,54,86,105,lisi,87,73,88,75,78,111,wangwu,79,82,56,64,77,107,qianliu,60,53,91,75,65,0;,for(i=0;i4;i+)sum=0.0;for(j=0;j5;j+)sum=sum+stui.sj;stui.aver=sum/5.0;printf(%d%-10s%3.0f%3.0f%3.0f%3.0f%3.0f%5.1fn,stui.num,,stui.s0,stui.s1,stui.s2,stui.s3,stui.s4,stui.aver);程序执行结果是:,111zhangsan678976548674.4105lisi877388757880.2111wangwu798256647771.6107qianliu605391756568.8,结构体变量可以作为函数的参数,此时是值传递。例7-3用函数实现例7-2的求平均值的运算。程序如下:structchengjiintnum;charname10;floats5;floataver;,floatf(structchengjistud)intj;floatsum=0;for(j=0;j5;j+)sum=sum+stud.sj;returnsum/5.0;,main()inti,j;structchengjistu=111,zhangsan,67,89,76,54,86,105,lisi,87,73,88,75,78,111,wangwu,79,82,56,64,77,107,qianliu,60,53,91,75,65,0;for(i=0;i4;i+)stui.aver=f(stui);printf(%d%-10s%3.0f%3.0f%3.0f%3.0f%3.0f%5.1fn,stui.num,,stui.s0,stui.s1,stui.s2,stui.s3,stui.s4,stui.aver);此程序与例7-2程序的执行结果一致。但结构体structchengji应为外部结构体类型。,例7-4有10个选举人,3个候选人,每人只能投一个候选人的票,统计3个候选人的总票数。程序如下:#includestdio.h#includestring.hstructpersoncharname8;intcount;leader3=ZHANG,0,WANG,0,LI,0;,main()inti,j;charlead_name8;for(i=1;i=10;i+)scanf(%s,lead_name);for(j=0;j”是指向运算符(通过指针存取成员),方法2:(*结构体变量的指针).成员项名,例7-5用指针引用结构体成员的例子。#includestring.hstructabccharname10;charsex;intsalary;,main()structabcww,*p=程序执行结果是:,wanghaoM1234wanghaoM1234wanghaoM1234可见,三种方式对结构体成员引用的效果是相同的。,使用指向结构体数组的指针来访问数组,既方便了数组元素的引用,又提高了数组的利用率。例7-6用结构体数组的指针完成例7-2。程序如下:,7.3.2指向结构体数组的指针,main()inti,j;floatsum;structchengjiintnum;charname10;floats5;floataver;*p,stu=111,zhangsan,67,89,76,54,86,105,lisi,87,73,88,75,78,111,wangwu,79,82,56,64,77,107,qianliu,60,53,91,75,65,0;,p=stu;for(i=0;isj;stui.aver=sum/5.0;printf(%d%-10s%3.0f%3.0f%3.0f%3.0f%3.0f%5.1fn,p-num,p-name,p-s0,p-s1,p-s2,p-s3,p-s4,p-aver);,程序执行结果不变。注意,p的初值是数组stu的首地址,通过p+指向不同的数组元素。,假如p指向第2个数组元素(lisi),请同学们分析p-s0、p-s0+、(p-s0)+、(+p)-s0和(p+)-s0分别会得到什么结果。,将一个结构体变量的值传递给另一个函数,有3个方法:用结构体变量的成员作实参用法和用普通变量作实参是一样的,属于“值传递”。2.用结构体变量作参数用法和用普通变量作参数是一样的,也属于“值传递”。3.用指向结构体变量(或数组)的指针作参数属于“地址传递”,程序效率高。,7.3.3指向结构体数组元素的指针,例7-7用指向结构体变量(或数组)的指针作参数,求n个学生的平均成绩最高的学生的信息并输出。structCJintnum;charname10;floats5;floataver;,structCJ*fun(structCJ*pstud,intn)structCJ*p,*p_max,*p_end;intj;floatmax=0;p=pstud;p_max=p;p_end=p+n;for(;psj;sum=sum/5.0;p-aver=sum;if(summax)max=sum;p_max=p;returnp_max;,返回结构体structCJ类型指针的函数fun,main()inti,j;structCJ*pp,stu=111,zhangsan,67,89,76,54,86,105,lisi,87,73,88,75,78,111,wangwu,79,82,56,64,77,107,qianliu,60,53,91,75,65,0;pp=fun(stu,4);printf(%d%-10s%3.0f%3.0f%3.0f%3.0f%3.0f%5.1fn,pp-num,pp-name,pp-s0,pp-s1,pp-s2,pp-s3,pp-s4,pp-aver);,程序执行结果如下:105lisi877388757880.2,7.4内存的动态分配与单链表,本节先给出数据在计算内存中进行动态分配的概念和内存分配函数,然后介绍单链表及其有关操作的函数,它是动态分配内存、结构体、指针的综合应用。,7.4内存的动态分配与单链表,7.4.2内存分配函数,7.4.1数据的存储结构,7.4.3链表的概念,数据的存储结构分为顺序存储结构、链式存储结构。,7.4.1数据的存储结构,顺序存储结构用数组(内存空间连续)实现,插入和删除需移动大量元素,数组的大小需预先分配(静态存储)。,链式存储结构(动态存储)内存空间可以不连续,插入和删除不需移动元素。,C语言提供了专门用来进行动态存储分配的标准库函数。头文件名为stdlib.h或malloc.h。1.malloc函数函数原型:void*malloc(unsignedsize)功能:分配size个字节的存储区。返回值:所分配的内存区地址,若内存不够,返回0。2.Free函数函数原型:voidfree(p)功能:释放p所指的内存区。返回值:无。,7.4.2内存分配函数,3.calloc函数函数原型:void*calloc(unsignedn,unsignedsize)功能:分配n个数据项的内容的连续空间,每个数据项的大小为size。返回值:所分配的内存区地址,若内存不够,返回0。,例7-8动态分配内存的例子。#includestdlib.hmain()double*p,*q;printf(%o%on,程序执行结果如下:177716177720p=4576*p=1000000.0q=4576*q=2000000.0p=4576*p=2000000.0,链表是由零个或多个结点用链接指针串联在一起的数据结构。零个结点的链表称空链表。链表有单向链表、双向链表、循环链表等,我们在此只讨论单向链表,简称单链表。为方便叙述,以后提到链表均指单链表。链表中的每个结点的数据有两部分组成,即数据元素的信息和链接指针信息。图7-3是字符串CHINA的链表示意图。,7.4.3链表的概念,图7-3,图中,head称为链表头指针,对链表的访问必须从头指针开始,逐个结点进行访问,指针值为NULL即0的结点是链表的最后一个结点。可以说,头指针链表的唯一标识。为以后对链表尽心处理的方便,在链表的第1个结点之前附加一个结点,称其为头结点,链表的头指针指向头结点,头结点的指针指向链表的第1个结点。以后若不加说明,链表均带有头结点。,在C语言中,链表的存储又是如何具体实现呢?,定义一个结构体类型,结构体类型的成员中除包括数据元素的信息外,应有一个指针变量。,对上面的链表,其结构体类型及指针变量可定义如下:structstringchardata;structstring*next;*head,*p1,*p2;,链表的操作主要有建立链表、输出链表、求链表的长度、查找结点、插入结点、删除结点、合并链表、逆置链表等。,7.4.4链表的基本操作,下面以结构体类型structlistintnum;floatdata;structlist*next;为数据结构,逐一给出实现上述操作的函数。,1.建立链表建立链表的过程是从无到有的逐个为结点动态分配空间、输入结点内容、建立链接的过程。,建立链表的方法有头插法和尾插法两种。,头插法是新建的结点总是插在已有链表的第1个结点之前,成为新的第1个结点。,尾插法两种是新建的结点总是插在已有链表的最后一个结点之后,成为新的最后一个结点。,头插法建立链过程见图7-4。,(a)空链表L,(b)开辟新结点s,(c)s插到L的首结点之前,(d)重复(b)和(c),直到所有结点插入完毕。,L,S,L,S,L,S,L,算法的思路是:,1.设置两个指针变量L和s,L是头指针,s始终指向新开辟的结点;,2.先开辟一个新结点,令其指针域为NULL,让L指向该结点,得到一个空链表;,3.开辟新结点s,给s的数据成员赋值,把s插入到第1个结点之前,即令s-next=L-next;L-next=s;注意,次序不可颠倒。,4.重复第3步,直到结束。,例7-10用头插法建立链表。structlist*CreateFromHead()structlist*L,*s;intno,flag=1;floatx;L=(structlist*)malloc(sizeof(structlist);L-next=NULL;while(flag)scanf(%d%f,(a)空链表L,(b)开辟新结点s,(c)s插到L的首结点之后,(d)开辟新结点s,图7-4尾插法建立链表示意图,(e)s插到L的首结点之后,(f)插入3个结点后的链表L,算法的思路是:,1.设置3个指针变量L、s和r,L是头指针,s始终指向新开辟的结点,r是为指针,即r始终指向链表的最后一个结点指针;,2.先开辟一个新结点,令其指针域为NULL,让L指向该结点,得到一个空链表,令r=L;,3.开辟新结点s,给s的数据成员赋值,把s插入到最后一个结点之后,即令r-next=s;r=s;注意,次序不可颠倒。,4.重复第3步,直到结束。令r-next=NULL,例7-11用尾插法建立链表。structlist*CreateFromTail()structlist*L,*s,*r;intno,flag=1;floatx;L=(structlist*)malloc(sizeof(structlist);r=L;while(flag)scanf(%d%f,2输出链表建立的链表是必须要打印输出的。输出链表就是从链表的第1个结点开始,输出每个结点的数据,直到最后一个结点的指针域为空为止。,例7-12输出链表中的各个结点。voidPrintLinkList(structlist*Head)structlist*L,*p;p=Head-next;while(p!=NULL)printf(%5d%5.1fn,p-num,p-data);p=p-next;printf(n);,3.求链表的长度链表的长度就是链表所包含的结点个数(不含头结点),方法与输出链表类似。,例7-13求链表的长度。intListLength(structlist*L)structlist*p;intj;j=0;p=L-next;while(p!=NULL)/while(p)p=p-next;j+;returnj;,例7-14建立链表、并输出链表结点及长度的主函数。,#defineNULL0#includestdio.h#includestring.hstructlistintnum;floatdata;structlist*next;,main()structlist*Head,;Head=CreateFromHead();/*Head=CreateFromTail();*/PrintLinkList(Head);printf(“LISTLength=%d”,ListLength(Head);,4.查找指定的结点查找指定的结点最终是获得结点的指针,故函数通常定义为返回指针值的函数。,分为按结点的序号查找和按结点的值查找两种情况。,由于链表不能进行直接存取,要访问链表的第i个结点,必须从头指针开始,顺序找到第i个结点。同样,要访问链表的某成员值为key的结点,也从头指针开始,顺序找到其成员值为key的结点。,例7-15按结点的序号查找,返回结点的指针。,注意:循环条件p-next!=NULL不能写p!=NULL。,structlist*GetNode(structlist*L,inti)structlist*p=L;intj=0;while(p-next!=NULL,例7-16按结点的值(本例按data值)查找,返回结点的指针。,structlist*LocateKey(structlist*L,intkey)structlist*p=L-next;while(p!=NULL)if(p-data!=key)p=p-next;elsebreak;returnp;,5.删除结点对于单链表来说,要删除一个结点(设指针为r),必须找到该结点的直接前驱结点的指针(设为p),令p-next=r-next;free(r);则可可删除结点r并释放其内存空间。pr,图7-6删除结点的示意图,例7-17删除第i个结点并带回其num、data值。,intDeleteNode(structlist*L,inti,int*num1,int*data1)structlist*p=L,*r;intk=0;while(p-next!=NULL,if(k!=i-1)printf(DeleteNo.error!n);return0;r=p-next;*num1=r-num*data1=r-data;p-next=r-next;free(r);returnOK;,注意:被删除结点的num、data成员的值是通过指针变量带回的。,6.插入结点,要在第i个结点前插入一个值为num1、data1的结点,也必须先找到该结点的直接前驱结点的指针(设为pre),然后开辟新结点并赋值,最后令s-next=pre-next;pre-next=s使s插入到pre之后。,图7-7插入结点的示意图,例7-18在第i个结点前插入一个值为num1、data1的结点。,intInsertNode(structlist*L,inti,intnum1,intdata1)structlist*pre=L,*s;intk=0;while(pre!=NULL,if(k!=i-1)printf(InsertNO.error!n);return0;s=(structlist*)malloc(sizeof(structlist);s-num=num1;s-data=data1;s-next=pre-next;pre-next=s;returnOK;,7.5共用体,7.5.1共用体的概念,7.5.2共用体类型及共用体类型变量的定义,7.5.3共用体变量的引用,7.5.4使用共用体应注意的问题,7.5.1共用体的概念,C语言允许用户把若干个不同类型的数据组合在一体,作为结构体类型,也可作为共用体类型,二者都属于构造类型。,二者的不同之处在于:,结构体类型中各个成员分别占用一定个存储单元数据;,共用体类型中各个成员占用同一起始地址的存储单元;(使用覆盖技术,使几个变量相互覆盖)。,这种使几个不同的变量共同占用同一段内存的结构,称为共用体类型的结构。,公用体类型的定义形式为:union公用体名成员表列;公用体的成员表列的定义与结构体相同。有了公用体类型就可以定义公用体类型变量,同结构体一样,公用体类型变量也有三中定义方式。如,7.5.2共用体类型及共用体类型变量的定义,uniondatacharc;inti;floatf;a,b;,unioncharc;inti;floatf;a,b;,以及先定义公用体类型uniondata,在定义变量a,b为uniondata类型,即uniondataa,b;都是定义了公用体类型变量a,b。,图7-9公用体类型变量a在内存中的存储情况,公用体类型变量a,b在内存中各占4个字节(见图7-9),正好是占用字节数最多的成员所需的字节数。如果是以上述3个成员定义的结构体变量,则每个结构体变量在内存中各占7个字节。,7.5.3共用体变量的引用,共用体类型变量的引用方式与结构体类型变量的引用方式相同。,如共用体型变量a的成员引用可以是scanf(“%d”,printf(“%f”,a.f);,但其整体引用,如:printf(“%d”,a);a=5;k=a;等都是错误的。,(1)一个共用体型变量可以用来存放几种不同类型的成员,自然无法同时实现。,7.5.4使用共用体应注意的问题,(2)共用体型变量的地址和它的各成员的地址同值,如上述共用体型变量a在内存中存放的情形如图7-9所示,所以num;,printf(Inputthenumberstype(i,c,f,d):n);num.type_flag=getchar();printf(Inputthenumbern”);switch(num.type_flag)casei:scanf(%d,xh.xb=8;xh.zy=2;xh.bj=3;xh.sx=23;,但应注意位段允许的最大值范围。(unsignedbj:3;)如令xh.bj=9,系统只将1001后位001赋给了xh.bj,xh.bj的到的值是1.,(1)一个位段必须被说明成int,unsigned或signed中的任一种。长度为1的位段被认为是unsigned类型,因为单个位不可能具有符号。(2)位段中成员的引用与结构体类型中成员的引用一样,用“”运算符。比如:xh.xb=8表示引用位段变量xh中的第2位,它的值是015中的一个。(3)可定义无名位段,如:,7.6.2使用位段应注意的问题,structunsigneda:1unsignedb:2unsigned:5unsignedc:8,(4)一个位段必须存贮在同一存贮单元中,不能跨两个单元。(5)位段可在表达式中被引用(按整型数),也可用整型格式符输出。,7.7枚举类型,7.7.1枚举类型与枚举类型变量的定义,7.7.2枚举类型变量在使用中的几点说明,如果一个变量只有几种可能的值,可以定义为枚举类型。所谓“枚举”是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。,7.7.1枚举类型与枚举类型变量的定义,声明枚举类型用enum开头。,例如:enumweekdaysun,mon,tue,wed,thu,fri,sat;,声明了一个枚举类型enumweekday,可以用此类型来定义变量。,如enumweekdayworkday,week_end;定义workday和week_end为枚举类型变量,它们的值只能是sun到sat之一。,如workday=mon;week_end=sun;是正确的。,声明枚举类型的同时定义枚举变量,如,enumweekdaysun,mon,tue,wed,thu,fri,satworkday,week_end;,其中sun、mon、sat等称为枚举元素或枚举常量。它们是用户定义的标识符。这些标识符并不自动地代表什么含义。例如,不因为写成sun,就自动代表“星期天”。,(1)在C编译系统中,对枚举元素按常量处理,故称枚举常量。它们不是变量,不能对它们赋值。,7.7.2枚举类型变量在使用中的几点说明,(2)枚举元素作为常量,它们是有值的,C语言编译按定义时的顺序使它们的值为0,1,。如在上面的定义中,sun=0,mon=1,sat=6。也可在定义是改变枚举元素的默认值,如enumweek

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论