第11章结构体与共用体.ppt

上传人:本田雅阁 文档编号:2250907 上传时间:2019-03-11 格式:PPT 页数:59 大小:440.51KB
返回 下载 相关 举报
第11章结构体与共用体.ppt_第1页
第1页 / 共59页
第11章结构体与共用体.ppt_第2页
第2页 / 共59页
第11章结构体与共用体.ppt_第3页
第3页 / 共59页
亲,该文档总共59页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《第11章结构体与共用体.ppt》由会员分享,可在线阅读,更多相关《第11章结构体与共用体.ppt(59页珍藏版)》请在三一文库上搜索。

1、2019/3/11,1,第十一章 结构体与共用体,结构体的定义 结构体的初始化 访问结构体成员 结构体和函数,构造的数据类型,2019/3/11,2,2、定义结构的同时定义结构变量: struct student studend1, student2;(变量表列),3、直接定义结构变量: struct studend1, student2;,注意 (1)类型与变量是不同的概念; (2)对结构中的成员可以单独使用; (3)成员可以是结构变量;,2019/3/11,3,11.1 概述,结构:一种构造类型数据 (一条记录) 不同类型的数据组合成一个整体,以便引用,为什么引入结构型数据?,结构的定义:

2、struct student int num; char name20; char sex; int age; float score; char addr30; ;,struct student stu;,2019/3/11,4,11.2 定义结构体类型变量的方法,结构体类型的形式: struct 结构体名 类型名1 成员名1; 类型名2 成员名2; :;,这个结构就是一种数据类型 结构体类型许多种,关键字,2019/3/11,5,成员可以是结构变量,struct date int month; int day; int year; ; struct student int num; cha

3、r name20; struct date birthday; char addr30 ; student1,student2;,num,name,birthday,month,day,year,2019/3/11,6,11.3 结构体变量的引用,结构体变量不能整体引用,只能引用其成员,1) 结构体变量中成员的引用方式 结构体变量名.成员名 student1.num (“.”是成员运算符,优先级最高),3)成员可以像普通变量一样进行各种运算. student2.score= student1.score; student1.age+;,例如:student1.num = 10010;,2019

4、/3/11,7,11.4 结构体变量的初始化,在定义时初始化(eg11.1),struct student long int num; char name20; char sex; char addr20; a=89031,“Li Lin“,M,“123 Beijing Road“;,仅在定义时可整体初始化,a.num=89031; a.sex=M;,a;,name如何赋初值?,2019/3/11,8,11.5 结构体数组,1 )定义结构体数组 将结构体定义中的变量定义为数组即可,struct student int num; char name20; char sex; int age; f

5、loat score; char addr30; ; struct student stu3;,2019/3/11,9,2 )结构体数组的初始化,struct student stu3= 10101,“LiLin“,M,18,87.5,“123 Beijing“, 10102,“zhangfun“,M,19,99,“123 Shanghai“, 10104,“Wang Min“,F,20,78.5,“123 Nanjing“;,struct student int num; char name20; char sex; int age; float score; char addr30; ;,

6、2019/3/11,10,3)结构体数组的应用举例 例 11.2 对候选人得票的统计程序。有3个候选人,每次输入一个得票的候选人的名字,要求最后输出各人的得票结果。,2019/3/11,11,#include #include struct person char name20; int count; leader3=“Li“,0,“Zhang“,0,“Fun“,0;,void main() int i,j; char leader_name20; for(i=1;i=5;i+) scanf(“%s“,leader_name); for(j=0;j3;j+) if(strcmp(leader_

7、name,leaderj.name)=0) leaderj.count+; printf(“n“); for(i=0;i3;i+) printf(“%5s:%dn“,leaderi.name,leaderi.count);,2019/3/11,12,11.6 指向结构体类型数据的指针,结构体变量的指针是该变量所占内存区域的起始地址。,1) 指向结构体变量的指针, struct student stu1; struct student *stu1Ptr; stu1Ptr= ,(1)结构体变量.成员名 (2)(*p).成员名 (3) p- .成员名,2019/3/11,13,#include vo

