第10章结构体和共用体
第10章 结构体与共用体 概述 结构体 共用体 枚举类型 2 结构简介 存储一个班级中 5 名学员的信息(学号、姓名、性别和成绩) 问题 I. 使用数组 MaryJohnPeterRoseKate FMFMF 0102030405 8978.56797.564 解决方案 score num sex name 不能建立数组间的关系 II. 使用多维数组 MaryJohnPeterRoseKate FMFMF 0102030405 8978.56797.564 C 语言不允许一个数组包含多 种数据类型 III. 使用结构 numnamesexscore C 语言引入了称为结构的数据存储方式 “结构” 是一种构造数据类型,它是由若干数据项组合 而成的复杂数据对象,这些数据项称为结构的成员。 §10.1 概述 结构体(structure)是用户自定义的一种数据类 型,包含若干个类型不同的数据项。 用途把不同类型的数据组合成一个整体。而分别 用独立变量来表示不能反映它们之间的内在联系。 例定义一个结构体类型student,包 含学号、姓名、性别、年龄、成绩、 家庭地址。 §10.1 概述 结构体类型的定义 struct 结构体名 { 类型标识符 成员名1; 类型标识符 成员名2; }; struct是关键字 ,不能省略 合法标识符 可省略无名结构体 成员类型可以是基本 类型或构造类型 必须有分号 5 定义结构 struct structurename { datatype variable1; datatype variable2; . }; 结构成员 { }; 结构名 structstudent int num; char name[20]; char sex; 定义结构 float score; C 语言中的有效数据类型 6 定义结构 struct student { int num; char name[20]; char sex; float score; }; numnamesex student 结构定义并不预留内存 结构定义放置在程序的开始部分,位于头文件声明之后 score 结构定义仅描述了一个结构的形式。如果要在程序里使 用结构,需要声明结构变量。 struct date { int year; int month; int day; }; struct std_info { int num ; char name[20]; char sex; float score; char addr[30]; struct date birthday; }; 日期结构体类型由年、 月、日三项组成 学生信息结构类型由学 号、姓名、性别、成绩、 地址和生日共6项组成 可以改写成int year,mongth,day; §10.1.1结构体变量的定义 char name[20]; char sex; int age; float score; char addr[30]; }; struct student stu1,stu2; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; 结构体类型名 student可以不写 struct student { int num ; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2; stu1 num name sex age score addr 22012430 stu1在内存中共占字节数 2201243059 §10.1.3 结构体变量的引用 结构体变量的引用原则 结构体变量不能整体输入输出,要通过成员运算 符“.”,逐个访问其成员,且访问的格式为 结构体变量.成员 struct date { int year; int month; int day; }; struct date birth; printf“d,d,d“,birth; printf“d,d,d“,birth.year, birth.month,birth.day; “.”是成员运算符, 优先级最高 如果某成员本身又是一个结构类型,则只能通过多级的分量运 算,对最低一级的成员进行引用。 结构变量.成员.子成员..最低级子成员 引用结构变量student中的 birthday成员的格式分别为 student.birthday.year student.birthday.month student.birthday.day 结构体变量的引用原则 struct std_info { int num ; char name[20]; char sex; float score; struct date birthday; }student; struct date { int year; int month; int day; }; num name sex score birthday student 对最低一级成员,可像同类型的普通变量一样,进行 相应的各种运算。 结构体变量的初始化 8一般形式 结构体类型名 结构体变量{初值表}; 8说明 §若某成员本身又是结构体类型,则该成员的初值为一个初值表 §初值的数据类型,应与结构变量中相应成员的类型一致 struct std_info { int num ; char name[20]; char sex; float score; struct date birthday; }; struct std_info student{102, “Zhangsan“, M , 85, {1980,9,20}} ; struct student { int num; char name[20]; char sex; float score; }; struct student student1,student2; 内存 student1 struct student student1{1,“Yao Ming “, M ,90.5}; 1Yao MingM 赋值的顺序应与成员声明时的顺序一样;允许 初始化语句中的值的数目比结构成员数目少。 student1.num student1.name student1.sex 90.5 student1.score 结构变量初始化 student2 student2.num1; student2.name“Zhang Zi Liang“; student2.sex’M’; printf“请输入成绩\n“; scanf“f“, 结构变量赋值 1Zhang Zi Liang M q 用输入语句或赋值语句来给结构变量的各个成员赋值 78 78 student3 student2; student3 1Zhang Zi Liang M78 问题描述 根据学员的成绩,输出不及格学员的详细信息。 使用结构示例 include struct student { int num;//学号 char *name;//姓名 char sex;//性别 float score;//成绩 }; void main { static struct student stu1{1,“李亚鹏“, M ,61}; static struct student stu2{2,“周晶晶“, F ,92.5}; static struct student stu3{3,“姚光明“, M ,59}; printf“不及格学员的名单如下\n“; ifstu1.score60 } 不及格学员的名单如下 3 姚光明 M 59.00 stu1 1 李亚鹏 M78 stu2 2 周晶晶 F92 stu3 3 姚光明 M59 struct std_info {int num ; char name[20]; char sex; struct date birthday; }; main { struct std_info stu{102, “Zhangsan“, M , {1980,9,20}} ; printf“Num d\n“,stu.num; printf“Name s\n“,stu.name; printf“Sex c\n“,stu.sex; printf“Birthday d-d-d\n“,stu.birthday.year, stu.birthday.month, stu.birthday.day; } [例] 定义一个结构变量stu,用于存储和显示一个学生的基本 情况。 struct std_info stu; scanf“ds cddd“, char name[20]; char sex; int age; float score; }; struct student stu[3] ; 101LilinM 1887.5 102ZhanghuaM 1899 103WuliF1978.5 stu[0] stu[1] stu[2] O结构体数组初始化 结构体类型名 结构体数组名[n]={{初值表1},{初值表2}, .,{初值表n}}; struct student {int num ; char name[20]; char sex; int age; float score; }; struct student stu[3]={{101,“Lilin“, M ,18,87.5}, {102,“Zhanghua“, M ,18,99},{103, Wuli“, F ,19,78.5}} ; [例]定义结构类型struct std_info,定义一个结构数组 stu,用于存储和显示三个学生的基本情况。 struct date {int year; int month; int day; }; struct std_info {int num ; char name[20]; char sex; struct date birthday; } stu[3]{{102,“Zhangsan“, M ,{1980,9, 20}}, {105,“Lisi“, M ,{1980,8,15}}, {112,“Wangwu“, F ,{1980,3,10}} }; main { int i; printf“No. Name Sex Birthday\n“; fori0; i 统计后选人选票 struct person { char name[20]; int count; }leader[3]{“Lian”,0,“ABian”,0,”Song“,0}; main { int i,j; char leader_name[20]; fori1;inum101; strcpyp-name,“lilin“;} 引用结构体变量成员的三种形式 结构体变量.成员名 stu.num *p.成员名 *p.num p-成员名 p-num 若struct student stu; struct student *pstruct st *next;}; static struct st a[3]{5, p 则表达式 的值是6。 A.p-n B.p-n C.*p.n D.p-n D 指向结构体数组的指针 struct student {int num ; char name[20]; char sex; int age; }; struct student stu[3]= {{101,“Lilin“, M ,18,}, {102,“Zhanghua“, M ,18}, {103, Wuli“, F ,19,}} ; struct student *pstu; main {for ; pnum,p- name,p-sex; } 说明 §如果指针变量p指向结构体数组 ,则p1指向结构体数组的下一 个元素,而不是当前元素的下一 个成员。 §如果指针变量p指向一个结构变 量(或结构数组),就不能再使 之指向结构体变量(或结构数组 元素)的某一成员。 pstu; pstu.name; p-num p-num num name sex age stu[0] p stu[1] stu[2] p1 下面程序的输出结果为 。 struct st { int x; int *y; } *p; int dt[4]{10,20,30,40}; struct st aa[4]{50, main { paa; printf“d\n“,p-x; printf“d\n“,p-x; printf“d\n“,*p-y; } A.10 B.50 C. 51 D.60 20 60 60 70 20 21 21 31 10 20 30 40 dt 50 60 70 80 aa xy char position[10]; } 共用体变量的定义----与结构体变量的定义类似 char ch; float f; }; union data un1,un2,un3; char ch; float f; }un1,un2,un3; union data {int i; char ch; float f; }; union data un1,un2,un3; ch 注意共用变量占用的内存空间,等于最长 成员的长度,而不是各成员长度之和。 i f 2000 2001 2002 2003un1 un1占用的内存空间为4字节(不是2147字节) 。 共用体变量的引用 与结构体变量的引用一样,也只能逐个引用共用体变量的成员 un1=1; m=a;un1.i1;m=un1.i; 特点 (1)系统采用覆盖技术,实现共用变量各成员的内存共享,所以在某一时 刻,最后一次存入的成员值是起作用的。 例如,执行un1.i1; un1.ch c ; un1.f3.14后,un1.f才是有效的成员。 (2)由于所有成员共享同一内存空间,故共用变量与其各成员的地址相同 。 例如,&un1&un1.i&un1.ch&un1.f。 (3)不能对共用体变量进行初始化(注意结构体变量可以);也不能将 共用变量作为函数参数,以及使函数返回一个共用体数据,但可以使用指向 共用变量的指针。 (4)共用类型可以出现在结构类型定义中,反之亦然。 –结构体与共用体 l区别 存储方式不同 struct node { char ch[2]; int k; }a; union node { char ch[2]; int k; }b; a ch k bch k 变量的各成员同时存在 任一时刻只有一个成员存在 l联系 两者可相互嵌套 下面定义中sizeofa和sizeofa.share的值是 struct date { int day; int month; int year; union { int share1; float share2; }share; } a; 例 sizeofa10 sizeofa.share4 下面定义中变量w在内存中所占字节数 union aa { float x,y; char c[6]; }; struct st { union aa v; float w[5]; double ave; } w; 例 sizeofw34 下列程序输出结果是 。 include main {union {int k; char i[2]; }*s,a; s s-i[0]0 x39; s-i[1]0 x38; printf“x\n“,s-k; } A.3839 B.3938 C.380039 D.390038 例 a.k a.i[0 ] a.i[1 ] 共用体变量a 或s-k 或s-i[0] 或s-i[1] 在内存中存储 形式为 0011 1001 下列程序输出结果是 。 include main {union {int k; char i[2]; }*s,a; s s-i[0]0 x39; s-i[1]0 x38; printf“x\n“,s-k; } A.3839 B.3938 C.380039 D.390038 例 共用体变量a s-k s-i[0] s-i[1] 0011 1001 0011 1000 在内存中存储 形式为 下列程序输出结果是 。 include main {union {int k; char i[2]; }*s,a; s s-i[0]0 x39; s-i[1]0 x38; printf“x\n“,s-k; } A.3839 B.3938 C.380039 D.390038 例 共用体变量a 0011 1001 0011 1000 低字节 高字节 故s-k在 内存中存储数据为 0011 1000 0011 1001 s-k s-i[0] s-i[1] 若有以下的说明、定义和语句,则输出结果为___。 main { union un { int a; char c[2]; } w; w.c[0] A ;w.c[1] a ; printf“o\n“,w.a; } 例 w.a w.c[0] w.c[1] 共用体变量w 0100 0001 若有以下的说明、定义和语句,则输出结果为___。 main { union un { int a; char c[2]; } w; w.c[0] A ;w.c[1] a ; printf“o\n“,w.a; } 例 w.a w.c[0] w.c[1] 共用体变量w 0100 0001 0110 0001 若有以下的说明、定义和语句,则输出结果为___。 main { union un { int a; char c[2]; } w; w.c[0] A ;w.c[1] a ; printf“o\n“,w.a; } 例 w.a w.c[0] w.c[1] 共用体变量w 0100 0001 0110 0001 故w.a在 内存中存储数据为 0110 0001 0100 0001 若有以下的说明、定义和语句,则输出结果为___。 main { union un { int a; char c[2]; } w; w.c[0] A ;w.c[1] a ; printf“o\n“,w.a; } 例 w.a w.c[0] w.c[1] 共用体变量w 0100 0001 0110 0001 故w.a在 内存中存储数据为 0110 0001 0100 0001 以八进制形式输出,二进制向 八进制转换原则是三位二进 制对应一位八进制 1 若有以下的说明、定义和语句,则输出结果为___。 main { union un { int a; char c[2]; } w; w.c[0] A ;w.c[1] a ; printf“o\n“,w.a; } 例 w.a w.c[0] w.c[1] 共用体变量w 0100 0001 0110 0001 故w.a在 内存中存储数据为 0110 0001 0100 0001 以八进制形式输出,二进制 向八进制转换原则是三位 二进制对应一位八进制 10 若有以下的说明、定义和语句,则输出结果为___。 main { union un { int a; char c[2]; } w; w.c[0] A ;w.c[1] a ; printf“o\n“,w.a; } 例 w.a w.c[0] w.c[1] 共用体变量w 0100 0001 0110 0001 故w.a在 内存中存储数据为 0110 0001 0100 0001 以八进制形式输出,二进制向 八进制转换原则是三位二进 制对应一位八进制 105 若有以下的说明、定义和语句,则输出结果为___。 main { union un { int a; char c[2]; } w; w.c[0] A ;w.c[1] a ; printf“o\n“,w.a; } 例 w.a w.c[0] w.c[1] 共用体变量w 0100 0001 0110 0001 故w.a在 内存中存储数据为 0110 0001 0100 0001 以八进制形式输出,二进制向 八进制转换原则是三位二进 制对应一位八进制 1050 若有以下的说明、定义和语句,则输出结果为___。 main { union un { int a; char c[2]; } w; w.c[0] A ;w.c[1] a ; printf“o\n“,w.a; } 例 w.a w.c[0] w.c[1] 共用体变量w 0100 0001 0110 0001 故w.a在 内存中存储数据为 0110 0001 0100 0001 以八进制形式输出,二进制向 八进制转换原则是三位二进 制对应一位八进制 10506运行结果 60501 以下程序运行的输出结果是 。 main {union {char i[2]; int k; }r; r.i[0]2;r.i[1]0; printf“d\n“,r.k; } A.2 B.1 C.0 D.不确定A 例 e.in e. a 或e .b 共用体变量e e.in.x e.in.y 程序运行的结果是________。 main { union EXAMPLE { struct { int x; int y; }in; int a; int b; }e; e.a1; e.b2; e.in.xe.a*e.b; e.in.ye.ae.b; printf“d,d\n“,e.in.x,e.in.y; } 程序运行的结果是________。 main { union EXAMPLE { struct { int x; int y; }in; int a; int b; }e; e.a1; e.b2; e.in.xe.a*e.b; e.in.ye.ae.b; printf“d,d\n“,e.in.x,e.in.y; } e.in e.a或e.b 共用体变量e 1 e.in.x e.in.y 例 程序运行的结果是________。 main { union EXAMPLE { struct { int x; int y; }in; int a; int b; }e; e.a1; e.b2; e.in.xe.a*e.b; e.in.ye.ae.b; printf“d,d\n“,e.in.x,e.in.y; } e.in e.a或e.b 共用体变量e 1 e.in.x e.in.y 2 例 程序运行的结果是________。 main { union EXAMPLE { struct { int x; int y; }in; int a; int b; }e; e.a1; e.b2; e.in.xe.a*e.b; e.in.ye.ae.b; printf“d,d\n“,e.in.x,e.in.y; } e.in e.a或e.b 共用体变量e 2 e.in.x e.in.y 4 例 §10.6 枚举类型 用途 如果一个变量只有几种可能的值,就可以定义成枚举类型 枚举类型的定义 enum 枚举类型名{取值表}; 例enum weekdays {Sun,Mon,Tue,Wed,Thu,Fri,Sat} ; 枚举变量的定义----与结构体变量定义类似 §间接定义enum weekdays work; §直接定义enum weekdays {Sun,Mon,Tue,Wed,Thu,Fri,Sat } work; 说明 (1)枚举型仅适应于取值有限的数据。 例1周7天,1年12个月。 (2)取值表中的值称为枚举元素,其含义由程序解释。 例不是因为写成“Sun”就自动代表“星期天”。事实上, 枚举元素 用什么表示都可以。 (3)枚举元素按常量处理,它们的值是定义时的顺序号(从0开始), 所以枚举元素可以进行比较,比较规则是序号大者为大 例上例中的Sun的值为0、Mon的值为1、、Sat的值为6,所 以MonSun,Sat最大。 (4)枚举元素的值也是可以人为改变的在定义时由程序指定。 例如果enum weekdays {Sun7, Mon=1 ,Tue, Wed, Thu, Fri, Sat};则Sun7,Mon1,从Tue2开始,依次增1。 注意不同的枚举元素不可以指定相同的值 (5)一个整数不能直接赋值给枚举变量 例workday=2;(非法,因为类型不同) 改写成workday=enum weekday2; 下面程序的输出是 。 main { enum team{my,your4,his,herhis10}; printf“d d d d\n“,my,your,his,her; } A.0 1 2 3 B.0 4 0 10 C.0 4 5 15 D.1 4 5 15 C 下面程序的输出是 。 main { enum em{em13,em21,em3}; char *aa[]{“AA“,“BB“,“CC“,“DD“}; printf“sss\n“,aa[em1],aa[em2],aa[em3]; } DDBBCC §10.10 用typedef定义类型 作用用typedef定义已有类型的别名。该别名与标准类 型名一样,可用来定义相应的变量。 定义已有类型别名的方法 1按定义变量的方法,写出定义体; 2将变量名换成别名; 3在定义体最前面加上typedef。 关键字 例给实型float定义1个别名REAL。 1按定义实型变量的方法,写出定义 体 float f; 2将变量名换成别名 float REAL; 3在定义体最前面加上typedef typedef float REAL; 例给结构类型struct date定义1个别名 DATE。 struct date { int year, month, day; }; 1按定义结构变量的方法,写出定义体 struct date {} d; 2将变量名换成别名 struct date {} DATE; (3)在定义体最前面加上typedef typedef struct date {} DATE; typedef int *ipoin; ipoin p; 说明 (1)用typedef只是给已有类型增加1个别名 ,并不能创造1个新的类型。 (2)typedef与define有相似之处,但二者 是不同的前者是由编译器在编译时处理的; 后者是由编译预处理器在编译预处理时处理的 ,而且只能作简单的字符串替换。 1.设有以下定义 typedef union { long i; int k[5]; char c; } DATE; struct date { int cat; DATE cow; double dog; } too; DATE max; 则语句printf〞d〞,sizeofstruct datesizeofmax的执行 结果是 。 A.25 B.30 C.18 D.8 2 .下面程序的输出是 。 typedef union { long x[2]; int y[4]; char z[8]; } MYTYPE; MYTYPE them; main { printf“d\n“,sizeofthem; } A.32 B.16 C.8 D.24 4.设有以下说明语句 typedef struct { int n; char ch[8]; }PER; 则下面叙述中正确的是 A PER 是结构体变量名 B PER是结构体类型名 C typedef struct 是结构体类型 D struct 是结构体类型名 3.若要说明一个类型名STP,使 得定义语句STP s;等价于char *s;,以下选项中正确的是 A typedef STP char *s; B typedef *char STP; C typedef STP *char; D typedef char* STP ; B C D B l若有以下说明和定义 typedef int *INTEGER INTEGER p,*q; 以下叙述正确的是______。 A p是int型变量 B p是基类型为int的指针变量 C q是基类型为int的指针变量 lD 程序中可用INTEGER代替int类型名 B