第8章结构体与共用体.doc

上传人:scccc 文档编号:14408126 上传时间:2022-02-05 格式:DOC 页数:25 大小:247KB
返回 下载 相关 举报
第8章结构体与共用体.doc_第1页
第1页 / 共25页
第8章结构体与共用体.doc_第2页
第2页 / 共25页
第8章结构体与共用体.doc_第3页
第3页 / 共25页
亲,该文档总共25页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

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

1、第8章 结构体与共用体在日常生活中,我们常会遇到一些需要填写的登记表,如住宿表、成绩表、通讯地址等。在这些表中,填写的数据是不能用同一种数据类型描述的,在住宿表中我们通常会登记上姓 名、性别、身份证号码等项目;在通讯地址表中我们会写下姓名、邮编、邮箱地址、电话号 码、E-mail等项目。这些表中集合了各种数据,无法用前面学过的任一种数据类型完全描述,因此C引入一种能集中不同数据类型于一体的数据类型一一结构体类型。C语言的结构体类型相当于其它高级语言的“记录”。结构体类型的变量可以拥有不同数据类型的成员,是不同数据类型成员的集合。结构在C语言中相当重要,与指针同属C语言的精华。8.1 结构体类型

2、的定义结构体类型的定义是根据实际相关数据的具体情况,由用户定义的一种类型,定义结构 体类型的一般形式为:struct 结构体名类型标识符成员1;类型标识符成员2;类型标识符成员n;;各个成员可以是基本类型,也可以是结构类型,有的结构可能包含很多成员,有些成员 本身也可能很复杂,这就允许用户能定义复杂事务的数学模型。例如:要设计一个学生的情况登记表, 要求有学号(number)、姓名(name)、性别(sex)、 年龄(age)、家庭地址(address)和三门课成绩(achie)。三门课是语文(chinese)、数学(math) 和英语(english)。如图8-1所示。chinese mat

3、h englishscore899876numbermathsexageaddressachiestudent10001Wang liM20Zhongshan roadacore图8-1学生情况登记表结构图8-1表示两个结构,一个是student结构,另一个是score结构。用C语言来表示这种结构的定义如下:struct score float chinese;float math;float english;; struct studentint number;char name9;char sex;int age;char address30 ;struct score achie; /*

4、achie 是 struct score 类型 */;8.2 结构体类型变量的定义、引用和初始化8.2.1 结构体类型变量的定义定义结构仅是对一种事务的说明,说明结构所包含的各个成员及其数据类型,它并不被分配内存空间。比如定义一个整型变量 i为int i ,而int只表示C语言的整型数据类型,它代表该类型的存储大小及运算规则。只有当数据类型后跟变量名,某种数据类型才有了实体, 这个变量可以进行运算,但 int 本身不允许进行运算。因此, C 语言的结构定义就像 C 语言 的保留字 int 一样,需要指定结构类型的变量,才能对结构中各个成员进行操作。结构体类型变量的定义与其它类型的变量的定义是一

5、样的,但由于结构体类型需要针对 问题事先自行定义,所以结构体类型变量的定义形式就增加了灵活性,共计有三种形式,分 别介绍如下:1先定义结构体类型,再定义结构体类型变量:例如: struct student Na, Nb, Nc;/* 结构体的定义见 8.1*/其中struct是C语言的保留字,表明是结构类型。Student是一结构名,是上一节中已定义的结构。 Na、 Nb 、 Nc 是定义的结构体类型变量。2定义结构体类型同时定义结构体类型变量:structscorefloatchinese;floatmath;floatenglish;;struct studentint number;ch

6、ar name9;char sex;int age;char address30 ;struct score achie; /*achie 是 struct score 类型 */Na,Nb,Nc ; 3直接定义无结构名的结构体类型变量: struct scorefloat chinese;float math;float english;;structint number;char name9;char sex;int age;char address30 ;struct score achie; /*achie 是 struct score 类型 */Na,Nb,Nc ; 该定义方法由于无

