《第7章用户定制数据类型.ppt》由会员分享,可在线阅读,更多相关《第7章用户定制数据类型.ppt(73页珍藏版)》请在三一办公上搜索。
1、第七章用户定制数据类型,C语言提供有丰富的数据类型:,结构体(struct):也称集合数据类型,用于将不同类型的数据组织在一个名字下。共用体(union):允许一个存储空间中存储不同类型的变量。枚举(enumeration):用一组符号代替一组整数。typedef:用于为已经存在的类型定义新名字。,7.1 结构体类型基础,7.1.1 结构体类型及其定制1.结构体类型的概念现实生活中存在着大量需要作为一个整体来处理的数据,而这些数据的类型又不相同。例如:要处理学籍数据,需要处理学生学号(num)、姓名(name)、性别(sex)、年龄(age)、成绩(score)和地址(addr)等数据。而数组
2、则无法容纳不同类型的元素。结构体(structure),也称“结构”,就是C语言提供的处理一组不同类型数据的类型。,例如上述处理学籍的结构体类型定制语句为:,struct Student unsigned int num;char name20;char sex;int age;float score;char addr30;,struc 结构体名成员声明表列;,结构体类型的定制 是由声明成员的一组语句组成的,形式为,truct Addr char name30;/*姓名*/char street40;/*街道*/char city20;/*城市*/char provn20;/*省名*/uns
3、igned int zip;/*邮编*/,同样的方法可以为建立通信录定制一种数据类型struct Addr:,说明:(1)一个结构体类型的标志由两个单词组成:第一个单词为关键struct,它表明该类型是一种结构体类型;第二个单词是结构体名,如前面介绍的Student、Add,由程序设计者按标识符规则指定。这二者联合起来组成一个“类型标识符”即“类型名”,相当与int。,(2)age,sex,num不能称为变量名,而是结构体类型struct person的成员名。在一个函数中,可以另外定义与结构体类型的成员相同名的变量,它们代表不同的对象。例如:,struct Student char sex;
4、/*成员名*/int age;/*成员名*/;int age;/*变量名*/char sex;/*变量名*/,7.1.2定义结构体类型变量及对变量的初始化 定制一个结构体类型后,得到一个结构体类型名。有了这个类型名,就可以像int、char、float和double一样,用来定义一些结构体类型的变量。定义了变量,系统就会为变量分配存储空间。1.定义结构体变量可以采用不同的方法定义一个结构体类型的变量。(1)在定义了一个结构体类型之后,把变量定义为该类型。如有以下声明:,struct Student stdnt1,stdnt2,stdnt3;,定义了stdnt1、stdnt2,和stdnt3三个
5、struct Student类型的结构体变量。注意不能写成:,struct Student,stdnt1,stdnt2,stdnt3;/*错误逗号*/,Student stdnt1,stdnt2,stdnt3;/*缺少关键字struct*/,struct/*注意这个头部没有类型名*/unsigned int num;char name20;char sex;int age;float score;char addr30;stdnt1,stdnt2,stdnt3;,也不能写成:,(2)直接定义结构体类型的变量。如:,此时只是按照花括弧内的结构,直接定义了stdnt1,stdnt2和stdnt3s
6、tudent三个变量,并没有定义此结构体类型的名字。因此无法用结构体类型名再定义其它变量。,(3)在声明一个结构体类型的同时定义一个或若干个结构体变量。如:,struct Student unsigned int num;char name20;char sex;intage;float score;char addr30;stdnt1,stdnt2,stdnt3;,它的一般形式为:,struct 结构体名成员声明表列变量名表列;,这种形式紧凑,既声明了类型,又定义了变量。如果需要再用此struct Student定义其它变量,还可以用:,struct Student stdnt3,stdnt
7、4,stdnt5;,2.结构体变量的初始化在定义了结构体变量之后,stdnt1,stdnt2,stdnt3等就具有struct Student结构体类型的特征,也有了变量的特征。例如,stdnt1、stdnt2和stdnt3的值可以有如图7.1所示的值。,struct Student unsigned int num;char name20;char sex;int age;float score;char addr30;stdnt1=50201,”ZhangXi”,M,18,90.5,”Shanghai”,stdnt2=50202,”WhangLi”,F,19,88.3,”Beijing”;
8、,也可以用以下形式,Struct Studentstdnt3=50203,”LiHong”,M,17,79.9,”Shanxi”;,struct Student unsigned int num;char name20;char sex;unsigned char age;float score;#include int main(void)struct Student student1=50201,“WangLi”,M,18,89.5;struct Student student2;student2=student1;/*结构体变量间赋值*/printf(“student1:%u,%s,%c
9、,%u,%5.2fn”,student1.num,student1.name,student1.sex,student1.age,student1.score);printf(“student2:%u,%s,%c,%u,%5.2fn”,student2.num,student2.name,student2.sex,student2.age,student2.score);return 0;,运行情况如下:,2.引用结构体变量的成员 由于一个结构体变量是一个整体,要访问它其中的一个成员,必须先找到这个结构体变量,然后再从中找到它其中的一个成员。例如要访问结构体变量student1中的num,应写
10、成以下形式:student1.num 表达式studen1.num=50201将把50201赋值给结构体变量student1中的成员num。成员运算符的运算级别最高例如:student.1.num+100,在num两侧有二个运算符,由于成员运算符的运算优先于加号运算符,故相当于:(student1.num)+100,3.结构体类型数据的输出,printf(“%dn”,student1);scanf(“%d”,printf(%s,%d,%c,%d/%d/%d,%1d,%5.2fn,student1);,printf(%s,%s,%1dn,student1.name,student1.addr,s
11、tudent1.num);,为描述方便,假设有一个简单的结构体类型:,struct char name10;char addr18;unsigned int num;student1=“WangLi”,”12 Beijing Road”,50201;,由于C规定不允许对结构体变量作整体输入输出。如果想输出变量student1的值,应当用语句,printf(%s,%s,%1dn,student1.name,student1.addr,student1.num);,图7.2 student1在内存中的存储,变量student1在内存的存储如图7.2所示。,7.1.4 嵌套结构体类型 在声明一个结构
12、体类型时可以利用已声明了的另一个结构体类型来定义其成员的类型。这称为嵌套结构体类型。例7.2,struct Date int month;int day;int year;/*声明了一个struct Date类型*/struct Person char name20;/*姓名*/char sex;/*性别*/struct Date birthday;/*出生日期birthday是另一个结构体类型的成员*/unsigned long num;/*身份证号*/;,这样的定义相当于:,struct Person char name20;/*姓名*/char sex;/*性别*/int month;i
13、nt day;int year;unsigned longnum;/*身份证号*/;,当使用嵌套结构体类型定义了变量后,对结构体变量成员的操作,应采用逐级访问的方式进行。例如定义两个变量 struct Person zhang,wang;后,要访问zhang的出生年份,应当用表达式 zhang.Data.year下面是一个应用程序:,#include int main(void)struct Person p1=WangLi,M,12,15,1974,111000222;struct Person p2;p2=p1;printf(zhang:%s,%c,%d-%d-%d,%lun“,p1.na
14、me,p1.sex,p1.birthday.month,p1.birthday.day,p1.birthday.year,p1.num);printf(zhang:%s,%c,%d-%d-%d,%lun,p2.name,p2.sex,p2.birthday.month,p2.birthday.day,p2.birthday.year,p2.num);,运行情况如下:,也可以把一个结构体变量中的内嵌结构体类型成员赋给另一个结构体变量的相应部分。如上例中如果有下列语句是合法的:student2.birthday=student1.birthday,7.2 结构体数组,一个结构体变量只能存放一个对象
15、(如一个学生、一个职工)的一组数据。如果要存放一个班(30人)学生的有关数据就要设30个结构体变量,例student1,student2,student30,显然是很不方便的。人们自然想到使用数组,即将同类型的结构体变量用数组进行组织。7.2.1 结构体数组的定义与初始化1.定义结构体数组图7.5以struct Student 为例,说明定义结构体数组可以采用的三种方法。,struct Studentunsigned int num;Struct Student stu30;,struct Studentunsigned int num;stu30;,struct unsigned int n
16、um;stu30;,(a),(b),(c),图7.5 定义结构体数组的三种方法,2.结构体数组的初始化,struct Student unsigned int num;char name16;char sex;intage;float score;char addr30;;struct Student stu3=50201,”ZhangXi”,M,18,90.5,”Shanghai”,50202,”WhangLi”,F,19,88.3,”Beijing”,50203,”LiHong”,M,17,79.9,”Shanxi”;,定义了一个struct Student类型结构体数组stu,它有3个元
17、素,又定义了一个结构体变量student1,则下面的赋值合法:,struct Student stu3,student1;,7.2.2 对结构体数组元素的操作1.结构体数组元素的赋值 一个结构体元素(结构体下标变量)相当于一个结构体变量,可以将一个结构体数组元素赋值给同一结构体类型的数组中另一个元素,或赋给同一类型的变量。如,student1=stu0;stu0=stu1;stu1=student1;,2.引用结构体数组元素成员 引用结构体数组元素的成员的方法与引用结构体变量成员的方法相同。例如 stui.num 是引用下标为i的stu数组元素中的num成员。如果数组已初始化,且i=2,则相当
18、于stu2.num。,#include#include#define StuNUM 3struct StudType char name16;longnum;int age;charsex;float score;int main(void)struct StudType stuStuNUM;int i;char ch;char numstr16;,例7.7 输入3个学生的信息并将它们输出。,/*输入数据*/for(i=0;iStuNUM;i+)printf(nenter all data of stu%d:n,i);gets(stui.name);gets(numstr);stui.num=
19、atol(numstr);gets(numstr);stui.age=atoi(numstr);stui.sex=getchar();ch=getchar();gets(numstr);stui.score=atof(numstr);/*输出数据*/printf(n record name t t numtagetsextscoren);for(i=0;iStuNUM;i+)printf(%dt%-16s%-8d%dt%-ct%6.2fn,i,stui.name,stui.num,stui.age,stui.sex,stui.score);return 0;,运行情况如下:,7.3 指向结构体
20、的指针,7.3.1 指向结构体变量的指针1.指向结构体变量的指针及其定义可以定义一个指针变量指向一个结构体变量。结构体变量的指针就是这个结构体变量所占内存单元段的起始地址。如果已经如前定义了一个struct studtype类型,则可用下面形式定义一个指向这一种类型数据的指针变量:struct studtype*p;,2.使用指向结构体变量的指针引用结构体变量的成员,#include#include struct StudType char name16;longnum;int age;charsex;float score;,int main(void)struct StudType stu
21、dent,*p;strcpy(student.name,Wang Li);student.num=50101;student.age=18;student.sex=m;student.score=89.5;/*使用指向结构体变量的指针引用成员*/p=,运行结果如下:,说明:可以通过指针变量p引用它所指向的结构体变量student中的成员值。(*p).name就是引用p所指向的结构体变量中的name成员。不能写成p.name,因为p不是结构体变量。,3.使用指向结构体变量的指针指向变量的成员 用“(*p).成员名”来引用成员还嫌不直观,C语言允许将它写为“p-成员名”,例如:p-name和p-n
22、um。它更形象化的表示是p所指向的变量中的成员。用一个减号“-”和一个大于号“”两个字符组成指向运算符,形象地代表一个向右的箭头。“-”运算符的优先级别最高。又如:p-num+1相当于(p-num)+1p-num+相当于(p-num)+例7.8中main()的输出语句可改写为:,printf(“nnam:%snnum:%ldnage:%dnsex:%cnscore:%6.2fn”,p-name,p-num,p-age,p-sex,p-score);,7.3.2 指向结构体数组的指针C编译器不仅为一个结构体变量分配一个连续的存储空间,而且还像一般数组一样,为结构体数组中的元素分配一个连续的存储空
23、间。例如,struct StudType char name16;long num;int age;char sex;float score;stu3;,被分配的存储空间如图7.6所示。,图7.6 结构体数组的内存分配,根据C语言中指针与数组的关系,如果定义一个指向结构体数组的指针p=stu,p指向stu0,p+1 指向stu1,p+2 指向stu2。因此,例7.9中的程序可以改用指针实现。,#include#include#define StuNUM 3struct StudType char name16;long num;int age;char sex;float score;,int
24、 main(void)struct StudType stuStuNUM,*p;int i;char numstr16;/*输入数据*/for(i=0,p=stu;pname);gets(numstr);p-num=atol(numstr);gets(numstr);p-age=atoi(numstr);p-sex=getchar();getchar();gets(numstr);p-score=atof(numstr);/*输出数据*/printf(n record name t t numtagetsextscoren);for(i=0,p=stu;pname,p-num,p-age,p-
25、sex,p-score);return 0;,程序运行结果:,7.6 共用体类型数据,7.6.1 共用体的特点1.共用体类型的定制与共用体变量的定义关于共用体(union)数据类型是指将不同的数据项存放于同一段内存单元的一种构造数据类型。下面是一个共用体的例子:,union exam int a;double b;char c;x;,这个结构与结构体形式相同,数据类型的定制和变量的定义形式也与结构体相似,即可以采用如下三种形式:(1)然后用共用体类型定义共用体变量。(2),union共用体名成员表列;,union共用体名成员表列变量表列;,(3),union成员表列变量表列;,2.共用体类型与
26、结构体类型的比较共用体与结构体在形式上相似,但实质上有很大不同。下面在同样成员的情况下对二者进行比较。假定它们都有如下3个成员:4字节的int类型成员a;8字节的double类型成员b;1字节的char类型成员c。,(a)结构体的存储分配,(b)共用体的存储分配,图7.13 结构体与共用体的存储分配,(1)存储结构不同。,(2)由于结构体中的每个成员都有自己的存储空间,所有成员可以同时存储;而共用体中所有的成员共用一个存储空间,同一时间只能存储一个成员。(3)结构体变量可以在定义时进行初始化;而共用体变量不能在定义时进行初始化。例如下面的程序段都是非法的。,union m int i;char
27、 c;double d;x=3,s,3.141593;/*不能对共用体变量初始化*/,也不能直接用共用体变量名进行输入输出,如:,scanf(“%f”,#include#include int main(void)union exam int a;float b;char c;x,y;x.a=3;y=x;printf(“%dn”,y.a);,3,7.6.2 共用体变量的应用一个学校的人员数据管理中,对教师则应登记其“单位”,对“学生”则应登记其“班级”,它们都在同一栏中。可以:,struct long num;char name20;char sex;char job;/*职业*/union
28、int class;/*班级*/char group20;/*单位名*/category;person10;,如果job项输入为s(学生),则使程序接着接收一个整数给class(班号),如果job的值为t(教师),则接收一个字符串给group20。下面是一段应用程序:,scanf(“%c”,7.7 枚举类型数据,所谓“枚举”类型,是指这种类型的变量的值只能是指定的若干个名字之一。例如一个枚举类型和枚举变量可以定义如下:,enumcolorname red,yellow,blue,white,black;/*定义枚举类型enum colorname*/enum colorname color;/
29、*定义枚举变量color*/,变量color是枚举型enum colorname的,它的值只能是red,yellow,blue,white,black五者之一。,enumcolorname red,yellow,blue,white,black;/*定义枚举类型enum colorname*/enum colorname color;/*定义枚举变量color*/,例如下面的赋值合法,color=red;color=white;,而下面的语句不合法:,color=green;color=orange;,说明:(1)enum是关键字,标识枚举类型,定义枚举类型必须用enum开头。(2)在定义枚举
30、类型时,花括弧中的一些名字(red,yellow,blue,white,black)是程序设计者自己指定的,命名规则与标识符相同。这些名字并无固定的含义,只是一个符号。程序设计者仅仅为了使程序可读性提高才使用这些名字。,(3)它的值是一些整数。从花括弧中第一个名字开始,各名字分别代表0,1,2,3,4。这是系统自动赋给的,如:,printf(“%d”,red);,输出的值为0。但是定义枚举类型时不能写成:,enum colorname 0,1,2,3,4;,必须用符号red,yellow,:或其它标识符。这些符号称为枚举常量,或枚举元素。,(4)可以在定义类型时对枚举常量初始化,enum co
31、lornamered=3,yellow,blue,while=8,black;,此时,red为3,yellow为4,blue为5,while为8,black为9。因为yellow在red之后,red为3,yellow顺序加1,同理black为9,如果没有初始化,系统自动赋值,从花括弧中第一个名字开始,各名字分别代表0,1,2,3,4。(5)枚举常量可以进行比较,如:,if(color=red)printf(“red”);if(color!=black)printf(“it is not black!”);if(colorwhile)printf(“it is black”);,7.8 用Typ
32、edef定义类型,C语言还允许在程序中用typedef来定义新的类型名来代替已有的类型名。下面介绍typedef的几种用法。1.简单的名字替换,定义a,b为INTEGER类型,也即int类型。,typedef int INTEGER;,意思是将int型定义为INTEGER,这二者等价,在程序中就可以用INTEGER作为类型名来定义变量了。,INTEGER a,b;/*相当于int a,b;*/,2.定义一个结构体类型名,如,这样以后就可以用名字STUDENT来定义变量了。如,typedef struct char name20;long num;float score;STUDENT;,STU
33、DENT student1,student2,*p;,4.定义指针类型。,Typedef int COUNT20;/*定义COUNT为整型数组*/Typedef char NAME20;/*定义NAME为字符数组*/COUNT a,b;/*a,b为整型*/NAME c,d;/*c,d为字符数组*/,typedef char*STRING;/*定义STRING为字符指针类型*/STRING p1,p2,p10;/*p1,p2为字符指针变量,p为字 符指针 数组名*/,3.定义数组类型。,5.小结 归纳起来,用typedef定义一个新类型名的方法如下:先按定义变量的方法写出定义体(如char a2
34、0);将变量名换成新类型名(如char NAME20;)在最前面加上typedef(如typedef char NAME20;)然后可以用新类型名去定义变量(如NAME c,d;),习题,对于下面的声明,struct xyzint a;char bstruct xyz s1,s2;,在编译时,将会发生那种情形:()A.编译时错 B.编译、链接、执行都通过 C.编译和链接都通过,但不能执行 D.编译通过,但链接出错,习题,有结构体类型定义,struct s int a;int b;vs;,在下列候选答案中,选择正确的赋值操作:()A.s.a=5;B.s.vs.a=5;C.struct va;va
35、.x=5;D.struct s va=5;E.struct s vs.a=5;F.vs.a=5;,对于定义,struct saint x;float y;data,*p=,请从下列候选答案中,选择数据data的x成员的正确引用:()A.(*p).data B.(*p).x C.p-data.x D.p.data.x,对于定义 struct st int n;struct st*next;a3=5,7,(9),*p=则值为6的表达式为:()A.p+-n B.p-n+C.+p-n D.(*p).n+,阅读程序,指出程序的输出结果,#include struct sint x;int y;cnum2
36、=1,3,2,7;main()printf(“%dn”,cnum0.y*cnum1.x);,#include main()enum teammy,your=4,his,her=his+10;printf(“%d%d%d%dn”,my,your,his,her);,阅读程序,指出程序的输出结果,(5),#include main()unionunsigned char c;unsigned int i4;z;z.i0=0 x39;z.i0=0 x36;printf(%cn“,z.c);,#include typedef union long x2;int y4;char z8;MYTYPE;MY
37、TYPE them;main()printf(“%dn”,sizeof(them);,提示:字符0的十六进制ASCII码为30。(6),7.3 职工数据包括:职工号、职工名、性别、年龄、工龄、工资、地址。(1)为其定义一个结构体变量。(2)对上述定义的变量,从键盘输入所需的具体数据,然后用printf函数显示出来。(3)定义一个职工数据的结构体数组,从键盘输入每个结构体元素所需的数据,然后逐个输出这些元素的数据(为简化起见,可设数组只有三个元素)。7.4 设计一个用于人事管理的结构体:(1)每个人的数据包括:职工号、姓名、性别、出生日期;(2)性别和出生日期用位段表示。7.5 有n个学生,每个
38、学生的数据包括学号(num),姓名(name20),性别(sex),年龄(age),三门课成绩(score3)。(1)要求在main函数中输入这几个学生的数据,然后调用一个函数count,在该函数中计算出每个学生的总分和平均分,然后打印出所有各项数据(包括原有的和新求出的)。提示:在定义结构体类型时应预留出准备计算结果的成员项;用结构体变量为函数参数,将各数据传给count函数。(2)改为用指针方法处理,即用指针变量逐次指向数组中各元素,然后向指针变量所指向的元素输入数据,并将指针变量作为函数参数将地址值传给count函数,在函数count中作统计,然后将数据返回main函数,在main函数输
39、出。,7.6 有4名学生,每个学生包括学号、姓名、成绩,要求用指针方法找出成绩最高者的姓名和成绩。7.7 建立一个链表,每个节点包含的成员为:职工号、工资。(1)用malloc函数开辟新节点。要求链表包含5个节点,从键盘输入节点中的有效数据。然后把这些节点的数据打印出来。要求用函数creat来建立函数,用list函数来输出数据。这5个职工的号码为0601,0603,0605,0607,0609。(2)在(1)的基础上,新增加一个职工的数据。这个新节点不放在最后,而是按职工号顺序插入,新职工号为0606。写一个函数insert来插入新节点。(3)在(1)、(2)的基础上,写一个函数delete,
40、用来删除一个节点(按指定的职工号删除)。要求删除职工号为0606的节点;7.7 有一个unsigned long类型整数(4字节),想分别将前2个字节和后两个字节作为两个unsigned short类型输出(各占2个字节)。用一函数实现,并要将unsigned long型数作为参数,在函数中输出这两个unsigned short数据 7.8 将4个字符“拼”成一个long型数,这4个字符为“a”,“b”,“c”,“d”。写一函数,把由这4个字符连续组成的4个字节内容作为一个long int数输出。,7.9 某校建立一个人员登记表,内容示例如下:,请为之建立一个数据库。7.10 口袋中有红、黄、兰、白、黑五种颜色的球若干个,每次从口袋中取出3个。问得到三种不同色的球的可能取法,打印出每种组合的三种颜色(提示,用枚举类型)。7.11 有一个信息系统,需要设计一个菜单程序,进行有关功能的调用。请用菜单程序设计一个用指向函数的指针实现这一调用功能。,