《C语言程序设计-结构体和共用体.ppt》由会员分享,可在线阅读,更多相关《C语言程序设计-结构体和共用体.ppt(54页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第十二第十二章章n问题:问题:有时需要将不同类型的数据组合成一个有机的整体,以便于引用。如:如:一个学生有学号/姓名/性别/年龄/地址等属性 int num;char name20;char sex;int age;int char addr30;100101 Li Fun M 18 87.5 Beijing num name sex age score addr12.212.2结构体的定义结构体的定义结构是一种构造数据类型结构是一种构造数据类型(“结构结构”是由若干个成员组是由若干个成员组成的成的),在使用之前必须先定义,然后才能用来定义,在使用之前必须先定义,然后才能用来定义相应的结构体变
2、量、结构体数组、结构体指针变量。相应的结构体变量、结构体数组、结构体指针变量。结构体类型一般形式:结构体类型一般形式:struct 结构体名结构体名 成员列表成员列表 ;其中各成员都应进行类型说明,即其中各成员都应进行类型说明,即类型名类型名 成员名;成员名;例:例:struct student int num;char name20;char sex;int age;float score;char addr30;;结构体变量的定义结构体变量的定义(1)先声明结构类型,再定义结构体变量先声明结构类型,再定义结构体变量例:例:struct student int num;char name20
3、;float score;;struct student stu1,stu2;结构体变量的定义结构体变量的定义(2)在声明结构类型的同时定义结构体变量在声明结构类型的同时定义结构体变量例:例:struct student int num;char name20;float score;stu1,stu2;结构体变量的定义结构体变量的定义(3)直接定义结构体类型变量直接定义结构体类型变量例:例:struct int num;char name20;float score;stu1,stu2;结构体变量的引用结构体变量的引用 一般对结构体变量的使用,包括赋值、输入、一般对结构体变量的使用,包括赋值
4、、输入、输出、运算等都是通过其输出、运算等都是通过其成员成员来实现的。来实现的。结构体变量成员的表示方法:结构体变量成员的表示方法:结构体变量名结构体变量名.成员名成员名例:例:stu1.num(学生学生1的学号的学号)stu1.score(学生学生1的分数的分数)结构体变量的初始化结构体变量的初始化 和其他类型变量一样,定义结构体变量的同时,和其他类型变量一样,定义结构体变量的同时,给它的成员赋初值。给它的成员赋初值。例:例:#include void main()struct student int num;char name20;float score;stu1=1301,”Zhang
5、San”,82.50;printf(“No.%d,Name:%s,Score:%fn”,stu1.num,stu1.name,stu1.score);结构体变量的赋值结构体变量的赋值 通过输入语句或赋值语句,实现对结构体变量的通过输入语句或赋值语句,实现对结构体变量的成员赋值。成员赋值。例:例:#include void main()struct student int num;char name20;float score;stu1;stu1.num=1301;stu1.name=”Zhang San”;scanf(“%f”,&stu1.score);printf(“No.%d,Name:%
6、s,Score:%fn”,stu1.num,stu1.name,stu1.score);嵌套的结构体嵌套的结构体一个结构体的成员又是一个结构体。一个结构体的成员又是一个结构体。例:例:struct date struct student int month;int num;int day;char name20;int year;char sex;int age;struct date birthday;char addr30;;birthdaynum name sex age addr month day year12.312.3结构体数组结构体数组 结构体数组的每一个元素都是具有相同结构类
7、型的结构体数组的每一个元素都是具有相同结构类型的结构体变量。结构体变量。例:例:struct student int num;char name20;float score;stu3;其中,定义了一个结构体数组其中,定义了一个结构体数组stu,共有,共有3个元素,个元素,每个元素都具有每个元素都具有struct student的结构形式。的结构形式。结构体数组的初始化赋值结构体数组的初始化赋值例:例:struct student int num;char name20;float score;stu3=1301,”Zhang San”,57,1302,“Li Si”,82.50,1303,“W
8、ang Wu”,69;当对全部元素进行初始化赋值时,也可以不给出长度。当对全部元素进行初始化赋值时,也可以不给出长度。12.412.4结构体指针变量结构体指针变量指向结构体变量的指针指向结构体变量的指针一般形式为:一般形式为:struct 结构名结构名 *结构体指针变量名;结构体指针变量名;例:例:struct student int num;char name20;float score;;struct student*pstu;其中定义了一个指向其中定义了一个指向student的指针变量的指针变量pstu。指向结构体变量的指针变量指向结构体变量的指针变量用结构体指针变量,访问结构体变量的各
9、个成员用结构体指针变量,访问结构体变量的各个成员,一般形式为:一般形式为:(*结构体指针变量结构体指针变量).成员名;成员名;或或 结构体指针变量结构体指针变量-成员名;成员名;例:例:(*pstu).num 或或 pstu-num 例:例:#include void main()struct student int num;char name20;float score;stu1=1301,”Zhang San”,82.50,*pstu;pstu=&stu1;printf(“No.%d,Name:%s,Score:%fn”,stu1.num,stu1.name,stu1.score);pri
10、ntf(“No.%d,Name:%s,Score:%fn”,(*pstu).num,(*pstu).name,(*pstu).score);printf(“No.%d,Name:%s,Score:%fn”,pstu-num,pstu-name,pstu-score);指向结构体数组的指针变量指向结构体数组的指针变量结构体指针变量可指向一个结构体数组,其指针变结构体指针变量可指向一个结构体数组,其指针变量的值是整个结构体数组的首地址。量的值是整个结构体数组的首地址。例:例:设设ps为指向结构体数组的指针变量,为指向结构体数组的指针变量,则则ps指向该结构体数组的指向该结构体数组的0号元素;号元素
11、;ps+1指向该结指向该结构体数组的构体数组的1号元素。号元素。例:例:#include void main()struct student int num;char name20;float score;stu3=1301,”Zhang San”,57,1302,“Li Si”,82.50,1303,“Wang Wu”,69;struct student*ps=stu;ps+;printf(“No.%d,Name:%s,Score:%fn”,ps-num,ps-name,ps-score);12.512.5向函数传递结构体向函数传递结构体(3(3种方式种方式)1.用结构体的单个成员作为函数参
12、数,向函数传递结用结构体的单个成员作为函数参数,向函数传递结 构体的构体的单个成员单个成员。这与普通类型的变量作函数参数没什么区别,都是这与普通类型的变量作函数参数没什么区别,都是传值调用传值调用,在函数内部对其进行操作,不会引起实,在函数内部对其进行操作,不会引起实参结构体成员值的变化。参结构体成员值的变化。2.用结构体变量作为函数参数,向函数传递结构体的用结构体变量作为函数参数,向函数传递结构体的 完整结构完整结构。这种传递,是将整个结构体成员的内容复制给被调这种传递,是将整个结构体成员的内容复制给被调函数。这种方式是函数。这种方式是传值调用传值调用,在函数内部对其进行,在函数内部对其进行
13、操作,不会引起实参结构体成员值的变化。操作,不会引起实参结构体成员值的变化。3.用结构体指针或结构体数组作为函数参数,向函数用结构体指针或结构体数组作为函数参数,向函数 传递结构体的传递结构体的地址地址。由于是由于是传地址调用传地址调用,在函数内部对其进行操作,将,在函数内部对其进行操作,将影响实参结构体成员值的变化。影响实参结构体成员值的变化。12.612.6共用体共用体 共用体共用体(也称为联合也称为联合)也是一种也是一种构造的数据类型构造的数据类型。共用体是将不同类型的数据组织在一起共同占用同共用体是将不同类型的数据组织在一起共同占用同一段内存的一种构造数据类型。一段内存的一种构造数据类
14、型。例如,在校学生和教师都填写以下表格:例如,在校学生和教师都填写以下表格:姓名姓名 年龄年龄 职业职业 单位单位其中,职业分两类:教师和学生;其中,职业分两类:教师和学生;而而单位单位一栏里,学生填写班级编号一栏里,学生填写班级编号(整型类型整型类型),教师填写某系某教研室教师填写某系某教研室(整型类型整型类型)。共用体的定义共用体的定义共用体与结构体的类型声明方法类似。共用体与结构体的类型声明方法类似。共用体的关键字为共用体的关键字为union。一般形式:一般形式:union 共用体名共用体名 成员列表成员列表 ;其中各成员都应进行类型说明,即其中各成员都应进行类型说明,即类型名类型名 成
15、员名;成员名;union department int class;char office20;;共用体变量的说明共用体变量的说明(3(3种形式种形式)(1)union department 先定义再说明;先定义再说明;int class;char office20;;union department a,b;(2)union department 定义同时说明;定义同时说明;int class;char office20;a,b;(3)union 直接说明。直接说明。int class;char office20;a,b;共用体与结构体的区别共用体与结构体的区别 (1)结构体变量所占内存长度
16、是各成员占的内存长结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有自己的内存单元。度之和。每个成员分别占有自己的内存单元。(2)共用体变量所占内存长度是共用体变量所占内存长度是最长最长的成员的长度。的成员的长度。即共用体变量的地址和它的各成员的地址是同一地即共用体变量的地址和它的各成员的地址是同一地址。址。共用体变量的引用共用体变量的引用 对共用体变量的使用,包括赋值、使用只能是对对共用体变量的使用,包括赋值、使用只能是对变量的变量的成员成员进行。进行。共用体变量成员的表示方法:共用体变量成员的表示方法:共用体变量名共用体变量名.成员名成员名例:例:a.class a.offi
17、ce 不允许对共用体变量作初始化赋值,赋值只能在不允许对共用体变量作初始化赋值,赋值只能在程序中进行。程序中进行。#include#define PN 3void main()struct char name10;int age;char job;union int class;char office10;units;bodyPN;例:设有一个教师和学生通用的表格,有姓名、年龄、职例:设有一个教师和学生通用的表格,有姓名、年龄、职业、单位业、单位4 4项。在职业项中,用项。在职业项中,用ss表示学生,用表示学生,用tt表示教师。编程输入人员数据,再以表格输出。表示教师。编程输入人员数据,再以表
18、格输出。int n,i;for(i=0;iPN;i+)printf(“input name,age,job and departmentn”);scanf(“%s%d%c”,bodyi.name,&bodyi.age,&bodyi.job);if(bodyi.job=s)scanf(“%d”,&bodyi.units.class);else scanf(“%s”,bodyi.units.office);printf(“nametagetjobtclass/officen”);for(i=0;iPN;i+)if(bodyi.job=s)printf(“%st%dt%3ct%dn”,bodyi.n
19、ame,bodyi.age,bodyi.job,bodyi.units.class);else printf(“%st%dt%3ct%sn”,bodyi.name,bodyi.age,bodyi.job,bodyi.units.office);12.712.7枚举数据类型枚举数据类型 当某些变量仅由有限个数据值组成时,通常用枚举当某些变量仅由有限个数据值组成时,通常用枚举类型来表示。类型来表示。所谓枚举是指将变量的值一一列举出来,变量的值所谓枚举是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。如一周只有只限于列举出来的值的范围内。如一周只有7天,一天,一年只有年只有12个月等等
20、。个月等等。注意:枚举类型是一种注意:枚举类型是一种基本数据类型基本数据类型,而不是一种,而不是一种构造类型。关键字为构造类型。关键字为enum。一般形式:一般形式:enum 枚举名枚举名 枚举值表枚举值表 ;在枚举值表中应罗列出所有可用值,这些值称之为枚在枚举值表中应罗列出所有可用值,这些值称之为枚举元素。举元素。例:例:enum weekday sun,mon,tue,wed,thu,fri,sat;声明了一个枚举类型声明了一个枚举类型enum weekday,可以用此类型来,可以用此类型来定义变量,该变量只能取定义变量,该变量只能取7天中的某一天。天中的某一天。枚举变量的说明枚举变量的说
21、明(3(3种形式种形式)(1)enum weekday 先定义再说明;先定义再说明;sun,mon,tue,wed,thu,fri,sat;enum weekday a,b,c;(2)enum weekday 定义同时说明;定义同时说明;sun,mon,tue,wed,thu,fri,sata,b,c;(3)enum 直接说明。直接说明。sun,mon,tue,wed,thu,fri,sata,b,c;枚举变量的赋值和使用枚举变量的赋值和使用(1)在在C编译中,对编译中,对枚举元素按常量处理枚举元素按常量处理,故称枚举,故称枚举常量。它们不是变量,不能对它们赋值。常量。它们不是变量,不能对它们
22、赋值。例:例:sun=5;mon=2;sun=mon;是错误的。是错误的。枚举变量的赋值和使用枚举变量的赋值和使用(2)枚举元素本身由系统定义为有序号的数值,枚举元素本身由系统定义为有序号的数值,从从0开始顺序定义为开始顺序定义为0,1,2,例如在例如在weekday中,中,sun值为值为0,mon值为值为1,sat值值为为6。这个序号值是可以输出的。这个序号值是可以输出的。例:例:#include void main()enum weekday sun,mon,tue,wed,thu,fri,sata,b,c;a=sun;b=mon;c=tue;printf(“%d,%d,%d”a,b,c)
23、;运行结果:运行结果:0,1,2枚举变量的赋值和使用枚举变量的赋值和使用(3)只能把枚举值赋予枚举变量,只能把枚举值赋予枚举变量,不能把元素的数值不能把元素的数值直接赋予枚举变量。直接赋予枚举变量。例:例:a=sun;b=mon;是正确的。是正确的。a=0;b=1;是错误的。是错误的。如果一定要把数值赋予枚举变量,则必须用强制类如果一定要把数值赋予枚举变量,则必须用强制类型转换,则应型转换,则应b=(enum weekday)1;其意义是将顺序其意义是将顺序号为号为1的枚举元素赋予枚举变量的枚举元素赋予枚举变量b,等价于,等价于b=mon;(4)枚举元素不是字符常量,也不是字符串常量,使枚举元
24、素不是字符常量,也不是字符串常量,使用时无须加单、双引号。用时无须加单、双引号。用用typedeftypedef定义数据类型定义数据类型 C语言允许用户用语言允许用户用typedef来自定义类型说明符。来自定义类型说明符。例:例:typedef int INTEDER;(指定用指定用INTEDER来代表来代表int类型类型)因此,因此,INTEDER a,b;等价于等价于int a,b;typedef定义的一般形式为:定义的一般形式为:typedef 原类型名原类型名 新类型名;新类型名;用用typedeftypedef定义数据类型定义数据类型例:例:typedef char NAME20;其
25、中,其中,NAME是字符数组类型,长度为是字符数组类型,长度为20。然后可以。然后可以用用NAME说明变量说明变量:NAME s1,s2;等价于等价于char s120,s220;用用typedeftypedef定义数据类型定义数据类型例:例:typedef struct student int num;y char name20;float score;STU;STU表示表示struct student的结构类型,然后可以用的结构类型,然后可以用STU来说明结构变量:来说明结构变量:STU stu1,stu2;12.812.8动态数据结构动态数据结构单单向链表向链表一、问题一、问题1.用数组
26、的方式存储学生的数据,需要预先确定学生用数组的方式存储学生的数据,需要预先确定学生的人数,并且数组占用的是一块连续的内存区域。的人数,并且数组占用的是一块连续的内存区域。2.用动态存储的方法:每次分配一块空间存放一个学用动态存储的方法:每次分配一块空间存放一个学生的数据,称之为一个结点。有多少学生就申请分配生的数据,称之为一个结点。有多少学生就申请分配多少块空间,也就建立多少个结点。当学生留级、退多少块空间,也就建立多少个结点。当学生留级、退学后,可删除该结点,并释放该结点占用的空间。使学后,可删除该结点,并释放该结点占用的空间。使用动态分配,每个结点之间的内存空间可以是不连续用动态分配,每个
27、结点之间的内存空间可以是不连续的的(结点内是连续的结点内是连续的)。结点之间的联系可以用指针实。结点之间的联系可以用指针实现。现。二、链表的定义二、链表的定义 用一个指针变量用一个指针变量head指向第指向第1个结点的首地址,以个结点的首地址,以后每个结点都分为两个域,一个是后每个结点都分为两个域,一个是数据域数据域,存放各种,存放各种实际的数据;另一个域是实际的数据;另一个域是指针域指针域,存放下一个结点的,存放下一个结点的首地址。最后一个结点因无后续结点连接,其指针域首地址。最后一个结点因无后续结点连接,其指针域可赋予可赋予NULL。这种连接方式,在数据结构中称为这种连接方式,在数据结构中
28、称为链表链表。链表中每一个结点都是同一种结构类型。链表中每一个结点都是同一种结构类型。例:一个存放学生的学号和成绩的结点为:例:一个存放学生的学号和成绩的结点为:struct student1 int num;float score;struct student1*next;前两个成员项组成数据域,后一个成员项前两个成员项组成数据域,后一个成员项next构成指构成指针域,它是一个指向同类型结构的指针变量。针域,它是一个指向同类型结构的指针变量。#include#define NULL 0struct student long num;float score;struct student*nex
29、t;void main()struct student a,b,c,*head,*p;a.num=00101;a.score=89.5;b.num=00103;b.score=90;c.num=00107;c.score=85;例:建立一个简单链表,由例:建立一个简单链表,由3 3个学生数据的结点组成。输个学生数据的结点组成。输出各结点中的数据。出各结点中的数据。head=&a;a.next=&b;b.next=&c;c.next=NULL;p=head;doprintf(“%ld%5.1fn”,p-num,p-score);p=p-next;while(p!=NULL);三、单向链表的建立三
30、、单向链表的建立 可以采取向链表中添加结点的方式来建立一个单向可以采取向链表中添加结点的方式来建立一个单向链表。链表。为了向链表中添加一个新结点,首先要为新建结点为了向链表中添加一个新结点,首先要为新建结点动态申请内存空间动态申请内存空间,让指针变量,让指针变量p指向这个新建结点指向这个新建结点,然后将新建结点添加到链表中。然后将新建结点添加到链表中。需要考虑以下两种情况:需要考虑以下两种情况:(1)若原链表为空表若原链表为空表(将新建结点置为头结点将新建结点置为头结点);(2)若原链表为非空若原链表为非空(将新建结点添加到表尾将新建结点添加到表尾)。四、单向链表的删除操作四、单向链表的删除操
31、作 链表的删除操作就是将一个待删除结点从链表中断链表的删除操作就是将一个待删除结点从链表中断开,不再与链表的其他结点开,不再与链表的其他结点 有任何联系。有任何联系。需要考虑如下四种情况:需要考虑如下四种情况:(1)若原链表为空表若原链表为空表,则无需删除结点,直接退出程序,则无需删除结点,直接退出程序(2)若找到的待删除结点若找到的待删除结点p是头结点是头结点,则将,则将head指向当指向当前结点的下一个结点,即可删除当前结点。前结点的下一个结点,即可删除当前结点。(3)若找到的待删除结点若找到的待删除结点p不是头结点不是头结点,则将前一结点,则将前一结点的指针域指向当前结点的下一个结点,即
32、可删除当前的指针域指向当前结点的下一个结点,即可删除当前结点。结点。(4)若已搜索到表尾若已搜索到表尾,仍未找到待删除结点,则显示,仍未找到待删除结点,则显示“未找到未找到”。注意:结点被删除后,只表示将它从链表中断开,它注意:结点被删除后,只表示将它从链表中断开,它仍占用着内存,必须释放其所占的内存,否则将出现仍占用着内存,必须释放其所占的内存,否则将出现内存泄露。用内存泄露。用“free(p);”即可,其中即可,其中p是待删除结是待删除结点。点。五、单向链表的插入操作五、单向链表的插入操作 向链表中插入一个新结点时,首先要新建一个结点,向链表中插入一个新结点时,首先要新建一个结点,将其指针
33、域赋值为空指针,然后在链表中寻找适当的将其指针域赋值为空指针,然后在链表中寻找适当的位置执行结点插入操作。位置执行结点插入操作。需要考虑如下四种情况:需要考虑如下四种情况:(1)若原链表为空表若原链表为空表,则将新结点,则将新结点p作为头结点,让作为头结点,让head指向新结点。指向新结点。(2)若原链表为非空若原链表为非空。若在头结点前插入新结点,则新。若在头结点前插入新结点,则新结点的指针域指向原链表的头结点,且让结点的指针域指向原链表的头结点,且让head指向新指向新结点。结点。(3)若在链表中间插入新结点若在链表中间插入新结点,则将新结点的指针域指,则将新结点的指针域指向下一结点,且让前一结点的指针域指向新结点。向下一结点,且让前一结点的指针域指向新结点。(4)若在表尾插入新结点若在表尾插入新结点,则将末结点的指针域指向新,则将末结点的指针域指向新结点。结点。