1、2019/5/15,华中科技大学计算机学院,1,C语言程序设计,The C Programming Language,华中科技大学计算机学院 曹计昌,2019/5/15,华中科技大学计算机学院,2,第10章 结构与联合,结构与联合都属于C的构造类型。 对结构与联合而言,都需要先定义结构类型和联合类型,然后再根据已经定义的结构类型来定义对应的结构变量以及用已经定义的联合类型来定义对应的联合变量。本章介绍: 结构类型和结构变量的声明,结构类型的使用; 结构类型的指针; 有结构类型参数的函数; 结构数组; 字段结构; 以及联合类型和联合变量的定义,联合变量的使用; 动态存储分配,动态数组设计; 以及
2、与动态存储分配相关的链表、栈、树等动态数据结构。,2019/5/15,华中科技大学计算机学院,3,10.1 结构概述,结构产生的背景: 程序设计语言的发展总是与数据类型的发展、丰富、以及完善联系在一起的。 变量可以认为是内存单元的有名表示。变量在处理大量同类型数据时就暴露出名字多,不利于用循环处理等一系列不足。 数组则是处理大量同类型数据的有力工具。通过数组名和下标,可以方便的描述大量同类型数据,并且可以充分利用循环来进行快速处理。 问题: 如何将类型不同而关系又非常密切的数据项组织在一起,统一加以处理? 结构产生的背景!,2019/5/15,华中科技大学计算机学院,4,描述全班学习情况的实际
3、问题,问题: 描述全班、全年级每位同学的英语、高等数学、普通物理、C语言程序设计等课程的学习情况,需要学号、班级、姓名、以及各科成绩等属性来描述。 特点:学号、班级、姓名往往用字符数组描述、性别往往用字符型描述,各科成绩则往往用整型或浮点型描述。 困难:对这些大量不同类型数据项,用数组已经不能有效解决问题。 新的需求:如何将不同的数据类型的成员(即数据项)组织起来,形成新的构造类型就是结构产生的实际背景。,2019/5/15,华中科技大学计算机学院,5,设计和使用结构类型的方法,结构类型是一种能够将不同数据类型的成员组织起来所形成的一种新的构造类型。 结构类型的设计: 在程序设计中,要先确定需
4、要被组织的数据类型,由这些数据类型说明的标识符称为结构类型的成员;通过定义结构类型将这些成员组织起来,形成新的数据类型。 结构类型的使用: 通过结构类型来声明对应的结构变量、结构指针、或结构数组。对结构变量、结构指针、或结构数组中成员的操作将最终完成所需要解决的计算任务。,2019/5/15,华中科技大学计算机学院,6,注解,有些教材中将结构类型称为结构体、聚合类型。 C中的结构在其它程序设计语言中往往称为记录(record)。 以记录为基础,可以进一步构造文件、基于记录的数据库、以及许多动态数据结构。,2019/5/15,华中科技大学计算机学院,7,10.2 结构类型声明和结构变量的声明及初
5、始化,在声明结构类型时,需要规定该结构类型包括那些成员,要说明成员的数据类型和名字。 声明结构类型是创建用户自定义数据类型的过程,它并不创建对象,即不进行存储分配。 声明结构类型的一般形式是:struct 结构类型名成员声明表; 其中:struct是关键字,用以说明结构类型。结构类型名是该结构类型的名字,它应该是C的合法标识符。一对花括号界定的是成员声明表 。,2019/5/15,华中科技大学计算机学院,8,成员声明表的一般形式,数据类型1 成员名11,成员名1k; 数据类型n 成员名n1,成员名nm; 数据类型1 和数据类型n可以相同,也可以不同。 每个声明允许用逗号为分隔符说明多个同类型的
6、成员。 结构类型的声明应该以分号结束。,2019/5/15,华中科技大学计算机学院,9,例:学生学习情况的结构类型声明,struct stu_study /* stu_study是结构类型名 */char num12; /* 学号成员,字符数组类型 */char name9; /* 姓名成员,字符数组类型 */char sex; /* 性别成员,字符类型 */int English; /* 英语成员,整型 */int Math,Physics,C; / *数学、物理、C成员,整型 */ ; 该声明定义了一个struct stu_study的结构类型.stu_study是结构类型名,用以区分其他
7、类型的结构。 struct stu_study实际上是一种新的构造类型名,可用于说明struct stu_study类型的结构变量。其在语法方面的作用与int,char等一样,起类型说明符的作用。 num、name、sex、English、Math、Physics、C是成员,它们被组织到一个新的struct stu_study的结构类型之中。,2019/5/15,华中科技大学计算机学院,10,C关于结构类型声明的规定,(1) 同一结构内的成员不能同名。但成员可以与结构外部的变量同名,也可以与其他结构的成员同名。 (2) 成员的数据类型可以是除本结构类型以外的其他任何类型。 (3) 结构类型可以
8、嵌套定义,形成嵌套结构。 (4) 结构类型是包含一系列成员的构造类型,成员在内存中连续存放,成员存储分配按照结构声明体中不同声明从上向下,同一声明中从左向右的顺序进行,每个成员所占存储空间的大小由其类型确定。 (5) 一般而言,成员所占存储的大小必须在结构类型声明时确定。即C不支持动态结构类型。 注: 根据ISO/IEC 9899标准,作为一个特例,结构类型中最后一个成员可以具有不完全的数组类型,使得C可以在有限程度上支持动态结构类型。,2019/5/15,华中科技大学计算机学院,11,含柔性数组成员(flexible array member)的声明,struct dy_stu_study
9、/* dy_stu_study是结构名 */ char num12; /* 学号成员,字符数组类型 */ char name9; /* 姓名成员,字符数组类型 */ char sex; /* 性别成员,字符类型 */ int score;/* 各科成绩的柔性数组成员,动态整型数组 */ ; 可以通过动态存储分配为score数组指定大小。如果score数组依次存放英语、数学、物理、C语言4门课程的成绩,在16位机中可以为其分配42=8个字节的存储;在32位机中则需要为其分配44=16个字节的存储。称这种结构类型为有限动态结构类型。,2019/5/15,华中科技大学计算机学院,12,例10.1声明
10、一个同学通讯录的结构类型,struct address_book char name9; /* 姓名,字符数组类型 */int age; /* 年龄,整型 */char department50; /* 工作部门,字符数组类型 */char address80; /* 家庭住址,字符数组类型 */char phone_number16;/* 电话,字符数组类型 */char mobile12; /* 手机号码,字符数组类型 */char email50; /* 电子邮箱,字符数组类型 */ ;,2019/5/15,华中科技大学计算机学院,13,例10.2 声明一个只含有整数类型和指向自身实例指
11、针的结构类型。,struct int_node int number;struct int_node *next; ; 在该结构类型中: number被称为数据域, 而next被称为指向自身结构实例的指针域。,2019/5/15,华中科技大学计算机学院,14,10.2.2 结构变量的声明,结构类型的变量往往简称为结构变量,有时甚至简称为结构。 结构变量的声明有两种方式: 一是结构类型和结构变量分别声明。即:先声明结构类型,再声明结构变量。 二是结构类型和结构变量同时声明。即:在声明结构类型的同时声明结构变量。,2019/5/15,华中科技大学计算机学院,15,1结构类型和结构变量分别声明,声明
12、结构变量的一般形式是:存储类型 struct 结构类型名 结构变量列表; 其中,存储类型可以是extern、static、auto、register,分别表示外部结构变量、静态结构变量、自动结构变量(或局部结构变量)、以及寄存器结构变量。 结构变量列表由标识符序列组成,两个标识符之间必须用逗号分隔,每个标识符对应一个结构变量。结构变量的声明应该以分号结束 。,2019/5/15,华中科技大学计算机学院,16,结构变量声明语句,struct stu_study Zhang;就声明了一个struct dy_stu_study类型的结构变量Zhang。而结构变量声明语句:struct address
13、_book John,Mary,Jones;则声明了三个struct address_book类型的结构变量John,Mary和Jones。,2019/5/15,华中科技大学计算机学院,17,例10.3 用存储类型修饰结构变量声明的例子。,(1) auto struct int_node a,b,c; (2) register struct address_book addr; (3) static struct int_node x,y; (4) extern struct stu_study Wang;,2019/5/15,华中科技大学计算机学院,18,2结构类型和结构变量同时声明,其一般
14、形式为: 存储类型 struct 结构类型名成员声明表 结构变量列表; 其中,结构变量列表由标识符序列组成,两个标识符之间要用逗号分隔,每个标识符对应一个结构变量。 并且可以通过存储类型修饰结构变量列表中的结构变量。,2019/5/15,华中科技大学计算机学院,19,结构类型和结构变量同时声明的例子,static struct point int x;int y; p1,p2; 它在声明结构类型struct point的同时,声明了struct point类型的静态结构变量p1和p2。 P1, p2具有静态生存期. struct point结构类型可以用来表示平面上的一个点,成员x、y分别表示
15、平面上点的横坐标和纵坐标。结构变量p1和p2则分别表示平面上的两个点。,2019/5/15,华中科技大学计算机学院,20,无名结构类型,一般称省略结构类型名的结构类型为无名结构类型。如: struct int x;float y; u,v; 它声明了结构变量u和v,结构变量u、v分别都有一个整型成员x,一个浮点型成员y。 由于省略了结构类型名,在后续程序中不能再声明类似类型的变量。,2019/5/15,华中科技大学计算机学院,21,3. 用typedef定义结构类型名,用typedef可以为一个已知的结构类型进行命名。这种方法在程序设计中使用得非常普遍。例如: typedef struct p
16、oint int x;int y; point; 它将struct point结构类型命名为point,,2019/5/15,华中科技大学计算机学院,22,用point来表示struct point 结构类型的声明,point u,v; 它与 struct point u,v; 等价。 用typedef还可以为一个无名结构类型进行命名。如:typedef struct int x;int y; point; 则point就代表有两个整型成员x,y的结构类型。也可以用:point u,v;说明结构变量u和v。,2019/5/15,华中科技大学计算机学院,23,10.2.3 结构变量的初始化,在声
17、明结构变量的同时可以对其进行初始化。初始化所用的初值由初值表提供,初值表的形式与数组初始化时使用的初值表类似,是由一对花括号界定的初值序列。结构变量的初始化的一般形式是: 存储类型 struct 结构类型名成员声明表 结构变量1=初值表1, ,结构变量n=初值表n; 或: 存储类型 struct 结构类型名 结构变量1=初值表1, ,结构变量n=初值表n;,2019/5/15,华中科技大学计算机学院,24,结构变量的初始化举例,struct stu_study char num5; char name9; char sex; int English; int Math,Physics,C; W
18、ang=1234,Wang Wu,m,81,92,76,85 ; 它将结构变量Wang的成员num、name、sex、English、Math、Physics、C依次初始化为1234、Wang Wu、m、81、92、76、85。,2019/5/15,华中科技大学计算机学院,25,通过存储类型修饰符对结构变量的存储类型进行修饰例的例子,static struct point int x;int y;p1=1,2,p2=10,20; 它在声明struct point类型的静态结构变量p1,p2的同时,分别将其成员x、y初始化为1,2和10,20。此时,成员x、y具有静态变量的特性。,2019/5/
19、15,华中科技大学计算机学院,26,10.3 结构类型的使用,结构类型的使用包括对结构变量的引用和对结构变量中成员的引用两个方面。 对结构变量的引用包括结构变量的赋值操作、取地址操作和间访操作,以及结构变量作为函数的参数及返回值。 对结构变量中成员的引用则需要通过成员选择运算符“.”来实现。,2019/5/15,华中科技大学计算机学院,27,10.3.1 结构变量的引用 1结构变量的赋值操作,当两个结构变量的类型相同时,它们之间可以直接相互值。例如:struct planet char code8;char name10;short visible;double diameter;star1=
20、“12345“,“Venus“,1,9456.35;struct planet star2; 则star2=star1;是完全合法的赋值。 赋值操作的语义是将赋值号右端结构变量中各个成员的值一一照赋给赋值号左端结构变量的各个成员。 此时结构变量star2的成员code、name、visible、diameter的值依次为“12345“,“Venus“,1,9456.35,与star1的成员的值相同。,2019/5/15,华中科技大学计算机学院,28,2结构变量的取地址操作和间访操作,可以通过单目等价。,2019/5/15,华中科技大学计算机学院,29,10.3.2 通过成员选择运算符“.”访问
21、成员,C提供了成员选择运算符“.”构成的成员选择表达式来支持对成员的访问和操作。成员选择表达式的一般形式是:结构变量名. 成员名 其中,“.”是小数点或句号字符,称为成员选择运算符。 它是一个双目操作符,其左操作数是结构变量,右操作数是结构变量的成员。 “.”操作符具有最高优先级,由它构成的成员选择表达式在任何地方都是一个整体,表示对结构变量中成员的访问。,2019/5/15,华中科技大学计算机学院,30,设有声明语句:struct stu_study Li;下面的代码片段对struct stu_study类型的结构变量Li的各个成员进行格式化输入或赋值操作。,struct stu_study
22、 Li; . scanf(“%s“,Li.num); strcpy(Li.name,“Li Si“); Li.sex=m; Li.English=Li.Math=80; scanf(“%d“,2019/5/15,华中科技大学计算机学院,31,值得注意的是:,由于Li.num和Li.name都是字符数组名,其数据类型都是char *,因此必须用scanf函数、字符串拷贝函数strcpy或gets函数进行赋值操作。 Li.num=“678“;或Li.name=“Li Si“;都是错误的赋值方法。 但Li.num0=6; Li.num1=7 ;Li.num2=8; Li.num3= 0;是合法的赋值
23、操作。,2019/5/15,华中科技大学计算机学院,32,下面的语句输出结构变量Li的各个成员之值:,printf(“%st“,Li.num); printf(“%st“,Li.name); putchar(Li.sex); putchar(t); printf(“%dt%dt%dt%dn“,Li.English,Li.Math,Li.Physics,Li.C); 其中,putchar(t);是用于格式控制。,2019/5/15,华中科技大学计算机学院,33,10.3.3 嵌套结构的声明,C标准规定:结构变量的成员的数据类型还可以是除自身之外的其他结构类型。具有结构类型成员的结构类型称为嵌套结
24、构类型,具有结构类型成员的结构变量称为嵌套结构变量。 嵌套结构的声明要遵循先声明嵌套结构类型,再声明嵌套结构类型变量的原则。这种原则称为先声明后引用原则。在声明嵌套结构类型时,应该先声明结构类型成员的结构类型,再声明嵌套结构类型。,2019/5/15,华中科技大学计算机学院,34,例10-4 大学生基本信息嵌套结构类型的声明举例。,描述大学生基本信息需要学号、姓名、性别、出生日期、家庭住址、家庭收入、联系电话等属性。 可以先定义一个日期类型,再在大学生基本信息结构类型中引入日期类型的结构成员,用以描述出生日期. 然后再声明大学生基本信息结构类型的结构变量。,2019/5/15,华中科技大学计算
25、机学院,35,先声明日期类型,struct datechar month10;int day;int year;,2019/5/15,华中科技大学计算机学院,36,再声明大学生基本信息嵌套结构类型struct stu_info,struct stu_info char num12; /* 学号 */char name9; /* 姓名 */char sex; /* 性别 */struct date birthday; /* 出生日期 */char address60; /* 家庭住址 */double income; /* 家庭收入 */ char phone_number16; /* 联系电话
26、 */char email40; /* 电子邮箱 */; 其中,birthday是struct date类型的结构成员。此时,struct stu_info是一个嵌套的结构类型。 struct stu_info s; 声明了一个嵌套结构类型struct stu_info的结构变量s。,2019/5/15,华中科技大学计算机学院,37,例10.5 在嵌套结构类型声明的内部声明结构类型并声明结构类型成员,并且在声明嵌套结构类型时定义结构变量。,struct stu_info1 char num12; char name9; char sex;struct date1 char month10;in
27、t day;int year; birthday;char address60; double income; char phone_number16;char email40; s1,s2; 此时,struct date1结构类型在struct stu_info1嵌套结构类型内部声明,同时还声明了结构成员birthday。 并且在声明嵌套结构类型struct stu_info1的同时,声明了嵌套结构类型struct stu_info1的变量s1和s2。,2019/5/15,华中科技大学计算机学院,38,10.3.4 嵌套结构中结构成员的成员的访问,嵌套结构中由于包含结构成员,因此存在结构成员
28、的成员。对嵌套结构中结构成员的成员的访问采用“.”操作符,构成结构成员的成员选择表达式。 “.”操作符的使用个数与嵌套结构的层数相等。在两层嵌套结构中,结构成员的成员选择表达式的一般形式是:结构变量名.结构成员名.成员名 “.”操作符的结合性是从左至右,编译器对“结构变量名.结构成员名.成员名”理解为:(结构变量名.结构成员名).成员名。,2019/5/15,华中科技大学计算机学院,39,设有声明语句: struct stu_info zhang; 则下面是struct stu_info类型结构变量zhang的结构成员birthday的成员选择表达式:,zhang.birthday.month
29、 或 (zhang.birthday).month 月份成员,类型char *。 zhang.birthday.day 或 (zhang.birthday).day 日成员,类型int。 zhang.birthday.year 或 (zhang.birthday).year 年份成员,类型int。 成员选择表达式是左值表达式,使用时要根据其数据类型进行相关操作。 例如, zhang.birthday.day=12为正确的赋值操作。而zhang.birthday.month=“July“为非法赋值操作。,2019/5/15,华中科技大学计算机学院,40,例10.6 根据平面上点的结构类型构造平面
30、上线段的嵌套结构类型,说明对嵌套结构变量中结构成员的成员的引用,并求线段的长度。,#include “stdio.h“ #include “math.h“ struct point /* 平面上点的结构类型 */int x,y; /* x,y是点的坐标 */ ; struct line /* 平面上线段的嵌套结构类型 */char name6; /* 线段名称 */struct point start; /* 线段的起点 */struct point end; /* 线段的终点 */ ;,2019/5/15,华中科技大学计算机学院,41,void main(void) struct line
31、a=“abc“,1,1,10,10; /* 声明嵌套结构变量时对其初始化 */double dx2,dy2,length;printf(“line name is %sn“,a.name); /* 输出线段名称 */ /* 下面输出起点坐标和终点坐标 */printf(“starting point:(%d,%d)n“,a.start.x, a.start.y);printf(“end point:(%d,%d)n“,a.end.x, a.end.y);/* 下面对线段名称和起点坐标进行格式化输入赋值 */scanf(“%s“,a.name);scanf(“%d%d“, ,2019/5/15,
32、华中科技大学计算机学院,42,类似的,由平面上的一个点和不包含该点的直线可以构造一个平面,可以设计出由struct point结构类型和struct line结构类型构造出的含有三层嵌套的struct plain结构类型:,struct pointint x,y; ; struct linestruct point start,end; ; struct plainstruct point a;struct line l; ;,2019/5/15,华中科技大学计算机学院,43,声明三层嵌套的struct plain类型结构变量的声明语句如下:struct plain p=1,1,5,5,20,
33、15;该语句定义了struct plain类型的结构变量p,并对其进行了初始化。 下面语句表达了如何对嵌套结构变量中具有基本类型成员的进行操作:p.a.x=2; p.l.start.x=5;printf(“p.l.start.x=%dn“,p.l.start.x);scanf(“%d“, 可见,嵌套多少层,对基本类型成员的访问就需要多少个对应的“.”操作。同时,对基本类型成员进行操作时一定要符合其数据类型的要求。,2019/5/15,华中科技大学计算机学院,44,10.4 结构类型的指针,以结构类型为基类型可以派生出结构类型的指针。 结构类型的指针可以用于指向结构类型的变量。从而允许通过结构类
34、型的指针访问结构变量的成员。 结构类型的指针往往简称为结构指针。,2019/5/15,华中科技大学计算机学院,45,10.4.1 结构指针的声明和赋值,与结构变量的声明类似,结构指针的声明也有两种方式。 一是先声明结构类型,再声明结构指针。 另一种是在声明结构类型的同时声明结构指针。 例如,假设有如下关于IC卡的结构类型声明:struct IC_Card /* 声明IC卡的结构类型 */char name9; /* 持卡人姓名 */char account9; /* 持卡人账号 */char password7; /* 密码 */int balance; /* 账户余额 */;,2019/5/
35、15,华中科技大学计算机学院,46,下面的声明语句声明了一个struct IC_Card类型的结构指针:struct IC_Card *p; 也可以在声明IC卡的结构类型的同时声明结构指针。如:struct IC_Cardchar name9;char account9;char password7;int balance; *p;,2019/5/15,华中科技大学计算机学院,47,可以在声明结构指针是对其初始化,也可以先声明结构指针,然后通过对结构指针进行赋值操作使结构指针指向结构变量。 下面的代码片段对结构指针进行初始化:struct IC_Cardchar name20;char acc
36、ount9;char password7;int balance;a,*p= 它在声明结构类型的同时,声明了结构变量a和结构指针p,并通过&a取出结构变量a的地址然后对结构指针p进行初始化。,2019/5/15,华中科技大学计算机学院,48,也可以:struct IC_Card b,*pb=效果完全一样。pb的类型是struct IC_Card *,基类型是struct IC_Card,pb能够且只能够指向struct IC_Card类型的结构变量。,2019/5/15,华中科技大学计算机学院,49,10.4.2 通过“*”用结构指针访问结构变量的成员,通过间访操作符*访问结构指针所指的结构变
37、量的表达式的一般形式是:* 结构指针它表示通过结构指针来访问结构指针所指的结构变量。该表达式的值是指针所指的结构变量的值,表达式的类型是指针所指的结构变量的类型。 访问结构指针所指结构变量的成员的表达式的一般形式是:(*结构指针).成员名它表示先通过*操作访问结构指针所指结构变量,再通过.操作访问结构指针所指结构变量的成员。 注意: (*结构指针).成员名中的括号不能省略!,2019/5/15,华中科技大学计算机学院,50,根据上面所声明的IC_Card结构类型,设有声明:struct IC_Card a,b=“zhang hua“,“12345678“,“234567“,1000;struc
38、t IC_Card *pa= 与a=b等价,,2019/5/15,华中科技大学计算机学院,51,下面的语句对指针pa所指结构变量a的各个成员输入赋值:,scanf(“%s“,(*pa).name);scanf(“%s“,(*pa).account);scanf(“%s“,(*pa).password);scanf(“%d“, (*pa).name、(*pa).account和(*pa).password的数据类型都是char *,分别表示指向姓名、账号和密码的字符指针。&(*pa).balance表示成员balance的地址,其操作顺序是先执行*操作,再执行.操作,最后执行&操作。,2019/
39、5/15,华中科技大学计算机学院,52,下面的语句输出指针pa所指结构变量a的各个成员的值:,printf(“(*pa).name=%st“,(*pa).name); printf(“(*pa).account=%sn“,(*pa).account); printf(“(*pa).password=%st“,(*pa).password); printf(“(*pa).balance=%dn“,(*pa).balance); 同理,gets(*pa).name);和strcpy(*pa).account, “54321“);都是对结构变量a的字符数组成员的正确输入。,2019/5/15,华中科
40、技大学计算机学院,53,(*pa).balance=12345;是对结构变量a的balance成员的正确赋值。 (*pa).name0=c;和*(*pa).name=c; 是对a的name0的正确赋值。 *(*pa).account+2)= 6; 是对a的account2的正确赋值。 +*(*pa).account+3);和(*(*pa).account+3)+;都是对a的account3的正确自增操作。 而*(*pa).account+3)+; 属非法赋值操作。因为+虽然是后缀+,但它作用到表达式(*pa).account+3)上,而(*pa).account+3)不是左值表达式,因此操作非
41、法。 同理,(*pa).password=“12011“;也属于非法赋值操作。,2019/5/15,华中科技大学计算机学院,54,10.4.3 通过成员选择运算符“-”访问结构变量的成员,C提供了另外一种结构成员选择运算符“-”实现对结构变量的成员简洁高效的引用。“-”由一个减号和紧跟的大于号组成,C将其作为单个运算符处理。用“-” 访问结构变量的成员的成员选择表达式的一般形式是:结构指针名-结构成员名 它表示引用结构指针所指结构变量的成员。“-”是双目运算符,它与“.”、“()”、“”一样具有最高优先级,结合性为左结合。 “-”的左操作数应该是结构类型的指针,而右操作数为结构指针所指结构变量
42、的成员。 此处的结构成员名为结构变量的成员名。为了简化起见,在不产生二义的情况下,简称结构变量的成员为结构成员。 结构指针名-结构成员名是一个表达式,其值为结构成员的值,其类型为结构成员值的数据类型。,2019/5/15,华中科技大学计算机学院,55,设有多种类型成员的嵌套结构类型声明如下: struct dateint year;char month12;short day; ; struct mul_typechar c;int n;float d;char s12;char * ps;struct date a;struct date *pa; m=a,100,3.14f,“myabcd
43、efg“,m.s,2007,“July“, 29, ,2019/5/15,华中科技大学计算机学院,56,下面的语句输出结构变量m的非结构类型成员之值:,printf(“%ct”,pm-c); 与printf(“%cn“,m.c); 等价,pm-c类型为char。 printf(“%dt”,pm-n); 与printf(“%dn“,m.n); 等价,pm-n类型为int。 printf(“%ft”,pm-d); 与printf(“%fn“,m.d); 等价,pm-d类型为float。 printf(“%st”,pm-s); 与printf(“%sn“,m.s); 等价,pm-s类型为char *
44、。 printf(“%st”,pm-ps); 与printf(“%sn“,m.ps); 等价,pm-ps类型为char *。,2019/5/15,华中科技大学计算机学院,57,下面8个表达式都表示对指针pm所指变量的结构成员m的年份成员year的引用:,pm-pa-year m.a.year (*pm).pa-year m.pa-yearpm-a.year (*pm-pa).year (*m.pa).year (*(*pm).pa).year; 它们的数据类型都是int型,值则由成员year的值决定。,2019/5/15,华中科技大学计算机学院,58,类似的,对指针pm所指变量的结构成员m的月
45、份成员month的8种引用为:,pm-pa-month m.a.month(*pm).pa-month m.pa-monthpm-a.month (*m.pa).month(*pm-pa).month (*(*pm).pa).month 它们的类型都是char *,,2019/5/15,华中科技大学计算机学院,59,通过下标运算符“”或间访运算符“*”还可以对s字符数组中的元素进行操作。,如: pm-pa-month2= n; 和 m.a.month3=e; 而 *pm-ps+;和(*pm-ps)+;含义完全不同。根据优先级和结合性,表达式*pm-ps+先做pm-ps,再对pm-ps做*操作,
46、结果是访问m.s0,表达式的值是a,类型是char;然后再做后缀+操作,使ps指向m.s1,+作用在ps上。而表达式(*pm-ps)+ 先做pm-ps,再对pm-ps做*操作,最后进行+操作。结果是访问m.s0,该表达式将m.s0的值由m更新为n,类型是char。+作用在m.s0上。,2019/5/15,华中科技大学计算机学院,60,结论:当“-”、“.”、“*”、前缀或后缀+和出现在同一个表达式中的时候,对表达式求值的理解极容易混淆出错。唯一的法宝是严格按照运算符的优先级和结合性,以及前缀+、前缀-、后缀+、后缀的操作语义所确定的顺序,逐步的进行分析和解释,才能正确判断表达式是合法还是非法,
47、才能正确计算出对合法表达式的求值结果。 设有: struct Tint n;char *pm; s=10,“abcdef“,*p=则表10.1给出了有关表达式的正确理解及等价表达式。,2019/5/15,华中科技大学计算机学院,61,表10.1 有关表达式的正确理解及等价表达式 (讲解p335),2019/5/15,华中科技大学计算机学院,62,10.5 结构类型作为函数的参数和返回值,结构类型的变量或结构类型的指针都可以作为函数的参数或者函数的返回值。 结构变量的成员,指向结构变量的成员的指针也可以作为函数的参数或函数的返回值。 对于一个物理量而言,不仅有大小,还有量纲,其声明如下:stru
48、ct motion double size; /* 物理量的大小 */char dimension12; /* 物理量的量纲 */;,2019/5/15,华中科技大学计算机学院,63,10.5.1 结构成员或结构变量作为函数的参数,1) 结构成员作为函数的参数 结构成员作为函数的参数时,形参的声明与其他基本类型的变量一样。 例如对2个物理量,假设量纲已经相同,因此可以进行物理量大小的相加操作。对应函数原型声明如下:double add_motion_size(double,double);add_motion_size函数的实现见例10.7 p340设有声明:struct motion b=1
49、2.5,“m/s“,c=26.7,“m/s“,d; 则调用该函数的代码为:d.size=add_motion_size(b.size,c.size);,2019/5/15,华中科技大学计算机学院,64,2) 结构变量作为函数的参数,结构变量作为函数的参数时,形参应该声明为结构类型的形参,实参则应该为相同类型的结构变量。 声明函数原型的一般形式为:存储类型 返回值类型 函数名(形参列表);形参列表的一般形式是:struct 结构类型名1 a1, , struct 结构类型名n an,其它基本类型的形参声明 即形参a1,an前面都要分别加struct 结构类型名1,, struct 结构类型名n 以表示a1是struct结构类型名1类型的形参,而an是struct 结构类型名n类型的形参。 结构类型名1和结构类型名n可以相同,也可以不同。其它基本类型的形参声明与一般函数相同.,