1、第10章 结构体与共用体,概述 结构体 共用体 枚举类型,2,结构简介,存储一个班级中 5 名学员的信息(学号、姓名、性别和成绩),问题:,I. 使用数组,解决方案:,score,num,sex,name,不能建立数组间的关系,II. 使用多维数组,C 语言不允许一个数组包含多种数据类型,III. 使用结构,C 语言引入了称为结构的数据存储方式,“结构” 是一种构造数据类型,它是由若干数据项组合而成的复杂数据对象,这些数据项称为结构的成员。,10.1 概述,结构体(structure)是用户自定义的一种数据类型,包含若干个类型不同的数据项。 用途:把不同类型的数据组合成一个整体。而分别用独立变
2、量来表示不能反映它们之间的内在联系。,例:定义一个结构体类型student,包含学号、姓名、性别、年龄、成绩、家庭地址。,10.1 概述,结构体类型的定义,struct 结构体名 类型标识符 成员名1;类型标识符 成员名2; ;,struct是关键字,不能省略,合法标识符 可省略:无名结构体,成员类型可以是基本类型或构造类型,必须有分号,5,定义结构,struct structurename datatype variable1;datatype variable2;. ;,结构成员,;,结构名,struct,student,int num;,char name20;,char sex;,定义
3、结构,float score;,C 语言中的有效数据类型,6,定义结构,struct student int num;char name20;char sex;float score; ;,num,name,sex,student,结构定义并不预留内存,结构定义放置在程序的开始部分,位于头文件声明之后,score,结构定义仅描述了一个结构的形式。如果要在程序里使用结构,需要声明结构变量。,struct date int year; int month;int day;,struct std_info int num ; char name20; char sex; float score;ch
4、ar addr30;struct date birthday;,日期结构体类型:由年、月、日三项组成,学生信息结构类型:由学号、姓名、性别、成绩、地址和生日共6项组成,10.1.1结构体变量的定义,间接定义法: 先定义结构体类型,后定义结构体变量,struct student int num ; char name20; char sex;int age; float score;char addr30; struct student stu1,stu2;,直接定义法: 在定义结构类型的同时,定义结构变量,struct student int num ; char name20; char s
5、ex;int age; float score;char addr30;stu1,stu2;,结构体类型名student可以不写,struct student int num ; char name20; char sex;int age; float score;char addr30;stu1,stu2;,stu1:,num name sex age score addr,stu1在内存中共占字节数: 2+20+1+2+4+30=59,10.1.3 结构体变量的引用,结构体变量的引用原则 结构体变量不能整体输入输出,要通过成员运算符“.”,逐个访问其成员,且访问的格式为:结构体变量.成员,
6、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 stude
7、nt.birthday.day,结构体变量的引用原则,struct std_info int num ; char name20; char sex; float score;struct date birthday;student;,struct date int year; int month;int day;,num name sex score birthday,student:,对最低一级成员,可像同类型的普通变量一样,进行相应的各种运算。,结构体变量的初始化,一般形式结构体类型名 结构体变量=初值表; 说明 若某成员本身又是结构体类型,则该成员的初值为一个初值表 初值的数据类型,应
8、与结构变量中相应成员的类型一致,struct std_info int num ; char name20; char sex; float score;struct date birthday;; struct std_info student=102, “Zhangsan“, M, 85,1980,9,20 ;,struct student int num;char name20;char sex;float score; ; struct student student1,student2;,struct student student1=1,“Yao Ming “,M,90.5;,1,
9、Yao Ming,M,赋值的顺序应与成员声明时的顺序一样;允许初始化语句中的值的数目比结构成员数目少。,student1.num,student1.name,student1.sex,90.5,student1.score,结构变量初始化,student2.num=1; student2.name=“Zhang Zi Liang“; student2.sex=M; printf(“请输入成绩:n“); scanf(“%f“,结构变量赋值,1,Zhang Zi Liang,M,用输入语句或赋值语句来给结构变量的各个成员赋值,78,78,student3 = student2;,1,Zhang Z
10、i Liang,M,78,问题描述: 根据学员的成绩,输出不及格学员的详细信息。,使用结构示例,#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“);if(stu1.score
11、=60 ,不及格学员的名单如下:,3 姚光明 M 59.00,1,李亚鹏,M,78,2,周晶晶,F,92,3,姚光明,M,59,struct std_info int num ; char name20; char sex; struct date birthday;;main() struct std_info stu=102, “Zhangsan“, M, 1980,9,20 ; printf(“Num: %dn“,stu.num); printf(“Name: %sn“,stu.name); printf(“Sex: %cn“,stu.sex); printf(“Birthday: %d
12、-%d-%dn“,stu.birthday.year,stu.birthday.month, stu.birthday.day); ,例 定义一个结构变量stu,用于存储和显示一个学生的基本情况。,struct std_info stu; scanf(“%d%s %c%d%d%d“, &stu.num,stu.name,&stu.sex,&stu.birthday.year,&stu.birthday.month,&stu.birthday.day);,10.2结构体数组,定义:结构数组的每一个元素,都是结构类型数据,均包含结构类型的所有成员。,struct student int num ;
13、 char name20; char sex; int age;float score;; struct student stu3 ;,stu0 stu1 stu2,结构体数组初始化: 结构体类型名 结构体数组名n初值表1,初值表2,.,初值表n;,struct student int num ; char name20; char sex; int age;float score;; struct student stu3101,“Lilin“,M,18,87.5,102,“Zhanghua“,M,18,99,103,Wuli“,F,19,78.5 ;,例定义结构类型struct std_i
14、nfo,定义一个结构数组stu,用于存储和显示三个学生的基本情况。,struct date int year; int month;int day; struct std_info int num ; char name20; char sex; struct date birthday; stu3=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 Birthdayn“);for(i=0; i3; i+) printf(
15、“%-7d“,stui.num);printf(“%-9s“,stui.name);printf(“%-4c“,stui.sex);printf(“%d-%d-%dn“,stui.birthday.year, stui.birthday.month,stui.birthday.day); ,程序运行结果: No. Name Sex Birthday 102 Zhangsan M 1980-9-20 105 Lisi M 1980-8-15 112 Wangwu F 1980-3-10, 统计后选人选票,struct person char name20;int count; leader3=“
16、Lian”,0,“ABian”,0,”Song“,0; main() int i,j; char leader_name20;for(i=1;i=10;i+) scanf(“%s“,leader_name);for(j=0;j3;j+)if(strcmp(leader_name,leaderj.name)=0)leaderj.count+;for(i=0;i3;i+)printf(“%5s:%dn“,leaderi.name,leaderi.count); ,10.3 指向结构体类型数据的指针,指向结构体变量的指针,结构体变量在内存中的起始地址称为结构体变量的指针。,struct studen
17、t int num ; char name20; char sex; int age;float score;; main() struct student stu;struct student *p=,struct student int num ; char name20; char sex; int age;float score;; main() struct student stu;struct student *p=,引用结构体变量成员的三种形式:,结构体变量.成员名 stu.num (*p).成员名 (*p).num p-成员名p-num,若struct student stu;
18、 struct student *p=&stu;则,结构体成员运算符“.“和“-“的比较: 二者的优先级相同,自左向右结合 运算符“.“前面只能是结构体变量名或(*p) 运算符“-“前面只能是指向结构体的指针变量名,不能是其它变量名stu-num,分析下列表达式: p-num p-num+ +p-num,设有以下语句: struct stint n;struct st *next; static struct st a3=5, 则表达式( )的值是6。 A.p+-n B.p-n+ C.(*p).n+ D.+p-n,D,指向结构体数组的指针,struct student int num ; ch
19、ar name20; char sex; int age;; struct student stu3101,“Lilin“,M,18,102,“Zhanghua“,M,18,103,Wuli“,F,19, ;struct student *p=stu;main() for( ; pnum,p-name,p-sex); ,说明: 如果指针变量p指向结构体数组,则p+1指向结构体数组的下一个元素,而不是当前元素的下一个成员。 如果指针变量p指向一个结构变量(或结构数组),就不能再使之指向结构体变量(或结构数组元素)的某一成员。p=stu; p=stu.name; (+p)-num (p+)-num
20、,下面程序的输出结果为( )。 struct st int x; int *y; *p; int dt4=10,20,30,40; struct st aa4=50, A.10 B.50 C. 51 D.60 20 60 60 70 20 21 21 31,dt,aa,x,y,&dt0 &dt1 &dt2 &dat3,p,p+,用结构体变量和指向结构体的指针作函数参数,用结构体类型数据作为函数参数有以下三种形式: 用结构体变量的成员作参数 用法与普通变量作参数相同,值传递 用结构体变量作参数 函数的实参和形参必须都是结构体变量,程序效率低,不主张用 用指向结构体变量的指针作参数提高运行效率,1
21、0.4 用指针处理链表,一、链表结构,链表的三要素: 头指针变量head指向链表的首结点(链表中每一个元素称为一个结点) 每个结点由2个域组成: 数据域-存储结点本身的信息 指针域-存储后继结点的指针(地址) 尾结点的指针域为NULL(空),作为链表结束的标志,10.5 共用体,概念:使几个不同的变量占有同一段内存空间的结构称为共用体 共用体类型的定义 -与结构体类型的定义类似,union 共用体类型名 类型标识符 成员名1;类型标识符 成员名2;,union category int class;char position10; ,共用体变量的定义-与结构体变量的定义类似,间接定义法: 先定
22、义共用体类型,后定义共用体变量,union data int i; char ch; float f; union data un1,un2,un3;,直接定义法: 在定义共用体类型的同时,定义共用体变量,union data int i; char ch; float f;un1,un2,un3;,union data int i; char ch; float f; union data un1,un2,un3;,注意:共用变量占用的内存空间,等于最长成员的长度,而不是各成员长度之和。,un1占用的内存空间为字节(不是2+1+4=7字节)。,共用体变量的引用与结构体变量的引用一样,也只能逐
23、个引用共用体变量的成员un11; ma;un1.i=1;mun1.i; 特点 (1)系统采用覆盖技术,实现共用变量各成员的内存共享,所以在某一时刻,最后一次存入的成员值是起作用的。 例如,执行un1.i=1; un1.ch=c; un1.f=3.14后,un1.f才是有效的成员。 (2)由于所有成员共享同一内存空间,故共用变量与其各成员的地址相同。 例如,un1=un1.i=un1.ch=un1.f。 (3)不能对共用体变量进行初始化(注意:结构体变量可以);也不能将共用变量作为函数参数,以及使函数返回一个共用体数据,但可以使用指向共用变量的指针。 (4)共用类型可以出现在结构类型定义中,反之
24、亦然。,结构体与共用体 区别: 存储方式不同,联系: 两者可相互嵌套,下面定义中sizeof(a)和sizeof(a.share)的值是?struct date int day;int month; int year;union int share1;float share2;share; a;,例,sizeof(a)=10 sizeof(a.share)=4,下面定义中变量w在内存中所占字节数?union aa float x,y;char c6; ; struct st union aa v;float w5;double ave; w;,例,sizeof(w)=34,下列程序输出结果是(
25、 )。#include main() union int k;char i2;*s,a;s=A.3839 B.3938 C.380039 D.390038,例,a.k,a.i0,a.i1,共用体变量a,或s-k,或s-i0,或s-i1,在内存中存储 形式为,0011 1001,下列程序输出结果是( )。#include main() union int k;char i2;*s,a;s=A.3839 B.3938 C.380039 D.390038,例,共用体变量a,s-k,s-i0,s-i1,0011 1001,0011 1000,在内存中存储 形式为,下列程序输出结果是( )。#inclu
26、de main() union int k;char i2;*s,a;s=A.3839 B.3938 C.380039 D.390038,例,共用体变量a,0011 1001,0011 1000,低字节,高字节,故s-k在 内存中存储数据为: 0011 1000 0011 1001,s-k,s-i0,s-i1,若有以下的说明、定义和语句,则输出结果为_。main() union un int a;char c2; w;w.c0=A;w.c1=a;printf(“%on“,w.a); ,例,w.a,w.c0,w.c1,共用体变量w,0100 0001,若有以下的说明、定义和语句,则输出结果为_。
27、main() union un int a;char c2; w;w.c0=A;w.c1=a;printf(“%on“,w.a); ,例,w.a,w.c0,w.c1,共用体变量w,0100 0001,0110 0001,若有以下的说明、定义和语句,则输出结果为_。main() union un int a;char c2; w;w.c0=A;w.c1=a;printf(“%on“,w.a); ,例,w.a,w.c0,w.c1,共用体变量w,0100 0001,0110 0001,故w.a在 内存中存储数据为: 0110 0001 0100 0001,若有以下的说明、定义和语句,则输出结果为_。
28、main() union un int a;char c2; w;w.c0=A;w.c1=a;printf(“%on“,w.a); ,例,w.a,w.c0,w.c1,共用体变量w,0100 0001,0110 0001,故w.a在 内存中存储数据为: 0110 0001 0100 0001,以八进制形式输出,二进制向八进制转换原则是:三位二进制对应一位八进制,1,若有以下的说明、定义和语句,则输出结果为_。main() union un int a;char c2; w;w.c0=A;w.c1=a;printf(“%on“,w.a); ,例,w.a,w.c0,w.c1,共用体变量w,0100
29、0001,0110 0001,故w.a在 内存中存储数据为: 0110 0001 0100 0001,以八进制形式输出,二进制向八进制转换原则是:三位二进制对应一位八进制,1,0,若有以下的说明、定义和语句,则输出结果为_。main() union un int a;char c2; w;w.c0=A;w.c1=a;printf(“%on“,w.a); ,例,w.a,w.c0,w.c1,共用体变量w,0100 0001,0110 0001,故w.a在 内存中存储数据为: 0110 0001 0100 0001,以八进制形式输出,二进制向八进制转换原则是:三位二进制对应一位八进制,1,0,5,若
30、有以下的说明、定义和语句,则输出结果为_。main() union un int a;char c2; w;w.c0=A;w.c1=a;printf(“%on“,w.a); ,例,w.a,w.c0,w.c1,共用体变量w,0100 0001,0110 0001,故w.a在 内存中存储数据为: 0110 0001 0100 0001,以八进制形式输出,二进制向八进制转换原则是:三位二进制对应一位八进制,1,0,5,0,若有以下的说明、定义和语句,则输出结果为_。main() union un int a;char c2; w;w.c0=A;w.c1=a;printf(“%on“,w.a); ,例
31、,w.a,w.c0,w.c1,共用体变量w,0100 0001,0110 0001,故w.a在 内存中存储数据为: 0110 0001 0100 0001,以八进制形式输出,二进制向八进制转换原则是:三位二进制对应一位八进制,1,0,5,0,6,运行结果:60501,以下程序运行的输出结果是( )。 main() union char i2;int k;r;r.i0=2;r.i1=0;printf(“%dn“,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 EXAMPL
32、E struct int x; int y; in; int a; int b; e; e.a=1; e.b=2; e.in.x=e.a*e.b; e.in.y=e.a+e.b; printf(“%d,%dn“,e.in.x,e.in.y); ,程序运行的结果是_。 main() union EXAMPLE struct int x; int y; in; int a; int b; e; e.a=1; e.b=2; e.in.x=e.a*e.b; e.in.y=e.a+e.b; printf(“%d,%dn“,e.in.x,e.in.y); ,e.in,e.a,或e.b,共用体变量e,1,e
33、.in.x,e.in.y,例,程序运行的结果是_。 main() union EXAMPLE struct int x; int y; in; int a; int b; e; e.a=1; e.b=2; e.in.x=e.a*e.b; e.in.y=e.a+e.b; printf(“%d,%dn“,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.a=1; e.b=2; e.i
34、n.x=e.a*e.b; e.in.y=e.a+e.b; printf(“%d,%dn“,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 w
35、ork;,说明:(1)枚举型仅适应于取值有限的数据。例:1周天,年个月。 (2)取值表中的值称为枚举元素,其含义由程序解释。例:不是因为写成“Sun”就自动代表“星期天”。事实上, 枚举元素用什么表示都可以。 (3)枚举元素按常量处理,它们的值是定义时的顺序号(从开始),所以枚举元素可以进行比较,比较规则是:序号大者为大!例:上例中的Sun的值为0、Mon的值为1、Sat的值为6,所以MonSun,Sat最大。 (4)枚举元素的值也是可以人为改变的:在定义时由程序指定。例:如果enum weekdays Sun=, Mon ,Tue, Wed, Thu, Fri, Sat;则Sun=,Mon=
36、,从Tue=2开始,依次增。注意:不同的枚举元素不可以指定相同的值(5)一个整数不能直接赋值给枚举变量例:workday2;(非法,因为类型不同)改写成:workday(enum weekday)2;,下面程序的输出是( )。 main() enum teammy,your=4,his,her=his+10; printf(“%d %d %d %dn“,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 emem1=3,em2=1,em3; char *aa=“AA“,“BB
37、“,“CC“,“DD“; printf(“%s%s%sn“,aaem1,aaem2,aaem3); ,DDBBCC,10.10 用typedef定义类型,作用:用typedef定义已有类型的别名。该别名与标准类型名一样,可用来定义相应的变量。 定义已有类型别名的方法(1)按定义变量的方法,写出定义体; (2)将变量名换成别名; (3)在定义体最前面加上typedef。,关键字,例:给实型float定义1个别名REAL。 (1)按定义实型变量的方法,写出定义体: float f; (2)将变量名换成别名:float REAL; (3)在定义体最前面加上typedef: typedef float
38、 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只是给已有类型增加个别名,并不能创造个新的类型。(2)typedef与#define有相似之处,但二者是不同的:前者是由编译器在编译时处理的;后者是
39、由编译预处理器在编译预处理时处理的,而且只能作简单的字符串替换。,1.设有以下定义 typedef union long i; int k5; char c; DATE; struct date int cat; DATE cow; double dog; too; DATE max; 则语句printf(%d,sizeof(struct date)+sizeof(max)的执行结果是( )。 A.25 B.30 C.18 D.8,2 .下面程序的输出是( )。 typedef union long x2; int y4; char z8; MYTYPE; MYTYPE them; main(
40、) printf(“%dn“,sizeof(them); A.32 B.16 C.8 D.24,4.设有以下说明语句 typedef struct int n; char ch8; 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,若有以下说明和定义 typedef int *INTEGER INTEGER p,*q; 以下叙述正确的是_。 A) p是int型变量 B) p是基类型为int的指针变量 C) q是基类型为int的指针变量 D) 程序中可用INTEGER代替int类型名,B,