400 likes | 595 Views
第13章 结构体的应用. 13.1 了解由用户构造的数据类型 13.2 结构体类型说明及结构体变量 13.3 结构体数组 13.4 函数之间结构体类型的数据传递 13.5 利用结构体变量构成静态链表 13.6 利用指针处理动态链表. 13.1 了解由用户构造的数据类型. 13.1.1 可以由用户构造的数据类型 13.1.2 用 typedef 定义类型名. 13.2 结构体类型说明及结构体变量. 13.2.1 结构体类型的说明 13.2.2 结构体变量的定义 13.2.3 结构体变量的初始化 13.2.4 结构体变量中成员的访问.
E N D
第13章 结构体的应用 • 13.1 了解由用户构造的数据类型 • 13.2 结构体类型说明及结构体变量 • 13.3 结构体数组 • 13.4 函数之间结构体类型的数据传递 • 13.5 利用结构体变量构成静态链表 • 13.6 利用指针处理动态链表
13.1 了解由用户构造的数据类型 • 13.1.1 可以由用户构造的数据类型 • 13.1.2 用typedef定义类型名
13.2 结构体类型说明及结构体变量 • 13.2.1 结构体类型的说明 • 13.2.2 结构体变量的定义 • 13.2.3 结构体变量的初始化 • 13.2.4 结构体变量中成员的访问
13.3 结构体数组 • 从例13.1中可以看出,利用结构体变量只能存放一名学生的信息。若要保存多名学生的信息就要使用结构体类型的数组。 • 13.3.1 结构体数组的定义 • 定义结构体数组的方法和定义结构体变量的方法一样:可以先说明结构体类型,再用类型名定义数组;也可以在说明类型的同时定义数组。例如:
struct student • { int num; • char name[9]; • char sex; • struct date birthday; • float score[3]; • }; • struct student pers[3];
也可以采用以下形式: • typedef struct • { int num; • char name[9]; • char sex; • struct { int year, month, day ;} birthday; • float score[3]; • }STU; • STU pers[3];
以上两种形式都是先说明了类型名(struct student或STU),再用类型名定义了具有3个元素的结构体数组pers。 • 若要直接定义结构体数组,可以采用以下两种形式:
结构体数组pers中的每个元素都是一个结构体类型,如图13-3所示。它们在内存中也占据着连续的存储单元。 结构体数组pers中的每个元素都是一个结构体类型,如图13-3所示。它们在内存中也占据着连续的存储单元。 图13-3 数组pers 的结构示意图
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} };
可以看出:所赋初值是放在一对花括号中的。为了清晰,每个元素的值又分别用一对花括号括起,中间以逗号分隔。数组pers赋初值后的情况如图13-4所示。 可以看出:所赋初值是放在一对花括号中的。为了清晰,每个元素的值又分别用一对花括号括起,中间以逗号分隔。数组pers赋初值后的情况如图13-4所示。
在定义结构体数组时,也可以不指定元素的个数,而通过初值的个数决定数组的大小。形式如下:在定义结构体数组时,也可以不指定元素的个数,而通过初值的个数决定数组的大小。形式如下: • struct student test[ ]={ {…},{…},{…},{…} }; • 这时编译系统会根据初值的个数,判定出数组test有4个元素。
13.3.3 结构体数组的应用 • 结构体数组中有若干个元素,每个元素中都包含有各自的成员,应该采用什么样的形式去引用它们呢?事实上,只要把数组元素看作是带有下标的变量,就可以沿用13.2.4中介绍的成员引用方法: • 结构体变量名.成员名 • 此处可理解为: • 结构体数组元素.成员名
结合图13.4可以看出: • pers[0].num • 表示的是数组第1个元素中值为1的num成员 • pers[1].sex • 表示的是数组第2个元素中值为F的sex成员 • pers[2].birthday.year • 表示的是数组第3个元素中的结构体birthday中的year成员
13.4 函数之间结构体类型的数据传递 • 13.4.1 结构体变量的成员作实参 • 结构体变量的成员作实参时,参数的传递情况取决于该成员本身的数据类型。如果作为实参传送的这一成员是简单变量,相应的形参应该是同类型的简单变量;如果作为实参传送的成员是数组名,对应的形参就必须是基类型相同的指针变量。
例13.4 结构体变量的成员作实参。 • #include <stdio.h> • typedef struct • { int num; • char name[9]; • char sex; • struct { int year,month,day ;} birthday; • float score[3]; • }STU;
void fun1(char *name) • /* 形参为字符型指针 */ • { printf("%9s",name); } • void fun2(int y) • /* 形参为整型变量 */ • { printf("%5d",y); } • void fun3(float *s) • /* 形参为单精度型指针 */
{ 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 };
fun1(std.name); • /* 相当于字符型数组名作实参 */ • fun2(std.birthday.year); • /* 相当于整型变量作实参 */ • fun3(std.score); • /* 相当于单精度型数组名作实参 */ • } • 程序的输出结果是: • Zhanghua 1961 76.5 78.0 82.0
13.4.2 结构体变量作形参 • 结构体变量可以作为一个整体传递给相应的形参。根据“按值”传递的原则,这时传给形参的是结构体变量的值。因此,形参必须是同类型的结构体变量。系统将为形参开辟临时存储单元,用以存放结构体中各成员的值。
例13.5 结构体变量作形参。 • 以下程序通过定义并赋初值的方式,利用结构体变量存储了一名学生的信息,通过调用函数show输出其内容。 • 源程序如下:
#include <stdio.h> • typedef struct • { int num; • char name[9]; • char sex; • struct { int year,month,day ;} birthday; • float score[3]; • }STU;
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"); • }
main( ) • { STU std={ • 1,"Zhanghua",'M',1961,10,8,76.5,78.0,82.0 }; • show(std); /* 结构体变量作实参 */ • } • 程序的运行结果如下: • 1 Zhanghua M 1961-10-8 76.5 78.0 82.0
13.4.3 结构体变量的地址作实参 • 如果需要在某个函数中改变实参的值,就一定要传地址。当实参是结构体变量的地址时,对应的形参应该是同一结构体类型的指针变量。
例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;
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"); • }
void modify(STU *ss,float a) • /* 形参ss为同类型的指针 */ • { int i; • for(i=0; i<3; i++) • ss–>score[i]*=a; • /* 用指针ss引用结构体成员 */ • }
main( ) • { STU std={ • 1,"Zhanghua",'M',1961,10,8,76.5,78.0,82.0 }; • float a; • printf("请输入系数值: "); • scanf("%f",&a); • modify(&std,a); • /* 结构体变量的地址作实参 */
printf("修改后的学生数据如下:\n"); • show(std); • } • 程序运行情况如下: • 请输入系数值:0.8 • 修改后的学生数据如下: • 1 Zhanghua M 1961-10-8 61.2 62.4 65.6
13.4.4 结构体数组名作实参 • 结构体数组名作实参,传递的是数组的首地址,相应的形参应该是同一结构体类型的指针。这一情况同8.4.2介绍的一维数组名作实参是类似的,区别仅在于结构体数组中的每个元素都是一个结构体类型的数据。
例13.7 计算平均分,输出成绩单。设有如下定义: • typedef struct • { int num; • char name[9]; • float score[3]; • float ave; • }STD;
编写函数 void fun1(STD s[ ],int n),用来计算s所指数组中每位学生3门课的平均分,存入相应的ave成员中。形参n代表学生人数。 • 编写函数 void fun2(STD x[ ],int n) 输出成绩单。 • 在主函数中,利用四名学生的信息进行调试。
源程序如下: • 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; • } • }
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); • } • }
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); • }
程序的运行结果如下: • num name scor1 scor2 scor3 ave • 1 Limi 60.0 67.0 76.0 67.7 • 2 Mali 73.0 81.0 69.0 74.3 • 3 Qiyin 86.0 75.0 82.0 81.0 • 4 Jake 66.0 85.0 72.0 74.3
13.5 利用结构体变量构成静态链表 • 13.5.1 构成单向链表的结点结构 • 13.5.2 静态链表
13.6 利用指针处理动态链表 • 13.6.1 动态链表的概念 • 13.6.2 动态生成和释放结点所需的函数 • 13.6.3 动态链表的建立和输出 • 13.6.4 链表中结点的删除 • 13.6.5 链表中结点的插入