第五节、结构体、联合体、枚举目标:1、结构体应用2、联合体应用3、枚举的应用4、自定义数据类型一、结构体类型学号姓名性别年龄身份证号家庭住址家庭联系电话11301pin.zhangF19320406841001264changzhou(0519)875426711302min.liM20612301830314261xi’an(029)3870909例子:新生入学登记表,要记录每个学生的学号,姓名,性别,年龄,身份证号,家庭住址,家庭联系电话等信息。使用数组:因为要有很多学生的信息要处理,按照我们前面学习过的知识,这个任务要使用数组。但是数组是由相同类型的数据构成。所以我们可以使用7个单独的数组(学号数组no、姓名数组name、性别数组sex、年龄数组age、身份证号数组pno、家庭住址数组addr、家庭联系电话数组tel)分别保存这几类信息。分立的几个数组将给数据的处理造成麻烦,但很多计算机语言只能这样处理(如:早期的FORTRAN,PASCAL,BASIC)。使用结构体:C语言利用结构体将同一个对象的不同类型属性数据,组成一个有联系的整体。也就是说可以定义一种结构体类型将属于同一个对象的不同类型的属性数据组合在一起。本例可以将属于同一个学生的各种不同类型的属性数据组合在一起,形成整体的结构体类型数据。可以用结构体类型变量存储、处理单个学生的信息。结构体是一种自定义数据类型。如果要存储、处理多个学生(对象)的信息,可以使用数组元素为结构体类型的数组,其中每个元素是一个学生(对象)的相关的整体的信息。1.结构体类型和结构体变量结构体是一种构造类型(自定义类型),除了结构体变量需要定义后才能使用外,结构体的类型本身也需要定义。结构体由若干“成员”组成。每个成员可以是一个基本的数据类型,也可以是一个已经定义的构造类型。1、结构体类型定义的一般形式struct结构体名{类型1成员1;类型2成员2;......类型n成员n;};说明:(1)结构体名:结构体类型的名称。遵循标识符规定。(2)结构体有若干数据成员,分别属于各自的数据类型,结构体成员名同样遵循标识符规定,它属于特定的结构体变量(对象),名字可以与程序中其它变量或标识符同名。(3)使用结构体类型时,struct结构体名作为一个整体,表示名字为“结构体名”的结构体类型。(4)结构体类型的成员可以是基本数据类型,也可以是其它的已经定义的结构体类型-结构体嵌套。结构体成员的类型不能是正在定义的结构体类型(递归定义,结构体大小不能确定),但可以是正在定义的结构体类型的指针。例如:定义关于学生信息的结构体类型。structstudent{intno;charname[20];charsex;intage;charpno[19];charaddr[40];chartel[10];};说明:(1)structstudent是结构体类型名,struct是关键词,在定义和使用时均不能省略。(2)该结构体类型由7个成员组成,分别属于不同的数据类型,分号“;”不能省略。成员含义同前。(3)在定义了结构体类型后,可以定义结构体变量(int整型类型,可以定义整型变量)。(4)由于结构体是一种自定义的数据类型,概念上等同于int,char等数据类型。因此,定义了结构体后,并不分配内存空间。只有定义了结构体变量后,才分配内存空间。定义了结构体,只是知道了结构体数据类型的大小。2、结构体变量的定义(三种方法)(1)先定义结构体类型,再定义结构体变量(概念、含义相当清晰),即:结构体类型定义;结构体变量定义;其中:结构体变量定义:struct结构体类型名结构体变量名;例如:structstudent{......};/*类型定义,定义结构体类型structstudent*/structstudentstudent1,student2;/*变量定义,定义2个类型为structstudent的结构体变量student1,student2*/(2)定义结构体类型的同时定义结构体变量。struct结构体名{...(成员)...}结构体变量名表;在这里定义属于结构体类型的变量例如:structstudent{......}student1,student2;说明:•这一种紧凑的格式,既定义类型,也定义变量;如果需要,在程序中还可以使用所定义的结构体类型,定义其它同类型变量。(3)直接定义结构体变量(不给出结构体类型名,匿名的结构体类型)Struct{...(成员)...}结构体变量名表;例如:struct{...}student1,student2;结构体类型、变量是不同的概念:•在定义时一般先定义一个结构体类型,然后定义变量为该类型;•赋值、存取或运算只能对变量,不能对类型;•编译时只对变量分配空间,对类型不分配空间。结构体变量的引用1、)引用结构体变量中的一个成员结构体变量名.成员名其中:“.”运算符是成员运算符。例如:student1.num=11301;scanf(“%s”,student1.name);if(strstr(student1.addr,”shanxi”)!=NULL)...;student1.age++;2、)成员本身又是结构体类型时的子成员的访问-使用成员运算符逐级访问。例如:student1.birthday.yearstudent1.birthday.monthstudent1.birthday.day3、)同一种类型的结构体变量之间可以直接赋值(整体赋值,成员逐个依次赋值)。例如:student2=student1;4、)不允许将一个结构体变量整体输入/输出例如:scanf(“%...”,&student1);printf(“%...”,student1);都是错误的。3.结构体变量的初始化结构体变量也可以在定义时进行初始化,但是变量后面的一组数据应该用“{}”括起来,其顺序也应该与结构体中的成员顺序保持一致。main(){structstudent{intno;charname[20];charsex;intage;charpno[19];charaddr[40];chartel[20];}student1={11301,ZhangPing,'F',19,320406841001264,changzhou,(0519)8754267};printf(no=%d,name=%s,sex=%c,age=%d,pno=%s\naddr=%s,tel=%s\n,\student1.no,student1.name,student1.sex,student1.age,\student1.pno,student1.addr,student1.tel);}结果:no=11301,name=ZhangPing,sex=F,age=19,pno=320406841001264addr=changzhou,tel=(0519)8754267本例中,结构体变量student1在定义的同时,其各个成员也按顺序被赋予了相应的一组数据。4、结构体与数组的比较我们前面学过数组,数组是同种类型的变量的集合,占用一个连续的空间。而结构体,我们通过结构体的定义,我们可以看到,结构体也是一些变量的集合,不过是不同类型的变量的集合。不同的类型,大小也不一致。那么他们的排列就会有一个对齐的问题。我们看例子:typedefstruct_tagData{chara;intb;}DATA;intmain(intargc,char*argv[]){DATAaa;aa.a='a';aa.b=1000;printf(sizeof(aa)=%d\n,sizeof(aa));printf(aa.a=%#x,aa.b=%#x\n,&aa.a,&aa.b);return0;}运行结果:例子显示结构体DATA中的大小是8字节,可是通过结构体的定义,我们看到只有5个字节。在结构体变量中,a的地址是0x12ff78,而b的地址是0x12ff7c,这中间有三个字节空间没有使用。答案就是,它确实没有使用,原因是32位的cpu通常是4字节的整数倍的内存地址中读取数据的。所以编译器为了优化代码,往往会根据变量的大小,将其指定到合适的位置,这就是我们说的内存对齐。例如:struct{chara;intb;charc;intd;chare;intf;charg;inti;}X;struct{chara;charc;chare;charg;intb;intd;intf;inti;}Y;这两个结构体,定义上是完全一样的,只是两者在内部排列顺序上不一致。我们计算这两个变量X,Y的大小时,得到的结果如下:我们可以看到,不同的排列导致结构体占用的内存大小不一样,差别非常明显。因此,我们在定义结构体时,要遵循:同种类型的定义放在一起。如:Y的定义那样。5、结构体数组结构体数组-数组元素的类型为结构体类型的数组。C语言允许使用结构体数组存放一类对象的数据。i.结构体数组的定义类似结构体变量定义,只是将“变量名”用“数组名[长度]”代替),也有3种方式。1、)先定义结构体类型,然后定义结构体数组:struct结构体名{......};struct结构体名结构体数组名[];2、)定义结构体类型同时定义结构体数组:struct结构体名{......}结构体数组名[数组的长度];3、)匿名结构体类型struct{......}结构体数组名[数组的长度];例如:定义30个元素的结构体数组stu,其中每个元素都是structstudent类型。structstudent{charname[20];charsex;charpno[19];charaddr[40];chartel[20];intage;intno;}stu[30];定义了结构体数组后,可以采用:数组元素.成员名。引用结构体数组某个元素的成员,结构体数组的初始化.在对结构体数组初始化时,要将每个元素的数据用“{}”括起来。6.结构体指针变量结构体指针变量:指向结构体变量的指针变量。结构体指针变量的值是结构体变量(在内存中的)起始地址。结构体变量aP结构体指针变量ii.结构体指针变量1)结构体指针变量的定义:struct结构体名*结构体指针变量名;例如:structstudent*p;定义了一个结构体指针变量,它可以指向一个structstudent结构体类型的数据。2)通过结构体指针变量访问结构体变量的成员:(两种访问形式)(1)(*结构体指针变量名).成员名。(理解:*结构体指针变量名=所指向的结构体变量名,注意:“.”运算符优先级比“*”运算符高)(2)结构体指针变量名-成员名(其中:“-”是指向成员运算符,很简洁,更常用)例如:可以使用(*p).age或p-age访问p指向的结构体的age成员。例3:用指针访问结构体变量及结构体数组(数组的指针就是指向其元素的指针,访问数组元素和访问变量所需要定义的指针变量完全相同;指向数组元素和指向变量的指针变量在使用上也完全相同)。参见:example3iii.结构体变量、结构体指针变量作函数参数结构体变量、结构体指针变量都可以像其它数据类型一样作为函数的参数,也可以将函数定义为结构体类型或结构体指针类型(返回值为结构体、结构体指针类型)。例4:对年龄在19岁以下(含19岁)同学的成绩增加10分。参见:example2二联合体(联合,共同体)联合体:将不同类型的数据项存放于同一段内存单元的一种构造数据类型。与结构类似,在联合体内可以定义多种不同数据类型的成员;区别是,在联合体类型变量所有成员共用一块内存单元。(虽然每个成员都可以被赋值,但只有最后一次赋予的成员值能够保存且有意义,前面赋予的成员值被后面赋予的成员值所覆盖)iv.联合体类型、联合体类型变量的定义1、联合体类型定义的一般形式:union联合体名{类型1成员1;类型2成员2;......类型n成员n;};2、联合体类型变量的定义,方法同结构体变量的定义(三种形式,同时,前后,匿名)例如:/*定义联合体类