1第七章结构体、共用体和枚举2本章要点结构体类型的定义和引用结构体数组指向结构体变量的指针共用体枚举3问题的引出•在日常生活中,我们常常会遇到一些需要填写的登记表,如住宿表、成绩表、通讯地址等等。•在职员通讯表中,通常需要登记姓名、工作单位、家庭住址、邮编、电话号码和e-mail等数据项,如图7-1所示。姓名(字符串)工作单位(字符串)家庭住址(字符串)邮编(长整型)电话号码(字符串或长整型)e-mail(字符串)图7-1职员通讯联系表的构成47.1结构体类型的定义定义一个结构体类型的一般形式为:struct结构体名{成员列表};其中,struct是定义结构体类型的关键字,结构体名的命名应符合C语言标识符的命名规则,花括号中的成员列表是由若干成员组成的,这些成员可以是任何基本数据类型的变量,也可以是数组、指针或结构体类型的变量。对结构体类型中的每个成员必须做类型说明,其说明形式如下:类型说明符成员名;其中,成员名的命名与变量名相同。上面提到的职员通讯表中的信息可以用结构体来描述。5•【例7-1】用户自定义一个结构体类型来描述职员通讯表中的信息。•程序:structEmployee{charname[20];/*姓名*/chardepartment[30];/*工作单位*/charaddress[30];/*家庭住址*/longbox;/*邮编*/longphone;/*电话号码*/charemail[30];/*e-mail*/};需要注意的是,在定义结构体类型时不要忽略了“}”后的分号。另外,在同一结构体内各成员的名称不能相同,但不同结构体中的成员名可以相同,并且结构体中的成员名可以与程序中的变量名相同。67.2结构体类型变量的定义和引用•7.2.1结构体类型变量的定义•结构体类型变量定义的一般形式如下:•结构体类型名变量名列表;可以采取以下3种方法定义结构体类型变量:(1)先定义结构体类型,再定义变量名structEmployeeemployee1,employee2;结构体类型名变量名7(2)在声明类型的同时定义变量定义的一般形式如下:struct结构体名{成员表列}变量名表列;例如:structEmployee{charname[20];chardepartment[30];charaddress[30];longbox;longphone;charemail[30];}employee1,employee2;8•(3)直接定义结构体类型变量•其一般形式为:•struct•{•成员表列•}变量名表列;•即不出现结构体名。•注意:•(1)类型与变量是不同的概念,不要混同。我们只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。•注意:•(2)对结构体中的成员,可以单独使用,它的作用与地位相当于普通变量。•(3)成员也可以是一个结构体变量。•(4)成员名可以与程序中的变量名相同,二者不代表同一对象。struct{charname[20];chardepartment[30];charaddress[30];longbox;longphone;charemail[30];}employee1,employee2;9由于结构体类型变量汇集了各类不同数据类型的成员,所以结构体类型变量的初始化就略显复杂。结构体类型变量的定义和初始化为:structEmployee{charname[20];chardepartment[30];charaddress[30];longbox;longphone;charemail[30];};structEmployeeemployee1={”liping”,”Businessdepartment”,”ChangchunChina”,130000,88547362,”liping@163.com”};7.2.2结构体类型变量的初始化10•结构体变量employee1中的各个成员分别赋予初值如下:成员“name”初始化为”liping”,成员“department”初始化为”Businessdepartment”,成员“address”初始化为”changchunChina”,成员“box”初始化为130000,成员“phone”初始化为88547362,成员“e-mail”初始化为”liping@163.com”,其存储示意图如图7-2所示。lipingBusinessdepartmentChangchunChina13000088547362liping@163.com0x20000x20140x20320x20500x20540x20582030304430地址占用字节数图7-2结构体变量employee1的存储示意图117.2.3结构体类型变量的引用引用结构体变量中成员的方式为:结构体变量名.成员名其中,“.”是结构体成员运算符,它在运算符中优先级最高,结合性是自左向右。【例7-2】定义结构体类型的变量并输出各成员的值。#includestdio.hintmain(){structdate{intday;intmonth;intyear;}today;today.day=8;today.month=8;today.year=2008;printf(”Today’sdateis%d-%d-%d.”,today.year,today.month,today.day);return0;}运行结果如下:Today’sdateis2008-8-8.12应遵守以下规则:(1)不能将一个结构体变量作为一个整体进行输入和输出。例如,已定义student1和student2为结构体变量并且它们已有值。不能这样引用:printf(“%d,%s,%c,%d,%f,%s\n”,student1);只能对结构体变量中的各个成员分别进行输入和输出。(2)对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。例如:student2.score=student1.score;sum=student1.score+student2.score;student1.age++;++student1.age;(3)可以引用结构体变量成员的地址,也可以引用结构体变量的地址如:scanf(%d“,&student1.num);printf(“%o”,&student1);但不能用以下语句整体读入结构体变量,如:scanf(%d,%s,%c,%d,%f,%s“,&student1);137.3包含结构体的结构体•在定义结构体方面,C语言为提供了极大的灵活性。例如,可以定义一个结构体,其成员变量是另外一个结构体,或者可以定义成员变量为数组类型的结构体。•前面已经看到如何把年月日组合成为date结构体,在某些应用场合,可能还需要把年月日与职员通讯表结合起来,例如,当需要记录职员生日信息时,可以修改前面定义的结构体类型structEmployee,增加一个structdate类型的成员。14•例如:structdate•{•intmonth;•intday;•intyear;•};•structemployee•{•charname[20];•structdatebirthday;•chardepartment[30];•charaddress[30];•longbox;•longphone;•charemail[30];•}employee1,employee2;•图11-3namebirthdaymonthdayyeardepar-tmentaddressboxphone图7-3存储示意图email15•注:C允许结构体类型的嵌套定义(即结构体类型中包含另一个结构体类型的变量),但不允许递归定义。也就是说,在一个结构体类型中,不允许成员是自身结构体类型的变量,但允许成员是指向自身结构体类型的指针。例如structEmployee{charname[20];chardepartment[30];charaddress[30];longbox;longphone;charemail[30];structEmployeeparents;/*结构体类型的递归定义*/};structEmployee{charname[20];chardepartment[30];charaddress[30];longbox;longphone;charemail[30];structEmployee*p;/*指向自身结构体类型的指针*/};167.4结构体类型数组的定义和引用•一个结构体变量中可以存放一组数据。如果有30个职员的数据需要参加运算,显然应该用数组,这就是结构体数组。结构体数组与以前介绍过的数值型数组不同之处在于每个数组元素都是一个结构体类型的数据,它们又都分别包括各个成员(分量)项。17•7.4.1定义结构体数组•和定义结构体变量的方法相仿,只需说明其为数组即可。例如:structEmployee{charname[20];chardepartment[30];charaddress[30];longbox;longphone;charemail[30];};structEmployeeEmployee[30];•该数组中有30个元素,每个元素的类型都是结构体类型。要获取第一个职员的姓名,即第一个数组元素employee[0]中第一个成员的值,引用形式为employee[0].name。从中可以看出,结构体类型数组的定义方法与结构体变量相似,只需说明它是数组类型即可。因此,结构体类型数组的定义方法也有三种,除了上面介绍的方法外,还可以在定义结构体类型的同时定义结构体类型数组或者以匿名形式来定义结构体类型数组。在具体应用中,如何选择定义的方式与结构体类型变量相同。18•下面举例说明结构体数组的定义与引用。•【例7-3】计算学生的平均成绩以及及格的人数。•程序:#includestdio.h#includestdlib.h#defineN6intmain(){inti,pass=0;floatav,sum=0.0;structStudentType{intnum;char*name;charsex[6]intage;floatscore;};/*定义结构体类型数组并进行初始化*/structStudentTypestudent[N]={{10101,”Zhanghaitao”,”man”,42,98.1},{10102,”Lichunling”,”woman”,22,99.8},{10103,”Wanggang”,”man”,43,96.5},{10104,”Zhaoxin”,”man”,23,16.5},{10105,”Zhangzhenyu”,”man”,51,56.6},{10106,”Dingyundong”,”man”,68,59.4}};/*计算平均成绩及及格学生人数*/for(i=0;iN;i++){sum+=student[i].score;if(student[i].score=60){pass++;}}av=sum/N;printf(”Averagescore:%4.1f\n”,av);printf(”Passingnumber:%d\n”,pass);return0;}运行结果如下:Averagescore:71.2Passingnumber:3197.5结构体与指针•指针变量非常灵活方便,可以指向任一类型变量的起始地址。同样,若定义指针变量指向结构体类型变量,则表示指向该结构体变量的起始地址,因此也可以通过指针来引用结构体类型变量。207.5.1指向结构体类型变量的指针•当指针用来指向一个结构体类型变量时,称为结构体类型指针。结构体类型指针中的值就是所指向的结构体类型变量的首地址。•结构体类型指针定义的一般形式如下:结构体类型名*结构体类型指针变量名结构体指针变量必须先赋值后使用,赋值是将结构