资源预览内容
第1页 / 共44页
第2页 / 共44页
第3页 / 共44页
第4页 / 共44页
第5页 / 共44页
第6页 / 共44页
第7页 / 共44页
第8页 / 共44页
第9页 / 共44页
第10页 / 共44页
亲,该文档总共44页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
C语言程序设计,中国铁道出版社,2008年1月,高等学校计算机教育系列规划教材,第9章 结构体,第9章 结构体 9.1 结构体类型的定义 9.2 结构体变量 9.3 结构体数组 9.4 结构体类型的指针 9.5 结构体与函数 9.6 链表 9.7 结构体应用举例 本章小结,9.1 结构体类型的定义 结构体类型的定义格式为: struct 结构体类型名 成员说明列表 ; 其中,花括号内的内容是该结构体类型的成员说明。每个成员说明的形式为: 类型符 成员名;,9.2 结构体变量 9.2.1 结构体变量的定义 要定义一个结构体类型的变量,可以采取以下3种方法。 (1)先定义结构体类型,再定义体类型变量。 (2)在定义类型的同时定义变量。 它的作用与前面定义的相同。即定义了两个struct student类型的变量student1和student2。这种定义方法的一般格式为: struct 结构体类型名 成员说明列表 变量名列表;,(3)直接定义结构体类型变量。 其一般格式为: struct 成员说明列表 变量名列表; 即在结构体定义时不出现结构体类型名。这种形式虽然简单,但不能在再需要使用时,使用所定义的结构体类型。,关于结构体类型,有几点需要说明: (1)类型与变量是不同的概念,不要混同。对结构体变量来说,在定义时一般先定义一个结构体类型,然后定义变量为该类型。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型是不分配存储空间的,只对变量分配存储空间。 (2)对结构体中的成员,可以单独使用,它的作用与地位相当于普通变量。 (3)成员也可以是一个结构体变量。 (4)成员名可以与程序中的变量名相同,两者代表不同的对象。,9.2.2 结构体变量的使用 由结构体变量名引用其成员的标记形式为: 结构体变量名.成员名 由指向结构体的指针变量引用结构体成员的标记形式为: 指针变量名-成员名,9.2.3 结构体变量的初始化 结构体变量和其他变量一样,可以在变量定义的同时进行初始化。 1对外部存储类型的结构体变量进行初始化 【例9.1】分析下列程序的输出结果。 2对静态存储类型的结构体变量进行初始化,9.2.4 结构体变量的输入和输出 C语言不允许把一个结构体变量作为一个整体进行输入或输出,而应按成员变量输入或输出。例如,若有一个结构体变量: struct char name15; char addr20; long num; stud=“Wang Dawei”,“125 Beijing Road”,3021118; 变量stud在内存中存储情况如图9-2所示,是按成员变量存放的。,由于变量stud包含两个字符串数据和一个长整型数据,因此输出stud变量,应该使用如下方式: printf(“%s,%s,%ldn”,stud.name,stud.addr,stud.num); 输入stud变量的各成员值,则用: scanf(“%s%s%ld”,stud.name,stud.addr, gets函数输入一个字符串给stud.name,puts函数输出stud.name数组中的字符串。,9.3 结构体数组 9.3.1 结构体数组的定义 与定义结构体变量的方法一样,在结构体变量名之后指定元素个数,就能定义结构体数组。结构体数组定义的一般格式为: 结构体类型名 数组名常量表达式; 如同元素为标准数据类型的数组一样,结构体数组各元素在内存中也按顺序存放,也可初始化,对结构体数组元素的访问也要利用元素的下标。访问结构体数组元素的成员的标记方法为: 结构体数组名元素下标.结构体成员名,9.3.2 结构体数组的初始化 在对结构体数组初始化时,要将每个元素的数据分别用花括弧括起来,一般格式是: 结构类型 数组名常量表达式=初始化表;,9.3.3 结构体数组的使用 一个结构体数组的元素相当于一个结构体变量,引用结构体数组元素有如下规则。 (1)引用某一元素的一个成员。 (2)可以将一个结构体数组元素赋给同一结构体类型数组中的另一个元素,或赋给同一类型的变量。 (3)不能把结构体数组元素作为一个整体直接进行输入或输出,只能以单个成员对象进行输入或输出。 【例9.2】结构体数组的应用。,9.4 结构体类型的指针 9.4.1 指向结构体变量的指针 指向结构体的指针变量定义的一般格式为: struct 类型名 *指针变量名; 通过指向结构体的指针变量引用结构体成员的方法是: 指针变量-结构体成员名 “*指针变量”表示指针变量所指对象,所以通过指向结构体的指针变量引用结构体成员也可写成以下形式: (*指针变量).结构体成员名 【例9.3】写出下列程序的执行结果。,9.4.2 指向结构体数组元素的指针 一个指针变量可以指向一个结构体数组元素,也就是将该结构体数组的数组元素地址赋给此指针变量。例如: struct int a; float b; arr3,*p; p=arr; 此时使p指向arr数组的第一个元素, “p=arr;”等价于“p=”则此时指针变量p 此时指向arr1,指针指向关系如 图9-3所示。 【例9.4】输入3个学生的信息并输出。,9.5 结构体与函数 9.5.1 结构体变量作为函数参数 旧的C标准不允许用结构体变量作为函数参数,只允许指向结构体变量的指针作为函数参数,即传递结构体变量的首地址。新的标准以及许多C语言编译系统都允许用结构体变量作为函数参数,即直接将实参结构体变量的各个成员的值全部传递给形参的结构体变量。当然,实参和形参的结构体变量类型应当完全一致。 【例9.5】将例9.4中的输出的功能用函数实现。,9.5.2 指向结构体变量的指针作为函数参数 用结构体变量作为函数参数,这是ANSI C新标准的扩充功能。在过去的C版本中不能这样使用,而是通过指针来传递结构体变量的地址给形参,再通过形参指针变量引用结构体变量中成员的值。 【例9.6】有一结构体变量stu,内含学生学号、姓名和3门课的成绩。要求在main函数中给变量赋值,在另一函数print中将它们输出。,9.5.3 返回结构体类型值的函数 函数的返回值可以是结构体类型。例如,定义了结构体数组: struct student stud100; 数据输入可由如下形式的语句实现: for(i=0;i100;i+) studi=input(); 函数input的功能是输入一个结构体数据,并将输入结构体数据作为返回值,返回给第i个学生记录,实现第i个学生的数据输入。,函数input定义如下: struct student input() int i; struct student stud; scanf(“%ld”, /*返回结构体数据*/ ,9.6 链 表 9.6.1 链表概述 链表是最简单也是最常用的一种数据结构。它是对动态获得的内存进行组织的一种结构。如图9-4所示为最简单的一种链表(单向链表)结构。链表有一个头指针变量,图中以head表示,它存放一个地址。该地址指向一个链表元素。链表中每一个元素称为结点,每个结点都包括两部分:一是用户需要用的实际数据,二是下一个结点的地址(指针)。可以看出,head指向第一个结点,第一个结点又指向第二个结点,一直到最后一个结点,该结点不再指向其他结点,它称为表尾,它的地址部分放一个NULL(表示“空地址”),链表到此结束。,图9-4 链表结构示意图 由图9-4可见,一个结点的后继结点位置由结点所包含的指针成员所指,链表中各结点在内存中的存放位置是任意的。如果寻找链表中的某一个结点,必须从链表头指针所指的第一个结点开始,顺序查找。另外,图9-4所示的链表结构是单向的,即每个结点只知道它的后继结点位置,而不能知道它的前驱结点。在某些应用中,要求链表的每个结点都能方便地知道它的前驱结点和后继结点,这种链表的表示应设有两个指针成员,分别指向它的前驱和后继结点,这种链表称为双向链表。为适应不同问题的特定要求,链表结构也有多种变形。,9.6.2 链表的基本操作 链表的基本操作包括建立链表,链表的插入、删除、输出和查找等。链表结点的存储空间是程序根据需要向系统动态申请的,这时要用到8.7节中介绍的动态内存管理函数。 1建立链表 如图9-5所示为用插表头方法建立链表,如图9-6所示为用链表尾方法建立链表。,图9-5 用插表头方法建立链表,插表头算法抽象描述如下: (1)head=NULL; /*表头指向空,表示链表为空*/ (2)产生新结点,地址赋给指针变量p。 (3)p-next=head;head=p; /*插表头操作*/ (4)循环执行(2),继续建立新结点。,图9-6 用链表尾方法建立链表,链表尾算法抽象描述如下: (1)head=last=NULL; /*表头指向空,表示链表为空,last是表尾指针*/ (2)产生新结点,地址赋给指针变量p,p-next=NULL; /*新结点作为表尾*/ (3)如果head为NULL,则 head=p; /*新结点作为表头,这时链表只有一个结点*/ 否则 last-next=p; /*链表操作*/ (4)last=p; /*表尾指针指向新结点*/ (5)循环执行(2),继续建立新结点。 【例9.7】编写一个函数,建立一个有n名学生数据的单向链表。,2链表的插入操作 链表的插入操作是要将一个结点插入到一个已有链表中的某个位置。该操作可以分两步完成,先找到插入点,再插入结点。操作步骤如图9-8所示。,图9-8 链表的插入操作,链表的插入操作算法描述如下: 指针head指向链表的头结点,p0指向待插入的结点,p1和p2一前一后指示插入点。 (1)最初p1=head;。 (2)移动指针p2=p1,p1=p1-next,直到找到插入点。 (3)插入结点p0-next=p1,p2-next=p0。 仍然以例9.7建立的有n名学生数据的单向链表为例,设已有的链表各结点是按学号由小到大顺序排列的。,用指针变量p0指向待插入的结点,最初p1=head,找插入点的操作如下: 当p0-nump1-num且p1-next!=NULL p2=p1; p1=p1-next; 插入结点操作如下: if p1=head则 结点作为表头插入 else if p1-next=NULL则 结点作为表尾插入 else 插入在p2所指结点之后,3链表的删除操作 从一个链表中删去一个结点,只要改变链接关系即可,即修改结点指针成员的值,如图9-9所示。,图9-9 删除结点操作,删除结点算法描述如下: 用指针p1指向待删结点,p2指向待删结点的前一个结点。 (1)p1 = head,从第一个结点开始检查。 (2)当p1指向的结点不是满足删除条件的结点且没有到表尾时,p2 = p1,p1 = p1-next(移动指针p1,继续查找)。 (3)如果找到了删除结点p1!=NULL,则要分两种情形: 如果p1 = = head(删除的是头结点)则 head=head-next; /*删除头结点*/ 否则 p2-next=p1-next; /*删除p1指向的结点*/ (4)free(pl),释放被删除结点的内存空间。,4链表的输出操作 要依次输出链表中各结点的数据比较容易处理。首先要知道链表头结点的地址,也就是要知道head的值,然后设一个指针变量p,先指向第一个结点,输出p所指的结点,然后使p后移一个结点,再输出。直到链表的尾结点。,5链表的查找操作 链表的查找是指在已知链表中查找值为某指定值的结点。链表的查找过程是从链表的头指针所指的第一个结点出发,顺序查找。若发现有指定值的结点,以指向该结点的指针值为查找结果;如果查找至链表
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号