Download presentation
Presentation is loading. Please wait.
1
第13章 结构体的应用 13.1 了解由用户构造的数据类型 13.2 结构体类型说明及结构体变量 13.3 结构体数组
第13章 结构体的应用 13.1 了解由用户构造的数据类型 13.2 结构体类型说明及结构体变量 13.3 结构体数组 13.4 函数之间结构体类型的数据传递 13.5 利用结构体变量构成静态链表 13.6 利用指针处理动态链表
2
13.1 了解由用户构造的数据类型 可以由用户构造的数 据类型 用typedef定义类型名
3
13.2 结构体类型说明及结构体变量 13.2.1 结构体类型的说明 13.2.2 结构体变量的定义 13.2.3 结构体变量的初始化
13.2 结构体类型说明及结构体变量 结构体类型的说明 结构体变量的定义 结构体变量的初始化 结构体变量中成员的 访问
4
13.3 结构体数组 从例13.1中可以看出,利用结构体变量只能存放一名学生的信息。若要保存多名学生的信息就要使用结构体类型的数组。 结构体数组的定义 定义结构体数组的方法和定义结构体变量的方法一样:可以先说明结构体类型,再用类型名定义数组;也可以在说明类型的同时定义数组。例如:
5
struct student { int num; char name[9]; char sex; struct date birthday; float score[3]; }; struct student pers[3];
6
也可以采用以下形式: typedef struct { int num; char name[9]; char sex; struct { int year, month, day ;} birthday; float score[3]; }STU; STU pers[3];
7
以上两种形式都是先说明了类型名(struct student或STU),再用类型名定义了具有3个元素的结构体数组pers。
若要直接定义结构体数组,可以采用以下两种形式:
9
结构体数组pers中的每个元素都是一个结构体类型,如图13-3所示。它们在内存中也占据着连续的存储单元。
10
13.3.2 结构体数组的初始化 和其他类型的数组一样,结构体数组也可以在定义的同时进行初始化。例如:
结构体数组的初始化 和其他类型的数组一样,结构体数组也可以在定义的同时进行初始化。例如: struct student pers[3]={ {1,"Zhanghua",'M',1961,10,8,76.5,78.0,82.0}, {2,"Wangwei",'F',1960,12,20,70.0,85.5,76.0}, {3,"Liming", 'M',1961,3,16,80.0,84.5,91.0} };
11
可以看出:所赋初值是放在一对花括号中的。为了清晰,每个元素的值又分别用一对花括号括起,中间以逗号分隔。数组pers赋初值后的情况如图13-4所示。
12
图13-4 数组pers赋初值后的示意图
13
在定义结构体数组时,也可以不指定元素的个数,而通过初值的个数决定数组的大小。形式如下:
struct student test[ ]={ {…},{…},{…},{…} }; 这时编译系统会根据初值的个数,判定出数组test有4个元素。
14
结构体数组的应用 结构体数组中有若干个元素,每个元素中都包含有各自的成员,应该采用什么样的形式去引用它们呢?事实上,只要把数组元素看作是带有下标的变量,就可以沿用13.2.4中介绍的成员引用方法: 结构体变量名.成员名 此处可理解为: 结构体数组元素.成员名
15
结合图13.4可以看出: pers[0].num 表示的是数组第1个元素中值为1的num成员 pers[1].sex 表示的是数组第2个元素中值为F的sex成员 pers[2].birthday.year 表示的是数组第3个元素中的结构体birthday中的year成员
16
13.4 函数之间结构体类型的数据传递 13.4.1 结构体变量的成员作实参
13.4 函数之间结构体类型的数据传递 结构体变量的成员作实参 结构体变量的成员作实参时,参数的传递情况取决于该成员本身的数据类型。如果作为实参传送的这一成员是简单变量,相应的形参应该是同类型的简单变量;如果作为实参传送的成员是数组名,对应的形参就必须是基类型相同的指针变量。
17
例13.4 结构体变量的成员作实参。 #include <stdio.h> typedef struct { int num; char name[9]; char sex; struct { int year,month,day ;} birthday; float score[3]; }STU;
18
void fun1(char *name) /* 形参为字符型指针 */ { printf("%9s",name); } void fun2(int y) /* 形参为整型变量 */ { printf("%5d",y); } void fun3(float *s) /* 形参为单精度型指针 */
19
{ int i; for(i=0; i<3; i++) printf("%5.1f",s[i]); printf("\n"); } main( ) { STU std={ 1,"Zhanghua",'M',1961,10,8,76.5,78.0,82.0 };
20
fun1(std.name); /* 相当于字符型数组名作实参 */ fun2(std.birthday.year); /* 相当于整型变量作实参 */ fun3(std.score); /* 相当于单精度型数组名作实参 */ } 程序的输出结果是: Zhanghua
21
结构体变量作形参 结构体变量可以作为一个整体传递给相应的形参。根据“按值”传递的原则,这时传给形参的是结构体变量的值。因此,形参必须是同类型的结构体变量。系统将为形参开辟临时存储单元,用以存放结构体中各成员的值。
22
例13.5 结构体变量作形参。 以下程序通过定义并赋初值的方式,利用结构体变量存储了一名学生的信息,通过调用函数show输出其内容。 源程序如下:
23
#include <stdio.h>
typedef struct { int num; char name[9]; char sex; struct { int year,month,day ;} birthday; float score[3]; }STU;
24
void show(STU tt) /* 形参是同类型的结构体变量 */ { int i; printf("%d %s %c %d–%d–%d", tt.num,tt.name,tt.sex, tt.birthday.year,tt.birthday.month,tt.birthday.day); for(i=0; i<3; i++) printf("%5.1f",tt.score[i]); printf("\n"); }
25
main( ) { STU std={ 1,"Zhanghua",'M',1961,10,8,76.5,78.0,82.0 }; show(std); /* 结构体变量作实参 */ } 程序的运行结果如下: 1 Zhanghua M
26
结构体变量的地址作实参 如果需要在某个函数中改变实参的值,就一定要传地址。当实参是结构体变量的地址时,对应的形参应该是同一结构体类型的指针变量。
27
例13.6 在例13.5的基础上增加一个函数modify,用以将学生的各科成绩乘以一个系数,然后再调用show函数输出。
源程序如下: #include <stdio.h> typedef struct { int num; char name[9]; char sex; struct { int year,month,day ;} birthday; float score[3]; }STU;
28
void show(STU tt) { int i; printf("%d %s %c %d–%d–%d", tt.num,tt.name,tt.sex, tt.birthday.year,tt.birthday.month,tt.birthday.day); for(i=0; i<3; i++) printf("%5.1f",tt.score[i]); printf("\n"); }
29
void modify(STU *ss,float a)
{ int i; for(i=0; i<3; i++) ss–>score[i]*=a; /* 用指针ss引用结构体成员 */ }
30
main( ) { STU std={ 1,"Zhanghua",'M',1961,10,8,76.5,78.0,82.0 }; float a; printf("请输入系数值: "); scanf("%f",&a); modify(&std,a); /* 结构体变量的地址作实参 */
31
printf("修改后的学生数据如下:\n");
show(std); } 程序运行情况如下: 请输入系数值:0.8 修改后的学生数据如下: 1 Zhanghua M
32
结构体数组名作实参 结构体数组名作实参,传递的是数组的首地址,相应的形参应该是同一结构体类型的指针。这一情况同8.4.2介绍的一维数组名作实参是类似的,区别仅在于结构体数组中的每个元素都是一个结构体类型的数据。
33
例13.7 计算平均分,输出成绩单。设有如下定义:
typedef struct { int num; char name[9]; float score[3]; float ave; }STD;
34
编写函数 void fun1(STD s[ ],int n),用来计算s所指数组中每位学生3门课的平均分,存入相应的ave成员中。形参n代表学生人数。
编写函数 void fun2(STD x[ ],int n) 输出成绩单。 在主函数中,利用四名学生的信息进行调试。
35
源程序如下: void fun1(STD s[], int n) { int i,j; float sum; for(i=0; i<n; i++) /* 计算每位学生的平均分 */ { sum=0.0; for(j=0; j<3; j++) sum=sum+s[i].score[j]; s[i].ave=sum/3; }
36
void fun2(STD x[],int n) { int i,j; printf(" num name scor1 scor2 scor3 ave\n"); /* 输出成绩单 */ for(i=0; i<n; i++) { printf("%3d %6s ",x[i].num,x[i].name); for(j=0; j<3; j++) printf("%5.1f ",x[i].score[j]); printf("%5.1f\n",x[i].ave); }
37
main( ) { STD x[4]={ 1,"Limi",60,67,76,0.0, 2,"Mali",73,81,69,0.0, 3,"Qiyin",86,75,82,0.0, 4,"Jake",66,85,72,0.0}; /* 初始化时存放平均分的成员值为0.0 */ fun1(x,4); fun2(x,4); }
38
程序的运行结果如下: num name scor1 scor2 scor3 ave 1 Limi 2 Mali 3 Qiyin 4 Jake
39
13.5 利用结构体变量构成静态链表 构成单向链表的结点结构 静态链表
40
13.6 利用指针处理动态链表 13.6.1 动态链表的概念 13.6.2 动态生成和释放结点所需 的函数
13.6 利用指针处理动态链表 动态链表的概念 动态生成和释放结点所需 的函数 动态链表的建立和输出 链表中结点的删除 链表中结点的插入
Similar presentations