
第09章结构体、共用体和枚举类型.ppt
33页第第9 9章章 结构体、共用体和枚举类型结构体、共用体和枚举类型9.1 9.1 结构体的定义及应用结构体的定义及应用9.2 9.2 位域位域* *9.3 9.3 共用体的定义及应用共用体的定义及应用9.4 9.4 枚举类型枚举类型9.1 9.1 结构体的定义及应用结构体的定义及应用•设每个学生的数据包括:设每个学生的数据包括:–姓名:字符型数组姓名:字符型数组–年龄:无符号整型年龄:无符号整型–成绩:单精度浮点类型成绩:单精度浮点类型 如何存放如何存放1010位学生的原始数据?位学生的原始数据?解:解:定义定义3 3个数组分别存放个数组分别存放1010位学生的姓名、年龄和成绩,位学生的姓名、年龄和成绩,用数组下标区别不同的学生:用数组下标区别不同的学生:–char name[10][20]; //char name[10][20]; //存放存放1010位学生的姓名位学生的姓名–int age[10]; // int age[10]; // 年龄年龄–float score[10]; // float score[10]; // 成绩成绩 用用name[i]name[i]、、age[i]age[i]和和score[i]score[i]表示第表示第i i个学生数据。
个学生数据•不足:变量多、未直接反映同一学生数据间的联系不足:变量多、未直接反映同一学生数据间的联系•改进:改进: ① ①定义结构体类型,描述同一学生的多个数据:定义结构体类型,描述同一学生的多个数据: struct struct studentstudent{ {////反映同一学生数据间的联系反映同一学生数据间的联系 char name[20]; // char name[20]; //姓名姓名 int age; // int age; //年龄年龄 float score; // float score; //成绩成绩 }; }; ② ②定义定义studentstudent类型的数组,存放类型的数组,存放1010位学生的数据:位学生的数据: student s[10]; //student s[10]; //变量少变量少•结构体可将不同类型的数据组织为一个整体结构体可将不同类型的数据组织为一个整体9.1.1 9.1.1 结构体类型的定义结构体类型的定义•结构体类型需先定义后使用,其定义格式:结构体类型需先定义后使用,其定义格式: struct struct 结构体类型名结构体类型名{ { 类型类型1 1 成员成员1;1; 类型类型2 2 成员成员2; 2; …… …… }; };说明说明–结构体类型名用标识符表示。
结构体类型名用标识符表示–成员可以是基本类型或导出类型的变量,不成员可以是基本类型或导出类型的变量,不能指定存储类型为能指定存储类型为autoauto、、registerregister、、externextern,,但可指定存储类型为但可指定存储类型为staticstatic–定义结构体类型用分号定义结构体类型用分号“;”“;”表示结束表示结束–结构体类型是一个存储模型,本身不占内存,结构体类型是一个存储模型,本身不占内存,仅当定义其变量时,系统才按此存储模型为仅当定义其变量时,系统才按此存储模型为其变量分配相应的内存其变量分配相应的内存9.1.2 9.1.2 结构体类型变量的定义结构体类型变量的定义•定义结构体类型变量的格式为:定义结构体类型变量的格式为: 结构体类型名结构体类型名 变量列表变量列表; ;或或 struct struct 结构体类型名结构体类型名 变量列表变量列表; ; 其中,结构体类型名为已定义的类型;多个变量之间其中,结构体类型名为已定义的类型;多个变量之间用逗号分隔;后一种格式与用逗号分隔;后一种格式与C C兼容•例如:例如: student s1,s2,s3[10];student s1,s2,s3[10];或或 struct student s1,s2,s3[10];struct student s1,s2,s3[10];studentstudent类型变量类型变量s1s1的内存分配图的内存分配图…•按按studentstudent类型的存储类型的存储模型为其变量模型为其变量s1s1分配内分配内存。
存•studentstudent类型的存储模类型的存储模型所需内存字节数:型所需内存字节数: sizeof(student)sizeof(student)•s1s1变量各成员在内存中变量各成员在内存中的顺序与其类型中成员的顺序与其类型中成员说明的顺序一致说明的顺序一致name占占20字节字节age占占4 4字节字节score占占4 4字节字节结构体类型变量定义的其他形式结构体类型变量定义的其他形式•结构体类型变量也可在声明结构体类型的同时定义结构体类型变量也可在声明结构体类型的同时定义•例如:例如: struct Date{struct Date{ int year,month,day; int year,month,day; } }today,yesterdaytoday,yesterday; ;•再如:再如: struct{ // struct{ //定义一个无名结构类型定义一个无名结构类型 int a; int a; float b; float b; } }x,yx,y; ; 无名结构体类型不能在该类型定义之外定义其变量。
无名结构体类型不能在该类型定义之外定义其变量结构体类型变量的初始化结构体类型变量的初始化•结构体变量的初始化:与数组的初始化方式类似,在结构体变量的初始化:与数组的初始化方式类似,在花括号中,按结构体成员说明的顺序依次列出其值花括号中,按结构体成员说明的顺序依次列出其值•例如:例如: student s1 student s1={"Jenny",20,98}={"Jenny",20,98}; ; Date today Date today={2007,1,2}={2007,1,2}; ; struct Complex{struct Complex{ float real,image; float real,image; }c1 }c1={2.0f,3.0f}={2.0f,3.0f},c2;,c2;9.1.3 9.1.3 结构体类型变量的使用结构体类型变量的使用•访问结构体变量成员的格式为:访问结构体变量成员的格式为: 结构体变量结构体变量. .成员名成员名 其中其中“.”“.”是成员访问运算符例如:是成员访问运算符例如: today.yeartoday.year 表示访问结构体变量表示访问结构体变量todaytoday的成员的成员yearyear。
•相同结构体类型的变量之间可直接赋值例如:相同结构体类型的变量之间可直接赋值例如: struct weather{struct weather{ double temp,wind; double temp,wind; }w1={7.5,3.2}, }w1={7.5,3.2},w2=w1w2=w1; ; 其中其中““w2=w1;”w2=w1;”等同于:等同于: w2.temp=w1.temp; w2.wind=w1.wind;w2.temp=w1.temp; w2.wind=w1.wind;•结构体类型变量不能直接输入结构体类型变量不能直接输入/ /输出,其成员能否直接输出,其成员能否直接输入输入/ /输出,取决于其成员的类型,若是基本类型或字输出,取决于其成员的类型,若是基本类型或字符数组,则可直接输入符数组,则可直接输入/ /输出如:输出如: cin>>s1; //cin>>s1; //错误错误 cin>>s1.name>>s1.age>>s1.score; //cin>>s1.name>>s1.age>>s1.score; //正确正确 cout< 参数的传递方式为值传须是相同结构体类型的变量参数的传递方式为值传递,系统将实参的每个成员逐个拷贝给对应的形参成递,系统将实参的每个成员逐个拷贝给对应的形参成员结构体类型变量也可做函数的返回值结构体类型变量也可做函数的返回值•例例9.1 9.1 编写求两分数之和的函数,并用它求编写求两分数之和的函数,并用它求1/8+5/241/8+5/24 # #include 人的全部信息 # #include 例如:内存浪费现象比比皆是例如:–人的性别只需人的性别只需1 1个二进制位就可精确表示,但通个二进制位就可精确表示,但通常用字符型或字符型数组表示常用字符型或字符型数组表示–人的年龄只需人的年龄只需7 7个二进制位就可精确表示,但通个二进制位就可精确表示,但通常用整型变量表示常用整型变量表示•针对上述情况,如何节约使用内存?针对上述情况,如何节约使用内存?•位域:结构体中位域:结构体中指定了存指定了存储位数的成位数的成员称称为位域位域使使用位域可解决上述问题用位域可解决上述问题•位域类型:位域类型:含有位域的含有位域的结构体构体类型型定义位域类型定义位域类型•格式为:格式为: struct struct 位位域域类型名类型名{ { 类型名类型名 位域名位域名1 :1 :二进制位数二进制位数; //; //定义位域定义位域 类型名类型名 位域名位域名2 :2 :二进制位数二进制位数; //; //定义位域定义位域 …… // …… //定义其它成员定义其它成员 }; }; 其中,位其中,位域域类型名用标识符表示,类型名只能是整型类型名用标识符表示,类型名只能是整型和字符型,二进制位数必须是大于或等于和字符型,二进制位数必须是大于或等于0 0的整数。 的整数•例如:例如: struct data{struct data{ unsigned short flaga:1; // unsigned short flaga:1; //取值取值0 0或或1 1 unsigned short flagb:3; // unsigned short flagb:3; //取值取值0 0~~7 7 unsigned short flagc:4; // unsigned short flagc:4; //取值取值0 0~~1515 short flagd:4; // short flagd:4; //取值取值-8-8~~7 7 }f1; }f1;位位域域类型类型datadata的变量的变量f1f1的内存分配图的内存分配图15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 015 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0注:同一字中位域的分配方向因系统而异,可能从右到左,注:同一字中位域的分配方向因系统而异,可能从右到左,也可能从左到右。 也可能从左到右VC++VC++从右到左从右到左•若要跳过几个二进位,可定义无名位域若无名位域若要跳过几个二进位,可定义无名位域若无名位域的位数为的位数为0 0,则表示下一位域从新单元开始如:,则表示下一位域从新单元开始如: struct PackedData{struct PackedData{ unsigned flaga:4; unsigned flaga:4; unsigned:2; // unsigned:2; //跳过跳过2 2个二进位,预留个二进位,预留 unsigned:0; //unsigned:0; //下一位域从新单元开始下一位域从新单元开始 unsigned flagd:7; unsigned flagd:7; }; }; flagdflagd位域从下一个位域从下一个unsignedunsigned存存储单元开始存元开始存储这样这样PackedDataPackedData类型需要类型需要2 2个个unsignedunsigned存储单元。 存储单元位域类型变量的定义、初始化和使用位域类型变量的定义、初始化和使用•位域类型变量的定义、初始化和用法与结构体类型变位域类型变量的定义、初始化和用法与结构体类型变量相同例如:量相同例如: data f2={0,4,10,-1};data f2={0,4,10,-1}; f2.flagc=12;f2.flagc=12;•注意:位域赋值时,若所赋数值超出位域的表示范围,注意:位域赋值时,若所赋数值超出位域的表示范围,则取其低位数字例如:则取其低位数字例如: f2.flagb=10;f2.flagb=10; 因因1010已超出已超出flagbflagb位域位域0 0~~7 7的表示范围,故赋给的表示范围,故赋给flagbflagb位域的是位域的是1010的二进制表示的低三位:的二进制表示的低三位: 10 10的二进制为的二进制为 1 1 0 1 00 1 0 即即f2.flagbf2.flagb实际为实际为2 2•位域变量节省内存,但存取费时使用时注意权衡位域变量节省内存,但存取费时。 使用时注意权衡•例例9.3 9.3 用位域来存放学生的信息用位域来存放学生的信息 #include 类型的变量来实现•共用体类型的定义格式:共用体类型的定义格式: union union 共用体类型名共用体类型名{ { 数据类型数据类型 成员名成员名1;1; 数据类型数据类型 成员名成员名2;2; …… …… }; };•在定义和使用形式上,共在定义和使用形式上,共用体与结构体相似:由多用体与结构体相似:由多个成员组成,成员的类型个成员组成,成员的类型可以不同可以不同•在内存分配上,共用体与在内存分配上,共用体与结构体有本质区别:结构结构体有本质区别:结构体的每个成员都有自己的体的每个成员都有自己的独占内存;而共用体的每独占内存;而共用体的每个成员共用同一块内存个成员共用同一块内存•共同体存储区域的大小由共同体存储区域的大小由占用最大存储区的成员决占用最大存储区的成员决定•例如:例如: union udata{union udata{ char c; char c; int i; int i; double d; double d; }; };•共用体类型定义后,即可定义其变量、数组、指针和共用体类型定义后,即可定义其变量、数组、指针和引用等。 例如:引用等例如: udata u1, // udata u1, //变量变量u1u1实际占用实际占用8 8字节内存字节内存 u2[10],u2[10], * *p=u2;p=u2;•对共用体变量的操作与结构体变量类似例如:对共用体变量的操作与结构体变量类似例如: u1.c='a';u1.c='a'; u1.i=25; u1.i=25; u1.d=15.2; u1.d=15.2; 注意,当对变量注意,当对变量u1u1的成员的成员i i赋值时,覆盖了成员赋值时,覆盖了成员c c的值;的值;类似的当对成员类似的当对成员d d赋值时,又覆盖了成员赋值时,又覆盖了成员i i的值同一的值同一时刻,只可使用其中的一个成员时刻,只可使用其中的一个成员•共用体可做函数的参数和返回值共用体可做函数的参数和返回值•应用举例:学生体能测试,男生测应用举例:学生体能测试,男生测100100米,女生测跳绳米,女生测跳绳要求输入学生的体能测试数据并输出。 要求输入学生的体能测试数据并输出include 例如:现实中有些数据只有有限几种取值例如:–交通灯的颜色:红、黄、绿;交通灯的颜色:红、黄、绿;–人的性别:男、女;人的性别:男、女;–一个星期:星期一、星期二、一个星期:星期一、星期二、……、星期日•如何表达这些数据?如何表达这些数据?–用用intint、、charchar类型例如,类型例如,charchar型变量表示性别,型变量表示性别,用用’’m’m’和和’’f’f’分别表示男和女,其它字符则不合分别表示男和女,其它字符则不合法,但编译器无法检查出这类错误法,但编译器无法检查出这类错误–用枚举类型:可更好解决这类问题用枚举类型:可更好解决这类问题枚举类型的定义枚举类型的定义•定义枚举类型的格式为:定义枚举类型的格式为: enum 定义枚举类型时,每个枚举常量对应一个整数值–若未指定枚举常量的值,则第若未指定枚举常量的值,则第1 1个枚举常量为个枚举常量为0 0,第,第2 2个枚举个枚举常量为常量为1 1,依次类推依次类推–也可给枚举常量指定值例如:也可给枚举常量指定值例如: enum weekday{Sun=7,Mon=1,Tue,Wed,Thu,Fri,Sat};enum weekday{Sun=7,Mon=1,Tue,Wed,Thu,Fri,Sat}; 此时此时SunSun为为7 7,,MonMon为为1 1,,TueTue为为2 2、、……、、SatSat为为6 6,即未指定值的,即未指定值的枚举常量,其值为前一枚举常量的值增枚举常量,其值为前一枚举常量的值增1 1枚举类型变量的定义枚举类型变量的定义•枚举变量的定义格式:枚举变量的定义格式: 枚举类型名枚举类型名 变量名变量名; ;或或 enum enum 枚举类型名枚举类型名 变量名变量名; //; //与与C C兼容兼容•例如:例如: weekday weekday workday, weekendworkday, weekend; ; 枚举变量枚举变量workdayworkday和和weekendweekend的值只能是的值只能是SunSun到到SatSat之一。 之一•也可在定义枚举类型时定义枚举变量例如:也可在定义枚举类型时定义枚举变量例如: enum weekday{enum weekday{ Sun,Mon,Tue,Wed,Thu,Fri,Sat Sun,Mon,Tue,Wed,Thu,Fri,Sat } }day1,day2day1,day2; ;枚举类型变量的使用枚举类型变量的使用•赋值运算:枚举常量赋给枚举类型变量,或同类型的赋值运算:枚举常量赋给枚举类型变量,或同类型的枚举类型变量之间相互赋值例如:枚举类型变量之间相互赋值例如: day1=Sun; day2=day1;day1=Sun; day2=day1; 不能将一个整数直接赋给枚举类型变量例如:不能将一个整数直接赋给枚举类型变量例如: enum Color{Red,Green,Yellow}c1,c2;enum Color{Red,Green,Yellow}c1,c2; c1=Yellow; // c1=Yellow; //正确正确 c2=1; //c2=1; //错误错误 可用强制类型转换把整数赋给枚举类型变量。 例如:可用强制类型转换把整数赋给枚举类型变量例如: c2=(Color)1; // c2=(Color)1; // 或或c2=Color(1);c2=Color(1); 其效果等价于:其效果等价于: c2=Green;c2=Green;枚举类型变量的使用枚举类型变量的使用•关系运算:枚举值进行比较时,比较的是它们对应的关系运算:枚举值进行比较时,比较的是它们对应的整型值的大小例如整型值的大小例如c1>c2c1>c2的运算结果为的运算结果为truetrue•输出:直接输出枚举变量时,输出的是枚举变量对应输出:直接输出枚举变量时,输出的是枚举变量对应的整数如需输出对应的字符串,必须通过代码进行的整数如需输出对应的字符串,必须通过代码进行转换•输入:不能直接输入枚举类型变量的值,例如:输入:不能直接输入枚举类型变量的值,例如: cin>>day1; //cin>>day1; //错误错误 对于枚举值的输入,通常通过输入一个整型值,然后对于枚举值的输入,通常通过输入一个整型值,然后把该整型值转换成一个枚举值。 把该整型值转换成一个枚举值•例例9.4 9.4 输入输入/ /输出枚举类型的值输出枚举类型的值 # #include