7、法记录该结构体类型,所以除直接定义外,不能再定义该结构体类型 变量。8.2.2 结构体变量的引用及初始化学习了怎样定义结构体类型和结构体类型变量,怎样正确地引用该结构体类型变量的成 员呢? C 语言规定引用的形式为:结构体类型变量名 .成员名例如:Na.age表示结构变量 Na中的age成员,该成员在结构定义中定义为整型变量, 这样可以对该成员进行赋值、算术运算等操作。以下例子都是合法的:Na.age=18;+Na.age;Total=Na.age+Nb.age+Nc.age;Nb.age=Na.age;strcpy(Na.address,中山南路”); strcpy(Nb.address,N

8、a.address);Nc=Na; /*C 语言允许将一个结构变量直接赋值给另一个具有相同结构的结构变量。*/如果成员本身又是一个结构类型,则要用若干个成员运算() ,一级一级地找到最低的 一级成员。 C 语言中只能对最低级的成员进行赋值、存取以及运算。例如:;Nb.achie=Na.achie; scanf(“%f”; scanf(“%d”,&Na.age); scanf(“%s”,&Nb.address); 对结构变量的初始化,其方法与对数组初始化相似,可以对外部存储类型的结构变量、静态存储类型的结构变量初始化,也可以对自动结构变量初始化。【例 8.1 】对结构变量进行初始化,并输出各成员

9、值。#include struct scorefloat chinese;float math;float english;struct studentint number;char name9;char sex;int age;char address30 ;struct score achie; /*achie是 struct score 类型 */;main()struct student Na=10001,wan li,M,19,zhongshan road,78.0,67.0,90.0; struct student Nb=10002,li fang,F,18,huajin road

10、,80.0,77.0,86.0; printf(%d,%s,%c,%d,%s,%.1f,%.1f,%.1fn,Na.number,Na.name,Na.sex,;printf(%d,%s,%c,%d,%s,%.1f,%.1f,%.1fn,Nb.number,Nb.name,Nb.sex,;8.3 结 构 体 数 组如果某班有 45个学生,每个学生的基本情况栏目相同,对这样的数据处理,就必须要数组来表示,而每一个数组元素都是一个结构体变量,都含有结构体的各个成员项,这就是 结构体数组。结构体数组的每个数组元素在内存中的地址是按照数组元素下标的顺序连续 的。与结构体变量说明类似,也可以通过三种形式

11、说明结构体数组。定义结构体数组的一般 形式为:struct结构体名结构体数组名整型常量表达式;例如:struct student stu45;/* 结构体的定义见 8.1*/定义一个结构体数组stu,共有45个元素,stu0stu44。每个元素都含有结构体student类型的各个成员项。结构体数组在说明时,可以对数组的部分或全部元素赋初值,即对数组元素的各个成员 项初始化。初始化的方法与对二维数组进行初始化的形式相似,如:struct student stu = , ,;【例8.2】设某组有4个人,填写如下的登记表,除姓名、学号外,还有三科成绩,编 程实现对表格的计算,求解出每个人的三科平均成

12、绩,求出四个学生的单科平均,并按平均 成绩由高分到低分输出。NameNumberEn glishmathemaphysicsaverageLipi ng1677265Yao ming2777380Liudo ng3817990Zhan gwei4687889#include struct stuchar name20;long number;float score4;main()void input();/*函数声明 */void aver();void order();void output();void out_row();struct stu stud4=liping,1,67.0,72

13、.0,65.0,yaoming,2,77.0,73.0,80.0,liudong,3,81.0,79.0,90.0,zhangwei,4,68.0,78.0,89.0;/*定义结构体数组并初始化*/float row3;aver(stud,4);order(stud,4);output(stud,4);out_row(stud,4);void aver(struct stu arr,int n)int i,j;for(i=0;in;i+)arri.score3=0;for(j=0;j3;j+)arri.score3+=arri.scorej; arri.score3/=3;void order

14、(struct stu arr,int n)struct stu temp;int i,j,x,y;for(i=0;in-1;i+)for(j=0;jarrj+1.score3)temp=arrj;arrj=arrj+1;arrj+1=temp; void output(struct stu arr,int n)int i,j;printf( * *TABLE *n);printf( printf(|%10s|%8s|%7s|%7s|%7s|%7s|n,Name,Number,English,mathema,ph ysics,average);printf(n);for(i=0;in;i+)

15、printf(|%10s|%8ld|,arri.name,arri.number);for(j=0;j4;j+)printf(%7.2f|,arri.scorej);printf(n);printf(n);void out_row(struct stu arr,int n) float row4=0,0,0,0;int i,j;for(i=0;i4;i+)for(j=0;jn;j+)rowi=rowi+arrj.scorei;rowi=rowi/n;printf(|%19c|,); for(i=0;i 成员项名例如: p2-age; 即 Stu0. ag e 。其中“ -”运算符,表示取结构体

16、指针变量所指向的结构体变量或结构体数组元素的成 员项。实际上,以下 3条语句功能是等价的:Ny.age = 17; ( *p1).age = 17; p1-age = 17;【例 8.3 】指向结构体变量的指针变量的使用。#include void main()struct testint i,j;char m,n;struct test a,b;struct test *pa,*pb;pa=&a;pb=&b;pa-i=pa-j=10;pa-m=pa-n=H; printf(%d,%d,%c,%cn,pa-i,pa-j,pa-m,pa-n);b=a;/* 将结构体变量 a 赋给另一个具有相同结

17、构的结构体变量 b*/ printf(%d,%d,%c,%cn,pb-i,pb-j,pb-m,pb-n);printf(%d,%d,%c,%cn,+pa-i,pa-j-,-pa-m,pa-n+); printf(%d,%d,%c,%cn,pb-i,pb-j,pb-m,pb-n);pb=pa;/* 将指针 pb 也指向结构体变量 a*/ printf(%d,%d,%c,%cn,+pa-i,pa-j-,-pa-m,pa-n+); printf(%d,%d,%c,%cn,pb-i,pb-j,pb-m,pb-n);说明:应注意pa-i+和+pa-i所表示的意思。其中,pa-i+是指先得到pa指向的结

18、构体变量中成员i的值,用完该值后使成员i的值加1 ; +pa-i是指先将pa指向的结构体变 量中成员i的值加1,然后使用成员i的现在值。8.4.2 结构体数组指针变量使用结构数组,可以通过数组下标来访问结构数组中各结构元素,也可以通过指向结构 数组的指针来访问结构数组中各结构元素,且使用起来更为方便。例如: struct student stu4,*p; /* 定义结构体数组及指向结构体类型的指针,结构 体类型定义见 8.1*/作 p=stu ,此时指针 p 就指向了结构体数组 stu 。 p 是指向一维结构体数组的指针,对 数组元素的引用可采用三种方法。1地址法stu+i 和 p+i 均表示

19、数组第 i 个元素的地址, 数组元素各成员的引用形式为: ( stu+i ) -name 、 (stu+i)-number禾口 (p+i)-name、( p+i ) -number 等。stu+i禾口 p+i 与&stui 意义相同。2指针法若p指向数组的某一个元素,则p+就指向其后续元素。3指针的数组表示法若 p=stu ,我们说指针 p 指向数组 stu , pi 表示数组的第 i 个元素,其效果与 stui 等同。对数组成员的引用描述为 :pi.name 、 pi.number 等。【例8.4 】指向结构体数组的指针变量的使用。#include struct data /* 定义结构体类

20、型 */int year,month,day;struct stu /* 定义结构体类型 */char name20;long num;struct data birthday;void main()int i;struct stu *p,student4=zhouping,1,1983,7,2,wangling,2,1984,3,24,hu bo,3,1982,5,16,hua qiang,4,1982,7,21;/*定义结构体数组并初始化 */p=student;/* 将数组的首地址赋值给指针 p,p 指向了一维数组 student*/ printf(n1Output name,numbe

21、r,year,month,dayn);for(i=0;iname,(p+i)-num,(p+i)-birthday.year,(p+i)-birthday.month,(p+i)-birthday.day);printf(n2Output name,number,year,month,dayn);for(i=0;iname,p-num,p-birthday.year,p-birthday.month,p-birthday.day);printf(n3Out putname,number,year,month,dayn);for(i=0;iname,(student+i)-num,(studen

22、t+i)-birthday.year,(student+i)-birthday.month,(student+i)-birthday.day);p=student;printf(n4Outputname,number,year,month,dayn);for(i=0;i4;i+)/* 采用指针的数组描述法输出数组元素的各成员 */ printf(%16s%7ld%8d/%d/%dn,pi.name,pi.num,pi.birthday.year, pi.birthday.month,pi.birthday.day);8.4.3 结构体指针变量作函数参数C 语言中允许一个完整的结构变量作为参数传

23、递,虽然合法,但要将全部成员值逐个传 递,特别是成员为数组时将会使传递的时间和空间开销很大,严重地降低了程序的效率。在 这种情况下,较好的办法是使用指针变量。以指向结构体变量(或数组)的指针作实参,将 结构体变量(或数组)的地址传给形参,这样,被调函数可以非常方便地处理主调函数中的 结构体变量(或数组) ,可以对它们的成员项进行修改或运算。【 例 8.5 】将【例 8.2 】改用结构体指针变量作函数参数实现。#include struct stuchar name20;long number;float score4;main()void input();/* 函数声明 */void aver

24、();void order();void output();void out_row();struct stu stud4=liping,1,67.0,72.0,65.0,yaoming,2,77.0,73.0,80.0,liudong,3,81.0,79.0,90.0,zhangwei,4,68.0,78.0,89.0;/* 定义结构体数组并初始化 */float row3;aver(stud,4);order(stud,4);output(stud,4);out_row(stud,4);void aver(struct stu *ptr,int n)/*形式参数中使用了指向结构体变量的指向

25、变量 */int i,j;for(i=0;iscore3=0;/* 采用结构体指针变量的表达方式“ - ” */for(j=0;jscore3+=(ptr+i)-scorej;(ptr+i)-score3/=3;void order(struct stu *ptr,int n)struct stu temp;int i,j,x,y;for(i=0;in-1;i+) for(j=0;jscore3(ptr+j+1)-score3) temp=*(ptr+j);*(ptr+j)=*(ptr+j+1);*(ptr+j+1)=temp;void output(struct stu *ptr,int n

26、)int i,j;printf( * *TABLE *n);printf( printf(|%10s|%8s|%7s|%7s|%7s|%7s|n,Name,Number,English,mathema,ph ysics,average);printf(n);for(i=0;iname,(ptr+i)-number);for(j=0;jscorej);printf(n);printf(n);void out_row(struct stu *ptr,int n)float row4=0,0,0,0;int i,j;for(i=0;i4;i+)for(j=0;jscorei;rowi=rowi/n;

27、printf(|%19c|,);for(i=0;i4;i+)printf(%7.2f|,rowi);printf(nn);说明:请注意将本例与例 8.2 进行比较分析。8.5 链 表8.5.1 链表的概述数组是一种静态的存储方式。所谓静态存储方式表现在数组使用之前,数组元素个数已 经说明好了,而且所占用的内存空间是连续的。因此,数组在处理一些动态数据(无法确切 知道数据的项数,并有可能增减)时存在一定的局限。这样一来,在程序设计中针对不同问 题有时需要30个大小的数组,有时需要 50个数组的大小,难于统一。要求数组必须说明的足 够大,如果数据项较少会造成内存使用的浪费,如果数据项多于说明,有可

28、能造成程序错误。链表是一种常用的重要的数据结构,是动态分配内存的数据组织方式。该方式允许用户 根据需要随时增减数据项,而且,数据项在内存中不必连续。图8-2表示的是最简单的一种链表(单链表)的结构。head120021003800ki-1kiki+1图8-2单链表示意图单链表有一个头结点 head,指向链表在内存的首地址。链表中的每一个结点的数据类型 都是结构体类型,结点有两个成员:数据域(存放该项数据的内容)和指针域(用来存放下 一个结点的地址)。链表按此结构对各结点的访问需从链表的头找起,后续结点的地址由当 前节点给出。无论在表中访问那一个结点,都需要从链表的头开始,顺序向后查找。链表的

29、尾节点由于无后续节点,其指针域为空,写作为 NULL。图8-2还给出这样一层含义,链表中的各结点在内存的存储地址不是连续的,其各结点 的地址是在需要时向系统申请分配的,系统根据内存的当前情况,既可以连续分配地址,也 可以跳跃式分配地址。看一下链表结点的数据结构定义:struct nodeint num;struct node *p;在链表结点的定义中,除一个整型的成员外,成员p是指向与结点类型完全相同的指针。 在链表节点的数据结构中,非常特殊的一点就是结构体内的指针域的数据类型使用了未定义 成功的数据类型。这是在 C中唯一规定可以先使用后定义的数据结构。需要注意的是:上面只是定义了一个 str

30、uct node类型,并未实际分配存储空间。链表结 构是动态地分配的,即在需要时才开辟一个结点的存储单元。怎样动态地开辟和释放存储单 元呢? C 语言提供了以下的库函数来实现。1 malloc 函数函数的原型声明为:void *malloc(unsigned size);函数的功能:分配大小为size (函数参数,最大65535)字节的内存单元,并返回所分配内存单元的地址,该地址是 void 类型,也就是说地址指向一个物理字节。分配内存可能成 功,也可能失败。成功时,则返回所分配内存单元的首地址;失败时,则返回NULL (空)。如:利用 malloc 函数分配一个整型单元,并赋值为 5。int

31、 *p;p=(int *)malloc(sizeof (int);*p=5;虽然分配了 int 类型所占字节数的内存单元,但返回的是 void 类型的地址,通过强制类 型转换后变成了 int 类型的地址。2. calloc 函数函数的原型声明为:void *calloc(unsigned n , unsigned size);函数的功能:分配 n个size大小的连续内存单元。如果分配成功,返回所分配内存单元 的首地址,类型为 void ;如果分配失败,返回NULL 。如:为有 10 个的浮点型数据分配内存:float *p;p=(float *)calloc(10,sizeof (float)

32、;3 free 函数函数的原型声明为:void free(void *ptr);函数的功能:释放ptr指向的由calloc或malloc分配的内存空间。函数无返回值。释放后的空间可以再次被使用。对链表的操作主要有以下几种:( 1)建立并初始化链表:从无到有地建立起一个链表,即往空链表中依次插入若干结 点,并保持结点之间的前驱和后继关系。( 2)索引操作:按给定的结点索引号或检索条件,查找某个结点。如果找到指定的结 点,则称为检索成功;否则,称为检索失败。(3)插入操作:在结点 ki-1与ki之间插入一个新的结点k使线性表的长度增1,且ki-1 与 ki 的逻辑关系发生如下变化:插入前,ki-1

33、是ki的前驱,ki是ki-1的后继;插入后,新插入的结点k成为ki-1的后继、ki的前驱,如图8-3所示。head120021003800k图8-3插入操作示意图(4)删除操作:删除结点ki,使线性表的长度减1,且ki-1、ki和ki+1之间的逻辑关系发生如下变化:删除前,ki是ki+1的前驱、ki-1的后继;删除后,ki-1成为ki+1的前驱,ki+1成为ki-1 的后继,如图8-4所示。ki-1kiki+1图8-4删除操作示意图8.5.2 创建并输出单链表【例8.6】创建一个存放整数(输入-999做结束标志)的单链表,并打印输出。#include#includestruct node/*

34、链表结点的结构*/int num;struct node * next;;void main()struct node *create();/*函数声明 */void print();struct node *head;/*定义头指针 */head=NULL;/*建一个空表 */head=create(head);/*创建单链表 */print(head);/*打印单链表 */struct node *create(struct node *head)/*函数返回的是与结点相同类型的指针 */struct node *p1,*p2;p1=p2=(struct node *)malloc(siz

35、eof(struct node);/*申请新结点 */scanf(%d,&p1-num);/* 输入结点的值 */p1-next=NULL;/* 将新结点的指针置为空 */ while(p1-num!=-999)/* 输入结点的数值大于 0*/if(head=NULL)head=p1;/* 空表,接入表头 */else p2-next=p1;/* 非空表,接到表尾 */p2=p1;p1=(struct node *)malloc(sizeof(struct node);/*申请下一个新结点 */scanf(%d,&p1-num);/* 输入结点的值 */ p1-next=NULL;/* 将新结

36、点的指针置为空 */return head;/* 返回链表的头指针 */void print(struct node *head)/* 输出以 head 为头的链表各结点的值 */struct node *temp;temp=head;/* 取得链表的头指针 */while(temp!=NULL)/* 只要是非空表 */printf(%6d,temp-num);/* 输出链表结点的值 */temp=temp-next;/* 跟踪链表增长 */ 在链表的创建过程中,链表的头指针是非常重要的参数。因为对链表的输出和查找都要 从链表的头开始,所以链表创建成功后,要返回一个链表头节点的地址,即头指针。

37、8.5.3 单链表的删除和插入【 例 8.7】创建包含学号、姓名结点的单链表。其结点数任意个,表以学号为序,低学号 的在前,高学号的在后,以输入姓名为空作结束。在此链表中,要求删除一个给定姓名的结 点,并插入一个给定学号和姓名的结点。#include stdlib.h#include malloc.hstruct node/* 结点的数据结构 */int num;char str20;struct node *next;void main()/* 函数声明 */struct node *create();struct node *insert();struct node *delet();vo

38、id print();struct node *head;char str20;int n;head=NULL;/* 做空表 */head=create(head);/* 调用函数创建以 head 为头的链表 */ print(head);/* 调用函数输出结点 */ printf(n input inserted num,name:n);gets(str);/*输入学号 */n=atoi(str);gets(str);/*输入姓名 */head=insert(head,str,n);/* 将结点插入链表 */ print(head);/* 调用函数输出结点 */ printf(n input

39、 deleted name:n);gets(str);/* 输入被删姓名 */head=delet(head,str);/* 调用函数删除结点 */ print(head);/* 调用函数输出结点 */ return;/* 创建链表 */struct node *create(struct node *head)char temp30;struct node *p1,*p2;p1=p2=(struct node*)malloc(sizeof(struct node);printf(input num,name:n); printf(exit:double times Enter!n);gets(temp);gets(p1-str); p1-num=atoi(temp);p1-next=NULL;while(strlen(p1-str)

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

当前位置:首页 > 社会民生


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