8、id main() struct student long int num; char name20; char sex; float score; ;/ stu_1 =89031,“Li Lin“,M,89.5; struct student stu_1; struct student *p; p=,eg11.3,2019/3/11,14,2)指向结构体数组的指针,例 11.4,#include struct student int num; char name20; char sex; int age; stu3=10101,“Li Lin“,M,18, 10102,“Zhang Fun“

9、,M,19, 10104,“Wang Min“,F,20; void main() struct student *p; for(p=stu;pnum,p-name,p-sex,p-age); ,2019/3/11,15,3)用结构体变量和指向结构体的指针作函数参数,把结构传递给函数有三种方式: 单个成员 整个结构 指向结构的指针,1、成员传递:用结构变量成员作为实参(值传递) 例如:对于上面定义的结构变量stu_1有四个成员。其中任何一个都可以做实参。 void main() prin(stu_1.num); : ,2019/3/11,16,2、结构传递(全体传递,多值传递): 用结构变量作

10、实参 将结构变量所占的内存单元内容全部顺序传递给形参(值传递),由于采用值传递内存开销大、在被调函数中改变的形参值不能返回主调用函数,因此在使用上很不方便。 eg11.5.c,3、传引用调用(地址传递): 定义结构指针变量并以此指针作为实参 从而完成将结构变量的指针传给函数。主调函数和被调函 数共用一段内存空间。 eg11.6.c,传递数组(自动实现传引用调用)和传递结构不同; 用指针作函数参数能提高程序运行效率,有时节约内存。,2019/3/11,17,11.8 共用体 构造数据类型,也叫联合体 用途:使几个不同类型的变量共占一段内存(相互覆盖) 共用体类型定义 定义形式:,union 共用

11、体名 类型标识符 成员名; 类型标识符 成员名; . ;,例 union data int i; char ch; float f; ;,类型定义不分配内存,2019/3/11,18,形式一: 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;,共用体变量的定义,共用体变量定义分配内存, 长度=最长成员所占字节数,共用体变量任何时刻 只有一个成员存

12、在,2019/3/11,19,共用体变量引用 引用方式:,例 a.i=1; a.ch=a; a.f=1.5; printf(“%d”,a.i); (编译通过,运行结果不对),引用规则 不能引用共用体变量,只能引用其成员,共用体变量中起作用的成员是最后一次存放的成员,例 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;

13、a,b; a.i=1; a.ch=a; a.f=1.5; b=a; () x=a.f; (),2019/3/11,20,结构体与共用体 区别: 存储方式不同,联系: 两者可相互嵌套,2019/3/11,21,例 结构体中嵌套共用体 eg11.12,struct int num; char name10; char sex; char job; union int class; char position10; category; person2;,2019/3/11,22,11.9 枚举类型,如果一个变量只有几种可能的值,可定义为枚举类型。 一、枚举类型定义 定义的一般形式为: enum 枚举

14、名 枚举值表 ; 在枚举值表中应罗列出所有可用值,这些值也称为枚举元素,被说明为该“枚举”类型的变量取值不能超过定义的范围 例如: enum weekday sun,mon,tue,wed,thu,fri,sat ;,2019/3/11,23,枚举变量的定义同结构体相同,有三种形式 enum weekday sun,mou,tue,wed,thu,fri,sat ; enum weekday a,b,c; 或者: enum weekday sun,mou,tue,wed,thu,fri,sat a,b,c; 或者: enum sun,mou,tue,wed,thu,fri,sat a,b,c;

15、,2019/3/11,24,二、赋值和使用 1.枚举值(枚举元素)是常量,不能在程序中用赋值语句再对它赋值 例如: sun=5; 错误 mon=2; 错误,2019/3/11,25,2.枚举元素本身由系统定义了一个表示序号的数值,从0开始顺序定义为0,1,2 例如: sun的值是0,mon的值是1,2019/3/11,26,3.枚举值可以用来作判断比较 按其在定义时的顺序号比较 例如: enum weekday sun,mon,tue,wed,thu,fri,sat a; sunmon if( asun ),2019/3/11,27,4.整数不能直接赋给枚举变量 例如: enum weekda

