C程序设计第11章结构体、联合体与枚举类型.ppt

第11章结构体 联合体与枚举类型 结构体类型是C语言允许用户定义的又一重要的构造数据类型 11 1结构体的概念11 2结构体数组11 3结构体指针11 4链表11 5联合体数据类型11 6枚举数据类型11 7自定义类型 11 1结构体的概念结构体类型是一种构造数据类型 是数目固定 类型不同的若干有序数据项的集合 每个数据项称为一个成员 每一个成员可以是一个基本数据类型或者是一个构造类型 结构体数据类型具有很强的数据描述能力 但C语言中并不提供现成的结构体类型 因此 用户在使用一个结构体类型之前 必须先定义它 也就是要在程序中构造所需要的数据类型 11 1 1结构体类型的定义结构体类型定义的一般形式为 struct结构体类型名 类型标识符成员名1 类型标识符成员名2 类型标识符成员名n 例如 定义一个 学生信息 的结构体类型如下 structstudent intnum charname 10 charsex intage charaddr 50 intscore 11 1 2结构体变量的定义 引用 初始化1 结构体变量的定义 1 先定义结构体类型 再定义结构体类型变量 这种定义的一般形式为 struct结构体类型名结构体变量名表 如上面定义了 学生信息 的结构体类型structstudent后 就可以用它来定义结构体变量 例如 structstudentstul stu2 定义了stul和stu2为structstudent类型的变量 编译系统为变量stul与stu2分配存储空间时 其存储格式与结构体类型structstudent所描述的保持一致 结构体中的各个成员按要求顺序存放 每一个structstudent类型的变量占用的存储单元为67个字节 2 在定义结构体类型的同时定义结构体变量 这种定义的一般形式为 struct结构体类型名 类型标识符成员名1 类型标识符成员名2 类型标识符成员名n 结构体变量名表 例如 structstudent intnum charname 10 charsex intage charaddr 50 intscore stu1 stu2 这种定义与前面的定义功能相同 都是既定义了结构体类型structstudent 又定义了两个结构体变量stu1与stu2 3 直接定义结构体类型的变量 其一般形式为 struct 类型标识符成员名1 类型标识符成员名2 类型标识符成员名n 结构体变量名表 例如 struct intnum charname 10 charsex intage charaddr 50 intscore stu1 stu2 2 结构体变量的引用结构体成员引用的一般形式如下 结构变量名 成员名其中 为结构体成员运算符 所有C语言运算符中它的优先级最高 因此可以把上述引用形式作为一个整体来看待 例如 stu1 name stu2 score分别表示结构体变量stu1的成员name与结构体变量stu2的成员score 例11 1定义有关职工工资信息的结构体类型变量 包括编号 姓名 基本工资 附加工资 水电费 实发工资 为结构体变量中的成员赋值并输出其值 structperson intnum 职工编号 char name 姓名 floatbase 基本工资 floataddition 附加工资 floatcost 水电费 floatsalary 实发工资 main structpersonemployeea employeeb employeea num 2086 employeea name Zhaoxiwang printf inputbase addition cost n scanf f f f 程序运行结果为 inputbase addition cost 805 85 376 57 123 52 Number 2086Name ZhaoxiwangBase 805 85Addition 376 57Cost 123 52Salary 1085 90 3 结构体变量的初始化结构体变量的初始化和对数组的初始化相类似 将各个成员的初值用一对花括弧括起来 括弧内各数据项的数据类型 顺序要和结构体类型说明中的成员类型相匹配 数据项间用逗号分隔 如果初值的个数少于结构中成员的个数 则余下的成员将自动初始化为0或NULL 例如 structstudent intnum charname 10 charsex intage charaddr 50 intscore main structstudentstu 1422 LinHui M 18 ShangHai 85 printf Number d nName s nSex c n stu num stu name stu sex printf Age d nAddress s nScore d n stu age stu addr stu score 程序运行结果为 Number 1422Name LinHuiSex MAge 18Address ShangHaiScore 85 11 1 3结构体的嵌套结构体类型定义时 其成员的类型也可以是结构体类型 即结构体类型定义是可以嵌套的 结构体定义的嵌套可以是多重的 例如 定义一个 职工信息 的结构体类型 每个职工包含编号 num 姓名 name 性别 sex 出生日期 birthday 家庭住址 addr 等信息 其中出生日期包括年 year 月 month 日 day 3个数据项 家庭住址包括城市 city 街道 street 门牌号码 streetnum 等信息 职工信息的逻辑结构如图11 3所示 图11 3职工信息逻辑结构 显然 职工信息 中的 出生日期 和 家庭住址 应该用结构体类型描述 首先定义结构体类型 日期 structdate和 住址 structaddress如下 structdate intyear 年 intmonth 月 intday 日 structaddress charcity 50 城市 charstreet 50 街道 intstreetnum 门牌号码 然后定义结构体类型 职工 structemployee如下 structemployee intnum charname 10 charsex structdatebirthday structaddressaddr 在结构体类型structemployee中 成员birthday是structdate结构体类型 它又有自己的成员year month day 成员addr是structaddress结构体类型 它又有自己的成员city street streetnum 这就是结构体类型的嵌套定义 对于嵌套的结构体 引用时应按照从左到右 从外到内的方式 用 一级一级地运算 直到找到最低一级的成员 例如 structemployeeemp emp num 1001 strcpy emp name LiuXiaomei emp sex F emp birthday year 1986 emp birthday month 5 emp birthday day 18 strcpy emp addr city BeiJing strcpy emp addr street Changanstreet emp addr streetnum 168 定义了structemployee类型的变量emp 对其各个成员赋值 赋值后结构体变量emp在内存中的存储形式如图11 4所示 图11 4结构体变量emp 11 2结构体数组 11 2 1结构体数组的定义 结构体数组的定义方法与其他整型数组 实型数组和字符型数组的定义方法类似 例如 structstudent intnum charname 10 charsex intage charaddr 50 intscore structstudentstu 40 与结构体变量的定义类似 结构体数组的定义也可以采用以下的方式 structstudent intnum charname 10 charsex intage charaddr 50 intscore stu 40 或struct intnum charname 10 charsex intage charaddr 50 intscore stu 40 11 2 2结构体数组的引用例11 3输入全班的学生的信息 包括学号 姓名 性别 年龄 成绩和家庭住址 并按成绩由高到低的次序排序 输出排序后的全班学生信息登记表 structstudent intnum charname 10 charsex intage charaddr 50 intscore main structstudentstu 40 temp inti j k for i 0 i 40 i printf n学号 scanf d for i 0 i 39 i k i for j i 1 j 40 j if stu k score stu j score k j temp stu i stu i stu k stu k temp printf n学号 t姓名 t性别 t年龄 t家庭住址 t 成绩 n for i 0 i 40 i printf d t s t c t stu i num stu i name stu i sex printf d t s t t d n stu i age stu i addr stu i score 11 2 3结构体数组的初始化 structstudent intnum charname 10 charsex intage charaddr 50 intscore structstudentstu 5 6001 Zhaozhen F 18 Beijing 85 6002 Linping F 19 Shanghai 70 6003 Hefang F 18 Qingdao 92 6004 Zhouming F 19 Jinan 87 6005 Wangtao M 18 Dalian 68 11 3结构体指针 11 3 1指向结构体变量的指针结构体变量所占内存单元的首地址称为结构体变量的指针 指向一个结构体变量的指针变量 称为结构体指针变量 结构体指针变量中的值是所指向的结构体变量的指针 结构体指针变量定义的一般形式为 struct结构体类型名 结构体指针变量名 有了结构体指针变量后 就能更方便地访问结构体变量的各个成员 利用指针引用结构体成员的一般形式为 结构体指针变量 成员名例如 pstu num 6001 C语言中为了直观而方便地通过指针来引用结构体成员 专门设置了指向运算符 来访问结构体成员 一般形式为 结构体指针变量 成员名例如 pstu num 6001 例11 4编一程序 利用结构体指针处理结构体中的成员 structstudent intnum charname 10 charsex intage charaddr 50 intscore main structstudentstu 6001 Zhaozhen F 18 Beijing 85 pstu pstu 程序运行结果为 Number 6001 Name Zhaozhen Sex FAge 18 Address Beijing Score 85Number 6001 Name Zhaozhen Sex FAge 18 Address Beijing Score 85Number 6001 Name Zhaozhen Sex FAge 18 Address Beijing Score 85 11 3 2指向结构体数组的指针同前面讨论的指向数组的指针一样 结构体指针也可用于指向结构体数组 结构体指针变量指向一个结构体数组 这时结构指针变量的值是整个结构体数组的首地址 结构体指针变量也可指向结构体数组中的一个元素 这时结构体指针变量的值是该结构体数组元素的地址 例11 5利用结构体指针变量输出结构体数组 图11 8结构数组的指针 11 3 3结构体指针作函数参数结构体变量作函数参数采取的是 单向值传递 方式 系统将实参结构体的全部成员拷贝给被调用函数的形参 例11 6编写程序 用结构体指针变量作函数参数 计算一组学生的平均成绩和不及格人数 structstudent intnum charname 10 intscore stu 5 6001 Zhaozhen 85 6002 Linping 57 6003 Hefang 62 6004 Zhouming 87 6005 Wangtao 48 main structstudent ps voidaver structstudent ps ps stu aver ps voidaver structstudent ps intc 0 i floatave sum 0 for i 0 iscore if ps score 60 c 1 ave sum 5 printf average 2f ncount d n ave c 程序运行结果为 average 67 80count 2 11 4链表 11 5联合体数据类型 11 5 1联合体的定义 1 联合体类型的定义定义一个联合类型的一般形式为 union联合体类型名 类型标识符成员名1 类型标识符成员名2 类型标识符成员名n 2 联合体变量的定义 1 先定义联合体类型 再定义联合体变量 2 定义联合体类型的同时定义联合体变量 3 直接定义联合体变量 unionudata类型的联合体变量u 包含有3个成员i c和f 注意 系统没有分别给成员i c f 分配1个字节 2个字节 4个字节共7个字节的存储空间 而只分配一个成员项的空间 三个成员共同使用一块内存空间 但联合体unionudata中各个成员项的数据长度又互不相同 所以应按其成员中数据长度最大的成员项f分配4个字节的内存空间 联合体变量u如果被赋予字符型值时就使用1个字节的存储空间 被赋予整型值时就使用2个字节的存储空间 被赋予实型值时 就使用4个字节的存储空间 udata中的3个成员c i f 共同占用同一段内存区的情况 如图11 21所示 图11 21联合体变量共同占用内存的情况 11 5 2联合体变量的引用使用成员运算符 引用联合体的成员 其一般格式为 联合变量名 成员名例如u i u c u f分别表示联合体变量u的成员i c f 联合体变量的成员的使用方法与同类型的变量完全相同 但要注意的是 由于联合体成员共同占用一块内存单元 一个联合体变量 每次只能赋予一个成员值 因此某个时刻只能有一个成员变量起作用 其他的成员不起作用 并且在联合体变量中起作用的成员是最后一次存放的成员 即在存入一个新的成员后 原来的成员就因被覆盖而失去作用 例11 15分析下列程序的输出结果 main union longa intb charc m m a 65535 printf ld d c n m a m b m c 66 程序运行结果为 65355 1A 程序中给联合体m的成员赋值为65535 假如联合体变量m在内存中分配的地址是2000H 那么m a所占的内存空间为2000H到2003H连续的四个字节 其值为65535 在内存中的存储为 2000H 11111111 2 2001H 11111111 2 2002H 00000000 2 2000H 00000000 2 m b所占的内存空间为2000H和2001H连续的两个字节 于是m b的值为 1 m c所占的内存空间为2000H 于是m c的ascii值为255 程序中输出m c 66 得到的是ASCII值为65的字符 于是输出A 另外 可以通过指针来引用联合体的成员 其格式如下 指向联合体变量指针名 成员名或者指向联合体变量指针名 成员名例如 unionudatau pu pu 则指针pu指向联合体变量u 通过指针pu可以访问u中的各个成员 例如 pu i 23 表示将23赋给pu指向的联合体变量的成员i 或者pu i 23以上两种方法的效果是一样的 但在使用指针访问联合体成员时 通常使用指向运算符 访问联合体成员 假设pu指向联合体变量 则下面3个语句的效果是一样的 u i 23 等价于 pu i 23 等价于pu i 23联合体的特征决定了它的应用远不如结构体应用那样广泛 但是实际应用中 常常会出现一些量相互排斥的情况 这时用联合体就非常方便 11 6枚举数据类型 11 6 1枚举类型的定义枚举类型通过枚举一系列有序的标识符来定义 枚举类型定义的一般格式为 enmu枚举名 枚举分量名1 枚举分量名2 枚举分量名n 其中 enmu是定义枚举类型的关键字 枚举名遵循标识符命名规则 用于标识所定义的枚举类型 枚举分量也是一个合法的标识符 由用户根据需要自己确定 它们列出一个枚举变量可以具有的值 又称为枚举常量 枚举常量各自代表一个数值 因此它们之间有先后顺序 可以进行比较 例如 enumweek sun mon tue wed thu fri sut 定义了一个枚举类型enmuweek 它由枚举常量sun mon tue wed thu fri和sut组成 即一个enmuweek类型的枚举变量可以具有的值为sun mon tue wed thu fri和sut 在C语言中 枚举类型中的枚举常量各自隐含一个int型值 在默认情况下 枚举常量的值从0开始 后一个总是比前一个大1 如在枚举类型week中 第一个枚举常量sun有值0 第二个枚举常量mon有值1 依次类推 最后一个枚举常量sat有值6 这是一种隐式定值方法 另外 在定义枚举类型时 还可以通过显式赋值的方法来确定枚举常量的值 例如 enumweek sun 7 mon 1 tue wed thu fri sat 这里 sun的值是7 mon的值是1 它们是通过显式赋值的方式来确定其值的 tue没有被显式赋值 它的值是前一个枚举常量的值加1 即为2 同样wed值为3 sat的值是6 11 6 2枚举变量的定义和引用1 先定义枚举类型 再定义枚举变量 2 定义枚举类型的同时定义枚举变量 3 直接定义枚举变量 例11 17编写程序 输入今天是星期几 计算并输出明天是星期几 程序如下 enumweek sun mon tur wed thu fri sat enumweektomorrow day enumday intn n int day 1 7 return enumweek n main enumweekday1 day2 char name sun mon tur wed thu fri sat intn printf n请输入0 6内的整数 scanf d 程序运行结果为 请输入0 6内的整数 3 明天是 thu 11 7自定义类型 自定义类型的一般形式为typedef类型说明符新类型名表 例如 typedeffloatREAL typedefREAL POINT POINTp1 p2 。