C语言程序设计-09结构体_第1页
C语言程序设计-09结构体_第2页
C语言程序设计-09结构体_第3页
C语言程序设计-09结构体_第4页
C语言程序设计-09结构体_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第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)在定义类型的同时定义变量。

它的作用与前面定义的相同。即定义了两个STRUCTSTUDENT类型的变量STUDENT1和STUDENT2。这种定义方法的一般格式为:

STRUCT结构体类型名

{

成员说明列表

}变量名列表;

(3)直接定义结构体类型变量。

其一般格式为:

STRUCT

{

成员说明列表

}变量名列表;

即在结构体定义时不出现结构体类型名。这种形式虽然简单,但不能在再需要使用时,使用所定义的结构体类型。关于结构体类型,有几点需要说明:

(1)类型与变量是不同的概念,不要混同。对结构体变量来说,在定义时一般先定义一个结构体类型,然后定义变量为该类型。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型是不分配存储空间的,只对变量分配存储空间。

(2)对结构体中的成员,可以单独使用,它的作用与地位相当于普通变量。

(3)成员也可以是一个结构体变量。

(4)成员名可以与程序中的变量名相同,两者代表不同的对象。

9.2.2结构体变量的使用

由结构体变量名引用其成员的标记形式为:

结构体变量名.成员名

由指向结构体的指针变量引用结构体成员的标记形式为:

指针变量名->成员名9.2.3结构体变量的初始化

结构体变量和其他变量一样,可以在变量定义的同时进行初始化。

1.对外部存储类型的结构体变量进行初始化

【例9.1】分析下列程序的输出结果。

2.对静态存储类型的结构体变量进行初始化

9.2.4结构体变量的输入和输出

C语言不允许把一个结构体变量作为一个整体进行输入或输出,而应按成员变量输入或输出。例如,若有一个结构体变量:

STRUCT

{

CHARNAME[15];

CHARADDR[20];

LONGNUM;

}STUD={“WANGDAWEI”,“125BEIJINGROAD”,3021118};

变量STUD在内存中存储情况如图9-2所示,是按成员变量存放的。由于变量STUD包含两个字符串数据和一个长整型数据,因此输出STUD变量,应该使用如下方式:

PRINTF(“%S,%S,%LD\N”,STUD.NAME,STUD.ADDR,STUD.NUM);

输入STUD变量的各成员值,则用:

SCANF(“%S%S%LD”,STUD.NAME,STUD.ADDR,&STUD.NUM);

由于成员项NAME和ADDR是字符数组,按%S字符串格式输入,故不要写成&STUD.NAME和&STUD.ADDR,而NUM成员是LONG型,故应当用&STUD.NUM。

当然也可以用GETS函数和PUTS函数输入和输出一个结构体变量中的字符数组成员。例如:

GETS(STUD.NAME);

PUTS(STUD.NAME);

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

{

INTA;

FLOATB;

}ARR[3],*P;

P=ARR;

此时使P指向ARR数组的第一个元素,

“P=ARR;”等价于“P=&ARR[0];”。

若执行“P++;”则此时指针变量P

此时指向ARR[1],指针指向关系如

图9-3所示。

【例9.4】输入3个学生的信息并输出。

9.5结构体与函数

9.5.1结构体变量作为函数参数

旧的C标准不允许用结构体变量作为函数参数,只允许指向结构体变量的指针作为函数参数,即传递结构体变量的首地址。新的标准以及许多C语言编译系统都允许用结构体变量作为函数参数,即直接将实参结构体变量的各个成员的值全部传递给形参的结构体变量。当然,实参和形参的结构体变量类型应当完全一致。

【例9.5】将例9.4中的输出的功能用函数实现。

9.5.2指向结构体变量的指针作为函数参数

用结构体变量作为函数参数,这是ANSIC新标准的扩充功能。在过去的C版本中不能这样使用,而是通过指针来传递结构体变量的地址给形参,再通过形参指针变量引用结构体变量中成员的值。

【例9.6】有一结构体变量STU,内含学生学号、姓名和3门课的成绩。要求在MAIN函数中给变量赋值,在另一函数PRINT中将它们输出。

9.5.3返回结构体类型值的函数

函数的返回值可以是结构体类型。例如,定义了结构体数组:

STRUCTSTUDENTSTUD[100];

数据输入可由如下形式的语句实现:

FOR(I=0;I<100;I++)

STUD[I]=INPUT();

函数INPUT的功能是输入一个结构体数据,并将输入结构体数据作为返回值,返回给第I个学生记录,实现第I个学生的数据输入。

函数INPUT定义如下:

STRUCTSTUDENTINPUT()

{

INTI;

STRUCTSTUDENTSTUD;

SCANF(“%LD”,&STUD.NO);

/*输入学号*/

GETS(STUD.NAME);

/*输入学生姓名*/

FOR(I=0;I<3;I++)

/*输入学生的3门成绩*/

SCANF(“%F”,&STUD.SCORE[I]);

RETURNSTUD; /*返回结构体数据*/

}

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->NUM>P1->NUM且P1->NEXT!=NULL

{

P2=P1;

P1=P1->NEXT;

}

插入结点操作如下:

IFP1==HEAD则

结点作为表头插入

ELSEIFP1->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.链表的查找操作

链表的查找是指在已知链表中查找值为某指定值的结点。链表的查找过程是从链表的头指针所指的第一个结点出发,顺序查找。若发现有指定值的结点,以指向该结点的指针值为查找结果;如果查找至链表结尾,未发现指定值的结点,查找结果为NULL,表示链表中没有指定值的结点。为简单起见,以指定的学号作为查找结点的关键字。

9.7结构体应用举例

【例9.8】用结构体类型描述复数,编一程序,计算并输出复数四则运算的结果,要求复数加、减、乘和除分别用4个函数实现。

【例9.9】设计一个洗牌和发牌的程序,用H代表红桃,D代表方片,C代表梅花,S代表黑桃,用1~13代表每一种花色的面值。

【例9.10】结构体数组排序。

【例9.11】链表的结点信息包括学生学号、成绩,结点定义如下:

STRUCTPLIST

{

INTNO;

FLOATSCORE;

STRUCTPLIST*NEXT;

};

设已经建立两个具有上述结构的链表,且两个链表都是按学号升序排列的,要求编写一个函数,将两个链表合并,仍按学号升序排列。

编写程序时要考虑以下几点:

(1)函数应有两个链表指针形参P1、P2,它们指向各自的表头。

(2)最初新链表的头指针HEAD=NULL,新链表的当前结点指针P=NULL。

(3)产生新链表的头结点。

IF(P1->NO<P2->NO)/*比较两个链表中当前结点的学号*/

{HEAD=P=P1;P1=P1->NEXT;}

ELSE

{HEAD=P=P2;P2=P2->NEXT;}

(4)当两个链表的指针均没指向表尾,则选择两个链表中的结点并入到新链表。

IF(PL->NO<P2->NO)

将P1指向的结点接到新链表的表尾:P->NEXT=P1;

并移动P和P1;

ELSE

将P2指示的结点接到新链表的表尾:P->NEXT=P2;

并移动P和P2;

(5)当某一个链表已到表尾,则另一个链表的剩余部分直接链接到新链表的表尾。

IF(P1!=NULL)

P->NEXT=P1;

ELSE

P->NEXT=P2;

本章小结

1.结构体是一种构造类型,它由若干成员组成。每一个成员既可以是一个基本数据类型也可以是

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论