16、y sun,mou,tue,wed,thu,fri,sat a; a=2; 错误 在赋值前应进行强制类型转换 a=(enum weekday)2; a=tue;,2019/3/11,28,11.10 用typedef定义类型 功能:用自定义名字为已有数据类型命名 类型定义简单形式: typedef type name;,例 typedef int INTEGER;,类型定义语句关键字,已有数据类型名,用户定义的类型名,例 typedef float REAL;,类型定义后,与已有类型一样使用,例 INTEGER a,b,c; REAL f1,f2;,说明: 1.typedef 没有创造新数据类

17、型 2.typedef 是定义类型,不能定义变量 3.typedef 与 define 不同,define typedef 预编译时处理 编译时处理 简单字符置换 为已有类型命名,2019/3/11,29,用typedef定义结构体: typedef struct int year; int month; int day; DATE; 声明新类型名DATE代表指定的结构体类型 DATE birthday;,2019/3/11,30,typedef定义的一般形式为: typedef 原类型名 新类型名 新类型名一般用大写表示,2019/3/11,31,typedef定义类型步骤 按定义变量方法先

18、写出定义体 如 int i; 将变量名换成新类型名 如 int INTEGER; 最前面加typedef 如 typedef int INTEGER; 用新类型名定义变量 如 INTEGER i,j;,2019/3/11,32,作业 11.3 11.4 说明:这两道合成一道题完成,#define N 5 struct student char num6; char name8; int score3; stuN;,2019/3/11,33,11.7 结构数据的动态存储分配 语言不允许动态数组。但在实际编程中,往往会发生这种情况,即所需的内存空间的大小取决于实际输入的数据,而无法预先确定。对于这

19、类问题,用数组的办法很难解决。语言提供了一些内存管理函数,用于动态地分配内存空间,或把不再使用的空间释放。 常用的内存管理函数有以下三个: 1、分配内存空间函数malloc(P296) 调用形式:(类型说明符*)malloc(unsigned int size) 功能:在内存的动态存储区中分配一片长度为size字节的连续区域。函数的返回值为该区域的首地址。 “类型说明符”表示把该区域用于何种数据类型。 (类型说明符*)表示把返回值强制转换为该类型指针。 size是一个无符号数。如果此函数未能成功执行,返回NULL.,2019/3/11,34,例如:char *pc; pc=(char *)ma

