资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,*,C,语言程序设计 第九章 结构、联合与枚举,计算机公共教学部,第九章 结构体、共用体与枚举,结构体,结构体变量的定义,结构体变量的引用,结构体变量的初始化,结构体数组,结构体和指针,共用体,迄今为止,已介绍了基本类型,(,或称简单类型,),的变量,(,如整型、实型、字符型变量等,),,也介绍了一种构造类型数据,数组,数组中的各元素是属于同一个类型的。但是只有这些数据类型是不够的。有时需要将不同类型的数据组合成一个有机的整体,以便于引用。这些组合在一个整体中的数据是互相联系的。例如,一个学生的学号、姓名、性别、年龄、成绩、家庭地址等项。这些项都与某一学生相联系。见图,1,。可以看到性别,(sex),、年龄,(age),、成绩,(score),、地址,(,addr,),是属于学号为,10010,和名为“,Li Fun”,的学生的。如果将,num,、,name,、,sex,、,age,、,score,、,addr,分别定义为互相独立的简单变量,难以反映它们之间的内在联系。,概述,应当把它们组织成一个组合项,在一个组合项中包含若干个类型不同,(,当然也可以相同,),的数据项。,C,语言允许用户自己指定这样一种数据结构,它称为结构体,(structure),。它相当于其他高级语言中的“记录”。,图,1,假设程序中要用到图,1,所表示的数据结构,但是,C,语言没有提供这种现成的数据类型,因此用户必须要在程序中建立所需的结构体类型。例如:,struct,student,int,num,;,char,name20,;,char,sex,;,int,age,;,float,score,;,char,addr30,;,;,注意,不要忽略最后的分号。上面由程序设计者指定了一个新的结构体类型,struct,student(struct,是声明结构体类型时所必须使用的关键字,不能省略,),,它向编译系统声明这是一个“结构体类型”,它包括,num,、,name,、,sex,、,age,、,score,、,addr,等不同类型的数据项。应当说明,struct,student,是一个类型名,它和系统提供的标准类型,(,如,int,、,char,、,float,、,double,等,),一样具有同样的地位和作用,都可以用来定义变量的类型,只不过结构体类型需要由用户自己指定而已。,结构体,结构体是一种,构造,数据类型,用途:把,不同类型,的数据组合成一个整体,-,自定义,数据类型,结构体类型定义,struct,结构体名,类型标识符 成员名;,类型标识符 成员名;,.,;,成员类型可以是,基本型或构造型,struct,是,关键字,不能省略,合法标识符,可省,:,无名结构体,例,struct,student,int,num;,char name20;,char sex;,int,age;,float score;,char addr30;,;,name,num,sex,age,score,addr,2,字节,2,字节,20,字节,1,字节,4,字节,30,字节,.,结构体类型定义描述结构,的组织形式,不分配内存,例子图解,1.,先定义结构体类型,再定义结构体变量,一般形式:,struct,结构体名,类型标识符 成员名;,类型标识符 成员名,;,.,;,struct,结构体名,变量名表列;,结构体变量的定义,如上面已定义了一个结构体类型,struct,student,,可以用它来定义变量。如,:,struct,student student1,student2,结构体类型名 结构体变量名,;,定义了,student1,和,student2,为,struct,student,类型的变量,即它们具有,struct,student,类型的结构。如图,2,所示。,图,2,在定义了结构体变量后,系统会为之分配内存单元。例如,student1,和,student2,在内存中各占,59,个字节,(2+20+1+2+4+30=59),。,应当注意:,将一个变量定义为标准类型,(,基本数据类型,),与定义为结构体类型不同之处在于后者不仅要求指定变量为结构体类型,而且要求指定为某一特定的结构体类型,(,例如,struct,student,类型,),。因为可以定义出许许多多种具体的结构体类型。而在定义变量为整型时,只需指定为,int,型即可。,一般形式:,struct,结构体名,类型标识符 成员名;,类型标识符 成员名;,.,变量名表列;,例,struct,student,int,num;,char name20;,char sex;,int,age;,float score;,char addr30;,stu1,stu2;,2.,定义结构体类型的同时定义结构体变量,struct,类型标识符 成员名;,类型标识符 成员名;,.,变量名表列;,例,struct,int,num;,char name20;,char sex;,int,age;,float score;,char addr30;,stu1,stu2;,用,无名结构体,直接定义,变量,只能一次,3.,直接定义结构体变量,一般形式:,关于结构体类型,有几点要说明:,(1),类型与变量是不同的概念,不要混同。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。,(2),对结构体中的成员,(,即“域”,),,可以单独使用,它的作用与地位相当于普通变量。关于对成员的引用方法。,(3),成员也可以是一个结构体变量。,(4),成员名可以与程序中的变量名相同,二者不代表同一对象。例如,程序中可以另定义一个变量,num,它与,struct,student,中的,num,是两回事,互不干扰。,struct,date,/*,声明一个结构体类型*,/,int,month,;,int,day,;,int,year,;,;,struct,student,int,num,;,char,name20,;,char,sex,;,int,age,;,struct,date birthday,;,/*birthday,是,struct,date,类型,*,/,char,addr30,;,student1,,,student2,;,先声明一个,struct,date,类型,它代表“日期”,包括,3,个成员:,month(,月,),、,day(,日,),、,year(,年,),。然后在声明,struct,student,类型时,将成员,birthday,指定为,struct,date,类型。,struct,student,的结构见图,3,所示。已声明的类型,struct,date,与其他类型,(,如,int,,,char),一样可以用来定义成员的类型。,图,3,结构体变量的引用,在定义了结构体变量以后,当然可以引用这个变量。但应遵守以下规则,:,(1),不能将一个结构体变量作为一个整体进行输入和输出。例如,已定义,student1,和,student2,为结构体变量并且它们已有值。不能这样引用,:,printf,(%d,%s,%c,%d,%f,%sn,student1);,只能对结构体变量中的各个成员分别进行输入和输出。引用结构体变量中成员的方式为,结构体变量名,.,成员名,例如,:student1.num,表示,student1,变量中的,num,成员,即,student1,的,num(,学号,),项。可以对变量的成员,赋值,例如,:,student1.num=10010;,“.”,是成员,(,分量,),运算符,它在所有的运算符中优先级最高,因此可以把,student 1.num,作为一个整体来看待。上面赋值语句的作用是将整数,10010,赋给,student 1,变量中的成员,num,。,(2),如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低的一级的成员。只能对最低级的成员进行赋值或存取以及运算。例如,对上面定义的结构体变量,student1,可以这样访问各成员,:,student1.num,student1.birthday.month,注意,:,不能用,student1.birthday,来访问,student1,变量中的成员,birthday,因为,birthday,本身是一个结构体变量。,(3),对结构体变量的成员可以像普通变量一样进行各种运算,(,根据其类型决定可以进行的运算,),。例如:,student2,score=student1,score,;,sum=student1,score+student2,score,;,student1,age+,;,+student1,age,;,由于“”运算符的优先级最高,因此,student1,age+,是对,student1,age,进行自加运算,而不是先对,age,进行自加运算。,(4),可以引用结构体变量成员的地址,也可以引用结构体变量的地址。如:,scanf(%d,,,(,输入,student1,num,的值,),printf(%o,,,&student1),;,(,输出,student1,的首地址,),但不能用以下语句整体读入结构体变量,如:,scanf(%d,,,%s,,,%c,,,%d,,,%f,,,%s,,,&student1),;,结构体变量的地址主要用于作函数参数,传递结构体的地址。,11.4,结构体变量的初始化,和其他类型变量一样,对结构体变量可以在定义时指定初始值。,例,11.1,对结构体变量初始化。,形式一:,struct,结构体名,类型标识符 成员名;,类型标识符 成员名;,.,;,struct,结构体名,结构体变量,=,初始数据,;,例,struct,student,int,num;,char name20;,char sex;,int,age;,char addr30;,;,struct,student stu1=112,“Wang Lin”,M,18,“200 Beijing Road”;,结构体变量的初始化,struct,结构体名,类型标识符 成员名;,类型标识符 成员名;,.,结构体变量,=,初始数据,;,例,struct,student,int,num;,char name20;,char sex;,int,age;,char addr30;,stu1=112,“Wang Lin”,M,18,“200 Beijing Road”;,结构体变量的初始化,形式二:,struct,类型标识符 成员名;,类型标识符 成员名;,.,结构体变量,=,初始数据,;,例,struct,int,num;,char name20;,char sex;,int,age;,char addr30;,stu1=112,“Wang Lin”,M,18,“200 Beijing Road”;,结构体变量的初始化,形式三:,结构体数组的定义,三种形式:,形式一,:,struct,student,int,num;,char name20;,char sex;,int,age;,;,struct,student stu2;,形式二,:,struct,student,int,num;,char name20;,char sex;,int,age;,stu2;,形式三,:,struct,int,num;,char name20;,char sex;,int,age;,stu2;,num,name,sex,age,num,name,sex,age,stu0,stu1,25B,结构体数组,例,struct,int,num;,char name20;,char sex;,int,age;,stu,=,;,结构体数组引用,引用方式:,结构体数组名,下标,.,成员名,struct,student,int,num;,char name20;,char sex;,int,age;,str3;,stu1.age,+;,strcpy(,stu0.name,”ZhaoDa”);,结构体数组初始化,struct,person,char name20;,int,count;,leader3=“Li”,0,“Zhang”,0,”Wang“,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;i,成员名,结构体变量名,.,成员名,指向运算符,优先级,:1,结合方向:从左向右,struct,student stu1;,struct,student *p=,stu1.num,=101,;,(*p).num,=101,结构体和指针,用结构体变量的成员作参数,-,值传递,用指向结构体变量或数组的指针作参数,-,地址传递,用结构体变量作参数,-,多值传递,,效率低,用指向结构体的指针作函数参数(看书自学),有时需要使几种不同类型的变量存放到同一段内存单元中。例如,可把一个整型变量、一个字符型变量、一个实型变量放在同一个地址开始的内存单元中。以上,3,个变量在内存中占的字节数不同,但都从同一地址开始存放。也就是使用覆盖技术,几个变量互相覆盖。这种使几个不同的变量共占同一段内存的结构,称为“共用体”类型的结构。,构造数据类型,也叫联合体,用途:使几个不同类型的变量共占一段内存,(,相互覆盖,),共用体类型定义,定义形式:,union,共用体名,类型标识符 成员名;,类型标识符 成员名;,.,;,例,union data,int,i;,char,ch,;,float f;,;,f,ch,i,类型定义,不分配内存,共用体,形式一,:,union data,int,i;,char,ch,;,float f;,a,b;,形式二,:,union data,int,i;,char,ch,;,float f;,;,union data a,b,c,*p,d3;,形式三,:,union,int,i;,char,ch,;,float f;,a,b,c;,f,ch,i,f,ch,i,a,b,共用体变量定义,分配内存,长度,=,最长成员,所占字节数,共用体变量任何时刻,只有,一个成员,存在,共用体变量的定义,引用方式:,例,a.i=1;,a.ch,=a;,a.f=1.5;,printf(“%d”,a.i,);(,编译通过,运行结果不对,),引用规则,不能引用共用体变量,只能,引用其成员,共用体指针名,-,成员名,共用体变量名,.,成员名,(*,共用体指针名,).,成员名,union data,int,i;,char,ch,;,float f;,;,union data a,b,c,*p,d3;,a.i,a.ch,a.f,p-i p-,ch,p-f,(*p).i (*,p).ch,(*p).f,d0.i d0.ch d0.f,共用体变量中起作用的成员是,最后一次存放的成员,例,union,int,i;,char,ch,;,float f;,a;,a=1;(,),不能,在定义共用体变量时,初始化,例,union,int,i;,char,ch,;,float f;,a=1,a,1.5;(,),可以用一个共用体变量为另一个变量赋值,例,float x;,union,int,i;char,ch,;float f;,a,b;,a.i=1;,a.ch,=a;a.f=1.5;,b=a;(,),x=a.f;(,),共用体变量引用,01100001 00110111,低字节,高字节,00110111,01100001,ch0,ch1,main(),union,int_char,int,i;,char ch2;,x;,x.i,=24887;,printf(i,=%on,x.i);,printf(ch0=%o,ch1=%on,ch0=%d,ch1=%,dn,x.ch0,x.ch1,x.ch0,x.ch1);,例 将一个整数按字节输出,区别,:,存储方式不同,struct,node,char ch2;,int,k;,a;,union,node,char ch2;,int,k;,b;,a,ch,k,b,ch,k,变量的各成员同时存在,任一时刻只有一个成员存在,联系,:,两者可相互嵌套,结构体与共用体,结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。,有些,C,变量所占的内存长度等于最长的成员的长度。例如,上面定义的“共用体”变量,a,、,b,、,c,各占,4,个字节,(,因为一个实型变量占,4,个字节,),,而不是各占,2+1+4=7,个字节。,枚 举 类 型,枚举类型是,ANSI C,新标准所增加的。,如果一个变量只有几种可能的值,可以定义为枚举类型。所谓“枚举”是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。声明枚举类型用,enum,开头。例如:,enum,weekdaysun,,,mon,,,tue,,,wed,,,thu,,,fri,,,sat;,声明了一个枚举类型,enum,weekday,,,可以用此类型来定义变量。如,:,enum,weekday,workday,,,week-end,;,workday,和,week-end,被定义为枚举变量,它们的值只能是,sun,到,sat,之一。例如:,workday=,mon,;,week-end=sun,;,是正确的。,当然,也可以直接定义枚举变量,如:,enumsun,,,mon,,,tue,,,wed,,,thu,,,fri,,,sat workday,,,week-end,;,其中,sun,、,mon,、,、,sat,等称为枚举元素或枚举常量。它们是用户定义的标识符。这些标识符并不自动地代表什么含义。例如,不因为写成,sun,,,就自动代表“星期天”。其实不写,sun,而写成,sunday,也可以。用什么标识符代表什么含义,完全由程序员决定,并在程序中作相应处理。,说明,:,(1),在,C,编译中,对枚举元素按常量处理,故称枚举常量。它们不是变量,不能对它们赋值。例如,:sun=0,;,mon,=1,;,是错误的。,(2),枚举元素作为常量,它们是有值的,,C,语言编译按定义时的顺序使它们的值为,0,,,1,,,2,,,。,在上面定义中,,sun,的值为,0,,,mon,的值为,1sat,为,6,。如果有赋值语句,:,workday=,mon,;,workday,变量的值为,1,。这个整数是可以输出的。如,:,printf(%d,,,workday),;,将输出整数,1,。,也可以改变枚举元素的值,在定义时由程序员指定,如,:,enum,weekdaysun=7,,,mon,=1,,,tue,,,wed,,,thu,,,fri,,,satworkday,,,week-end,;,定义,sun,为,7,,,mon,=1,,,以后顺序加,1,,,sat,为,6,。,(3),枚举值可以用来做判断比较。如,if(workday=,mon,),if(workday,sun),枚举值的比较规则是按其在定义时的顺序号比较。如果定义时未人为指定,则第一个枚举元素的值认作,0,。故,mon,大于,sun,,,sat,fri,。,(4),一个整数不能直接赋给一个枚举变量。如:,workday=2,;,是不对的。它们属于不同的类型。应先进行强制类型转换才能赋值。如:,workday=(,enum,weekday)2,;,它相当于将顺序号为,2,的枚举元素赋给,workday,,相当于,workday=,tue,;,甚至可以是表达式。如,:,workday=(,enum,weekday)(5-3),;,功能:用自定义名字为,已有,数据类型命名,类型定义,简单形式:,typedef,type,name,;,例,typedef,int,INTEGER;,类型定义语句关键字,已有数据类型名,用户定义的类型名,例,typedef,float REAL;,类型定义后,与已有类型一样使用,例,INTEGER a,b,c;,REAL f1,f2;,int,a,b,c;,float f1,f2;,说明,:,1.typedef,没有创造,新数据类型,2.typedef,是定义类型,不能定义变量,3.typedef,与,define,不同,define,typedef,预编译时处理,编译时处理,简单字符置换,为已有类型命名,用,typedef,定义类型,按定义变量方法先写出定义体 如,int,i;,将变量名换成新类型名 如,int,INTEGER,;,最前面加,typedef,如,typedef,int,INTEGER,;,用新类型名定义变量 如,INTEGER,i,j;,例 定义数组类型,int,a100;,int,ARRAY100;,typedef,int,ARRAY100;,ARRAY a,b,c;,int,a100,b100,c100;,例 定义指针类型,char *,str,;,char *STRING;,typedef,char *STRING;,STRING p,s10;,char *p;,char *s10;,例 定义函数指针类型,int,(*p)();,int,(*POWER)();,typedef,int,(*POWER)();,POWER p1,p2;,int,(*p1)(),(*p2)();,例 定义结构体类型,struct,date,int,month;,int,day;,int,year;,d;,例 定义结构体类型,struct,date,int,month;,int,day;,int,year;,DATE;,例 定义结构体类型,typedef,struct,date,int,month;,int,day;,int,year;,DATE;,例 定义结构体类型,DATE birthday,*p;,struct,date,int,month;,int,day;,int,year;,birthday,*p;,类型定义可嵌套,例,typedef,struct,club,char name20;,int,size;,int,year;,GROUP;,typedef,GROUP *PG;,PG,pclub,;,GROUP *,pclub,;,struct,club *,pclub,;,GROUP,为结构体类型,PG,为指向,GROUP,的指针类型,typedef,定义类型步骤,
展开阅读全文