20、lloc(10); 表示分配10个字节的内存空间,强制转换为指向字符的指针,并赋给指针变量pc。 2、分配内存空间函数 calloc 调用形式:(类型说明符*)calloc(n,size) 功能:在内存动态存储区中分配n块长度为size字节的连续区域。函数的返回值为该区域的首地址。 calloc函数与malloc 函数的区别仅在于一次可以分配n块区域。,2019/3/11,35,例如: struct student *ps; ps=(struct student *)calloc(2,sizeof(struct student); 其中的sizeof(struct student)是求stud

21、ent的结构长度。因此该语句的意思是:按student的长度分配2块连续区域,强制转换为指向结构student的指针,并把其首地址赋给指针变量ps。 3、释放内存空间函数free 调用形式:free(ptr); 功能:释放ptr所指向的一块内存空间,其中ptr是一个任意类型的指针变量,它指向被释放区域的首地址。被释放区应是由malloc或calloc函数所分配的区域。,2019/3/11,36,【例】分配一块区域,输入一个学生数据。 程序如下: void main() struct student int num; char *name; char sex; float score; *ps;

22、,2019/3/11,37,ps=(struct student *)malloc(sizeof(struct student); ps-num=202; ps-name=“Zhang San“; ps-sex=M; ps-score=86.5; printf(“Number=%dnName=%sn“,ps-num,ps-name); printf(“Sex=%cnScore=%fn“,ps-sex,ps-score); free(ps); 整个程序包含了申请内存空间、使用内存空间、释放内存空间三个步骤,实现存储空间的动态分配。,2019/3/11,38,链表及其基本操作 在上例中采用了动态分

23、配的办法为一个结构分配内存空间。每一次分配一块空间可用来存放一个学生的数据,我们可称之为一个结点。有多少个学生就应该申请分配多少块内存空间,也就是说要建立多少个结点。当然用结构数组也可以完成上述工作。如果事先不知道学生人数,也就无法确定数组大小。而且当学生留级、退学之后也不能把该元素占用的空间从数组中释放出来。,2019/3/11,39,用动态存储的方法可以很好地解决这些问题。有一个学生就分配一个结点,无须预先确定学生的准确人数,某学生退学,可删去该结点,并释放该结点占用的存储空间。从而节约了宝贵的内存资源。另一方面,用数组的方法必须占用一块连续的内存区域。而使用动态分配时,每个结点之间可以是

24、不连续的(结点内是连续的)。结点之间的联系可以用指针实现。即在结点结构中定义一个成员项用来存放下一结点的首地址,这个用于存放地址的成员,常把它称为指针域。 可在第一个结点的指针域内存入第二个结点的首地址,在第二个结点的指针域内又存放第三个结点的首地址,如此串连下去直到最后一个结点。最后一个结点因无后续结点连接,其指针域可赋为NULL。这样一种连接方式,在数据结构中称为“链表”。,2019/3/11,40,下图为一简单链表的示意图。 图8-1 单链表示意图 图中,head为“头指针”变量,它存放第一个结点的首地址,它没有数据,只是一个指针变量。以下的每个结点都分为两个域,一个是数据域,存放各种实

25、际的数据,如学号num,和成绩score等。另一个域为指针域,存放下一结点的首地址。链表中的每一个结点都是同一种结构类型。,2019/3/11,41,上图中的结点可以定义为以下结构: struct student int num; float score; struct student *next; 前两个成员项组成数据域,后一个成员项next构成指针域,它是一个指向student结构类型的指针变量。,2019/3/11,42,对链表的主要操作有以下几种: (1)建立链表; (2)链表的遍历; (3)插入一个结点; (4)删除一个结点; 下面通过例题来说明这些操作。,2019/3/11,43,

26、1、建立链表(P297 例11.8) 在本节算法和例题中假设n是已定义的全局变量,表示结点个数,其初值为零。建立链表的算法如下(图11-13,图11-14,15,16 ) (1)开辟一个新结点,并使p1、p2指向该结点 (2)读入一个学生数据给p1所指向的结点 (3)head=NULL,n=0 (4)当读入的p1-num不是0时做循环: n+ 如果n=1则head=p1否则p2-next=p1 p2=p1 再开辟一个新结点,并使p1指向它该结点 读入一个学生数据给p1所指向的结点 (5)将表尾结点的指针域置NULL,2019/3/11,44,【例11.8】写一个函数建立一个单向链表,当输入数据

27、为零时表示完成链表的建立。 根据建立链表的算法,函数设计如下: #define NULL 0 #define LEN sizeof(struct student) #include #include struct student long num; float score; struct student *next; ; int n; struct student *creat() struct student *head,*p1,*p2; n=0;,2019/3/11,45,p1=p2=(struct student *) malloc(LEN); /*建立新结点*/ scanf(“%ld,

28、%f“, ,2019/3/11,46,2、链表的遍历 链表的遍历就是从头结点开始依次访问链表的每个结点。链表的查找与输出都是遍历的例子。链表输出的算法如下: (1)p=head (2)如果p指向的不是尾结点,则 输出p所指向的结点 p移动,指向下一个结点 直到p指向尾结点为止,2019/3/11,47,【例11.9】写一个函数用来输出一个已知的单向链表。 设结构student的定义与例11.8相同,根据链表输出的算法,函数设计如下: void print(struct student *head ) struct student *p; printf(“nNow These%d records

29、 are:n“,n); p=head; if(head!=NULL) do printf(“%ld%5.1fn“,p-num,p-score); p=p-next; while (p!=NULL); ,2019/3/11,48,3、在链表中插入一个结点 设链表已按学号升序排序。如图8-2所示,要在链表中插入结点,首先确定插入位置,将插入位置的前一个结点的指针域指向插入结点的首地址,将插入结点的指针域设置为与插入位置的前一结点原来的指针域相同即可。若要插入结点的首地址为stud,则在链表中插入一个结点的算法如下:,图8-2 插入结点示意图,2019/3/11,49,(1)p1=head,p0=s

30、tud (2)如果链表是空表,则将p0所指向的结点直接插入到表头,结束 (3)当p0-nump1-num且p1不指向表尾时 p2=p1 p1=p1-next (循环结束时p1指向插入位置) (4)如果p0-nump1-num,则 如果p1指向表头,则head=p0, 否则p2-next=p0 p0-next=p1 否则p1-next=p0 p0-next=NULL (插到表尾后),2019/3/11,50,【例11.11】写一个函数用来在一个已排序的链表中插入一个结点。设结构student的定义与前相同,根据在链表中插入一个结点算法,函数设计如下: struct student * inser

31、t(struct student * head, struct student * stud) struct student *p0,*p1,*p2; p1=head; p0=stud;,2019/3/11,51,if(head=NULL) /*原来的链表为空表*/ head=p0;p0-next=NULL; /*结点直接作为表头*/ else while(p0-nump1-num) /*循环结束时p1指向插入位置(b) */,2019/3/11,52,if(p0-numnum) if(head=p1) head=p0; /*结点插入到表头(d) */ else p2-next=p0; /*结

32、点插入到p1前(c) */ p0-next=p1; else p1-next=p0;p0-next=NULL; /*结点插入到表尾(e)*/ n=n+1; return(head); ,2019/3/11,53,4、在链表中删除一个结点 如图8-3所示,要在链表中删除结点,在确定要删除的结点后,将其前一个结点的指针域用被删除结点的指针域代替即可。在链表中删除一个结点的算法如下:,图8-3 删除结点示意图,2019/3/11,54,(1)如果链表是一个空表,则输出信息,转(5) (2)p1=head (3)nump1-num以及p1指向的不是尾结点时 p2=p1 p1=p1-next (找出要删

33、除的结点p1) (4)如果p1是要删除的结点,则 如果p1是表头则head=p1-next 否则p2-next=p1-next 否则输出“找不到”的信息 (5)结束,2019/3/11,55,【例8.12】写一个函数用来在给定链表中删除一个结点。 设结构student的定义与前相同,根据在链表中删除一个结点算法, 函数设计如下: struct student * del(struct student * head, int num) struct student *p1,*p2; if (head=NULL) printf(“nlist null!n“); else while(num!=p1

34、-num /*找出要删除的结点p1 (b)*/,2019/3/11,56,if(num=p1-num) /*找到要删除的结点*/ /*删除的是头结点(c)*/ if(p1=head) head=p1-next; else p2-next=p1-next; /*删除的是普通结点(d)*/ printf(“delete:%ldn“,num); free(p1); n=n-1; else printf(“%ld not been found!n“,num); /*找不到要删除的结点*/ / end else return(head); ,2019/3/11,57,使用上述函数的主调函数可以设计为:

35、#define NULL 0 #define LEN sizeof(struct student) #include “stdlib.h” struct student long num; float score; struct student *next; ; int n; void main() struct studend *head,*stu; long del_num; float x;,2019/3/11,58,printf(“input records:n“); head=creat(); print(head); printf(“ninput the deleted number:“); scanf(“%ld“,2019/3/11,59,stu=(struct student *)malloc(LEN); scanf(“%ld,%f“, ,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1