710 likes | 896 Views
第 9 章 结构体及其应用. 9.1 一个程序实例 9.2 结构体类型的使用 9.3 链表 9.4 结构体应用实例 9.5 本章小结 9.6 实训 习题 9. 9.1 一个程序实例.
E N D
第 9 章 结构体及其应用 • 9.1 一个程序实例 • 9.2 结构体类型的使用 • 9.3 链表 • 9.4 结构体应用实例 • 9.5 本章小结 • 9.6 实训 • 习题 9
9.1 一个程序实例 • 通过前面的学习,我们了解到相同类型的一组数据可用数组存放。而现实生活中经常需要处理一些数据类型不同,而又相互关联的一组数据,例如,一个学生的个人信息(有学号、姓名、性别、年龄、住址、成绩等数据项) ,一本图书的信息(有分类编号、书名、作者、出版社、出版日期、价格、库存量等数据项) ,在描述这些数据类型不同、但是同一个学生或同一本书的信息时,简单变量或数组都显得力不从心。那么如何描述这些类型不同的相关数据呢? • C语言提供了将不同类型数据组合到一起的方法,这就是结构体类型(structure) 。 • 【例 − 】一个学生的信息包括学号、姓名、平时成绩、期末成绩和总评成绩,其中总评成绩的计算公式为: • 总评成绩=平时成绩×30%+期末成绩×70% • 根据给定的平时成绩和期末成绩计算该生总评成绩,并输出学生的信息。 下一页 返回
9.1 一个程序实例 • 【编程思路】 • 本实例中学生的信息包含 5 个数据项,这些数据项具有内在的联系(同属于一个学生) ,然而数据类型却不尽相同。面对这种情况,C 语言允许编程者自己构造一种数据类型——结构体类型,把多个数据项(类型可以相同也可以不相同)组合在一起,作为一个整体进行处理。 • 根据本题的情况,用以下形式构造名为 student 的结构体类型。 • struct student /*student 为结构体类型名*/ • { int num; /*存放学号,为int型*/ • char name[10] /*存放姓名,用字符数组*/ • float s1,s2,score; /*存放3个成绩,为float型*/ • }; 上一页 下一页 返回
9.1 一个程序实例 • struct student 是一种结构体类型,它由 5 个数据项组成,此处的数据项称为结构体成员或者域。接下来可以用 struct student 这个数据类型定义变量,只有变量才能存储数据。 • 例如,下面语句定义了一个结构体变量: • struct student wang; • 结构体变量 wang 包括学号、姓名、平时成绩、期末成绩和总评成绩等 5 个成员。程序中结构体变量不能整体引用,要引用到其中的成员。 • 结构体变量中成员的引用形式为:结构体变量.成员名。比如:wang.num、wang.name、wang.s1 等。结构体成员在程序中的作用和用法与普通变量相同。 上一页 下一页 返回
9.1 一个程序实例 • 【程序代码】 • #include <stdio.h> • #include <string.h> • struct student /*定义结构体类型*/ • { • int num; • char name[10]; • float s1,s2,score; • }; • main() • { • struct student wang; /*定义结构体变量*/ • /*以下给变量名为wang 的学生赋值*/ 上一页 下一页 返回
9.1 一个程序实例 • wang.num=101; • strcpy(wang.name,"wanghai"); • wang.s1=92.0; • wang.s2=87.5; • wang.score=wang.s1*0.3+wang.s2*0.7; /*计算总评成绩*/ • /*以下输出该学生信息*/ • printf("NO.:%d\n",wang.num); • printf("NAME:%s\n",wang.name); • printf("s1=%7.2f,s2=%7.2f,score=%7.2f\n\n",wang.s1,wang.s2,wang.score); • } • 程序输出结果为: 上一页 返回
9.2 结构体类型的使用 • 结构体类型是一种用户自定义的构造类型。使用时,必须先定义结构体类型,然后再用其类型定义结构体变量。 • 9.2.1 结构体类型的定义 • 定义结构体类型的一般形式为: • struct 结构体类型名 • { • 类型名1 成员名1; • 类型名2 成员名2; • …… • 类型名1 成员名1; • }; 下一页 返回
9.2 结构体类型的使用 • 例如: • struct stud • { int num; • char name[20]; • char sex; • int age; • float score[3]; • char address[30]; • }; • 说明: • (1)struct 是关键字,标志结构体类型。struct 后面是所定义的结构体类型的名字,结构体名应符合标识符的命名规则。这里结构体名可以省略,省略后将成为无名结构体。 上一页 下一页 返回
9.2 结构体类型的使用 • (2)结构体的各个成员用花括号括起来,结构体成员的定义方式和变量的定义方式一样,成员名的命名规则和变量相同;各成员之间用分号分隔;结构体类型的定义以分号结束。 • (3)结构体成员的数据类型可以是基本类型的,也可以是构造类型,如数组或其他结构体类型。 • 9.2.2 结构体变量的定义及引用 • 有了结构体数据类型,接下来需要定义结构体类型变量,以便存放结构体类型的数据。 • 1.结构体变量的定义 • C 语言中,结构体变量定义可以采取三种方法。 • (1)先声明结构体类型再定义变量名。 上一页 下一页 返回
9.2 结构体类型的使用 • 例如: • struct stud /*定义结构体类型*/ • { int num; • char name[20]; • char sex; • int age; • float score[3]; • char address[30]; • }; • struct stud student1,student2; /*定义结构体变量*/ • 以上定义了两个结构体变量 student1 和 student2, 它们均包含 6 个成员: 编号、姓名、性别、年龄、3 门课成绩和地址。 上一页 下一页 返回
9.2 结构体类型的使用 • 与普通变量一样,结构体变量也可以通过初始化赋值。例如: • struct stud student1={101,"ghz",'M',18,75.4,89.3,92.5,"xian"}; struct stud student2={102,"xhy",'M',16,95.1,99,92,"beijing"}; 结构体变量 student1 和 student2 中各成员的赋值情况如图 9−1 所示。 • 注意:上面定义的结构体类型有 6 个成员,而赋值的时候有 8 项数据,原因是第 5 个成员 score 是数组,它有 3 个元素,用来存放 3 门课成绩。 从图 9−1 中可以看到,各成员分配在连续的存储区域内,而且各个成员所占的字节数之和就是结构体变量的字节数。 • (2)定义结构体类型的同时定义结构体变量。 上一页 下一页 返回
9.2 结构体类型的使用 • 这种方法定义的一般形式为: • struct 结构体名 • { • 成员表列 • }变量名表列; • 例如,上面的结构体类型 struct stud 也可以采取以下形式定义: • struct stud • { int num; • char name[20]; • char sex; • int age; • float score[3]; • char address[30]; • } student1={101,"ghz",'M',18,75.4,89.3,92.5,"xian"},student2; 上一页 下一页 返回
9.2 结构体类型的使用 • (3)定义无名结构体类型的同时定义结构体变量(即不出现结构体名) 一般定义形式为: • struct • { • 成员表列 • }变量名表列; • 例如: • struct • { int num; • char name[20]; • char sex; • int age; • float score[3]; • char address[30]; • }student1,student2; 上一页 下一页 返回
9.2 结构体类型的使用 • 2. 结构体变量的引用 • (1)结构体变量中成员的引用。 • 结构体变量本身不能代表一个特定的值,只有它的成员才会有特定的值。因此使用结构体变量时,要引用其成员。 • 结构体变量中成员的引用形式是: • 结构体变量.成员名 • 例如,结构体变量 student1 中各个成员引用形式如下: • student1.num、student1.name、student1.sex、student1.age、student1.address • student1.score[0]、student1.score[1]、student1.score[2] 上一页 下一页 返回
9.2 结构体类型的使用 • 结构体中成员的作用与地位相当于普通变量,因此可以进行与普通变量一样的操作,比如赋值、输入输出等,例如有以下语句: • student1.num=101; • scanf(“%d”,&student1.num); • printf("%d \n",student1.num); • distance=student1.age- student2.age; • (2)同类型结构体变量可以相互赋值。 • 对结构体变量不能整体引用,但同类型结构体变量之间可以相互赋值。 • 【例 − 】结构体变量的引用。 • #include <stdio.h> • struct stud /*定义结构体类型stud*/ • { 上一页 下一页 返回
9.2 结构体类型的使用 • char xm[10]; • int age; • }; • void main() • { • struct stud stu1,stu2; /*定义结构体变量*/ • scanf("%s %d",stu1.xm,&stu1.age); /*结构体变量引用到成员*/ • printf("stu1-->%s:%d\n",stu1.xm,stu1.age); /*结构体变量引用到成员*/ • stu2=stu1; /* 把变量stu1各成员的值赋给变量stu2的相应成员*/ • printf("stu2---%s:%d\n",stu2.xm,stu2.age); /*结构体变量引用到成员*/ • } 程序运行时输入“zhangsan 20” ,输出结果为: 上一页 下一页 返回
9.2 结构体类型的使用 • 3. 结构体类型嵌套 • 以上给出的例子中,结构体成员的类型都是基本类型和数组类型。实际上,成员的类型可以是任何数据类型。下面给出成员类型是另一个结构体类型的例子。 • 例如: struct date /*日期结构*/ • { • int year; • int month; • int day; • }; • struct student 上一页 下一页 返回
9.2 结构体类型的使用 • { int num; • char name[20]; • char sex; • int age; • struct date birthday; /* struct date 为结构体类型*/ • char address[30]; • }stu={102,"xhy",'M',16,1977,5,8,"beijing"}; • 上例中结构体变量 stu 的存储结构如图 9−2 所示。 当成员本身又属于一个结构体类型,引用时要逐级找到最低一级成员,只能对最低级的成员进行赋值或存取操作。 例如,对上面定义的结构体变量 stu,可以这样访问其中的日期成员: • stu. birthday. year • stu.birthday.month • stu.birthday. day 上一页 下一页 返回
9.2 结构体类型的使用 • 9.2.3 结构体数组 • 在例 9−1 中一个结构体变量只能处理一个人的信息(如一个学生的学号、姓名、成绩等数据) 。但在实际应用中经常需要处理一批人的信息,这时应该使用结构体类型的数组。 • 定义结构体数组与定义结构体变量的方法相同。例如: • struct student • { • int num; • char name[20]; • char sex; • int age; • float score[3]; • char address[30]; • } stu[3]; 上一页 下一页 返回
9.2 结构体类型的使用 • 以上定义了一个数组 stu, 它有 3 个元素 stu[0]、 stu[1]、 stu[2], 类型均为 struct student 类型。 结构体数组中成员的引用方式与结构体变量相同, 下面以元素 stu[0]为例,给出各个成员的引用形式: • stu[0].num、stu[0].name、stu[0].sex、stu[0].age stu[0].address • stu[0].score[0]、stu[0].score[1]、stu[0].score[2] • 可见,结构体数组元素也是通过数组名和下标来引用的。因为各个元素都是结构体类型,因此对结构体数组元素的引用与对结构体变量的引用一样,也要逐级引用,只能对最低的成员进行存取和运算。 • 【例 − 】候选人得票统计程序。设有 3 个候选人,10 个投票人,输入得票人的名字并进行统计,最后输出各人得票结果。 上一页 下一页 返回
9.2 结构体类型的使用 • #include <string.h> • #include <stdio.h> • struct person • { • char name[20]; /*候选人姓名*/ • int count; /*候选人票数*/ • }leader[3]={"star",0,"mery",0,"sun",0}; /*定义结构体数组并初始化*/ • main() • { • int i,j; • char leader_name[20]; • for(i=1;i<=10;i++) 上一页 下一页 返回
9.2 结构体类型的使用 • { • scanf("%s",leader_name); • for(j=0;j<3;j++) • if(strcmp(leader_name,leader[j].name)==0) /*比较输入的名字与候选人的名字* • leader[j].count++; /*相当于leader[j].count= leader[j].count +1;*/ • } • printf("\n"); • for(i=0;i<3;i++) • printf("%5s:%d\n",leader[i].name,leader[i].count); • } 程序运行结果为: 上一页 下一页 返回
9.2 结构体类型的使用 • 9.2.4 结构体指针 • 结构体指针是指基类型为结构体类型的指针变量。通过结构体指针可以间接访问结构体中的成员。 下面通过实例说明结构体指针的应用。 【例 − 】使用结构体指针输出学生基本信息。 • 【程序代码】 • #include <string.h> • #include <stdio.h> • main() • { • struct student /* 定义一个结构体类型*/ • { • long num; • char name[20]; • char sex; • float score; 上一页 下一页 返回
9.2 结构体类型的使用 • }; • struct student stu,*p; /* 定义结构体变量stu和结构体指针p */ • p=&stu; /* 结构体指针p指向结构体变量stu */ • stu.num=101; • strcpy(stu.name,"Xuhuayu"); • stu.sex='M'; • stu.score=90.0; • printf("No.:%ld\nname:%s\nsex:%c\nscore:%f\n",stu.num,stu.name,stu.sex,stu.score); • printf("No.:%ld\nname:%s\nsex:%c\nscore:%f\n",(*p).num,(*p).name,(*p).sex,(*p).score); • } • 程序运行结果为: 上一页 下一页 返回
9.2 结构体类型的使用 • 【程序分析】 • 程序中将结构体变量 stu 的地址赋给指针变量 p,也就是使 p 指向 stu,然后对 stu 的各成员赋值,第一个 printf()函数输出 stu 的各个成员的值,第二个 printf函数也是用来输出 stu 各成员的值,但使用的是(*p).num 这样的形式。 • 通过结构体指针引用成员的方式有两种: • ① (*p).成员名 • ② p−>成员名 (−>为指向运算符) • 指针变量可以指向结构体变量,当然也可以指向结构体数组,其使用方法与指向数组的指针的使用方法类似,只不过把普通数组换成了结构体数组。 上一页 返回
9.3 链 表 • 9.3.1 链表的基本结构 • 链表是一种动态数据结构,可根据需要动态地开辟存储空间,随时释放不再需要的存储空间。这样可以有效利用存储空间,提高存储空间利用率。 图 9−3 是一种单向链表结构示意图。链表中的每个元素称为链表的结点,每个结点中包括两部分内容,即用户需要的数据和下一个结点的地址,也就是说,链表中的每个结点是由数据域和指针域组成。 在链表中通常用一个指针指向链表开头的结点,该指针称为头指针。图 9−3中 head 即为头指针,它指向第一个结点。 • 单向链表中前一个结点的指针域指向后一个结点,这样可以通过前一个结点引用后一个结点。最后一个结点不再指向其他结点,称为尾结点(即表尾) ,它的指针域的值是 NULL(空指针) ,表示整个链表到此结束。 下一页 返回
9.3 链 表 • 从链表的特点来看,结构体类型最适合描述链表。例如,有以下结构体类型定义: • struct node • { • int num; • float score; • struct node *next; • }; • 其中成员 num 和 score 用来存放结点中的有用数据(即数据域) ,next 是指针域,它的类型是 struct node 类型,用来指向一个结点。 上一页 下一页 返回
9.3 链 表 • 【例 − 】建立一个简单链表如图 9−4 所示,它由 3 个存放学生数据(包括学号和姓名)的结点组成,然后输出各个结点数据。 • 【程序代码】 • #include "stdio.h" • struct node • { • int num; /* 存储学生学号 */ • float score; /* 存储学生成绩 */ • struct node *next; /* 定义结构体指针,指向下一个结点 */ • }; • main() • { • struct node a,b,c,*head,*p; 上一页 下一页 返回
9.3 链 表 • a.num=101;a.score=85.4; /* 给结点a的num和score域赋值 */ • b.num=103;b.score=96.1; /* 给结点b的num和score域赋值 */ • c.num=105;c.score=77.5; /* 给结点c的num和score域赋值 */ • head=&a; /* 头指针head指向结点a */ • a.next=&b; /* 链接结点b和a结点*/ • b.next=&c; /* 链接结点c和b结点*/ • c.next=NULL; /* 结点c为尾结点*/ • p=head; /* 使p指针指向第一个结点*/ • do /* 依次输出各结点数据 */ • {printf("学号:%d 成绩:%5.2f\n",p->num,p->score); • p=p->next; /* 指针p后移,指向下一结点*/ • }while (p!=NULL); • } • 程序运行结果为: 上一页 下一页 返回
9.3 链 表 • 9.3.2 链表的基本操作 • 1.动态分配和释放存储区 • 动态开辟存储空间需要使用 malloc()函数,释放存储空间使用 free()函数。这些函数包含在头文件“stdlib.h”中。 • (1)malloc()函数。函数调用的一般形式为:malloc(size) • 功能:在内存申请分配一个 size 字节的存储区。调用结果为新分配的存储区的首地址,是一个 void*类型指针,若申请失败,则返回 NULL。 void*类型指针是一个指向非具体数据类型的指针,称为无类型指针,因此一般在使用该函数时,要用强制类型转换将其转换为所需要的类型。例如: • int *p; • p=(int*)malloc(2); 上一页 下一页 返回
9.3 链 表 • 上面语句完成向内存申请 2 字节的存储区,用来存放一个整数,并让指针 p指向存储区的首部。 • struct node *p; • p=(struct node *)malloc(sizeof(struct node)); • 上面语句中sizeof是C语言的运算符, 功能是计算数据类型或变量所占的字节数,sizeof(struct node)是计算struct node类型所占的字节数,那么malloc(sizeof(struct node))的功能是申请分配一个struct node类型所需大小的存储区。 由于malloc()的返回值是无类型指针,而指针p的基类型是struct node类型,因此需要进行强制类型转换,将malloc()函数的返回值转换为指向struct node类型的指针。 • (2)free()函数。函数调用的一般形式为:free(p) • 功能:释放指针 p 所指向的动态存储区。 上一页 下一页 返回
9.3 链 表 • 2. 建立单向链表 • 建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入结点数据,并建立起前后链接关系。 【例 − 】建立链表函数。 建立一个有若干名学生数据的单向动态链表,当输入的学生学号为零时结束操作。 • 【程序代码】 • #include "stdio.h" • #include "stdlib.h" • struct node • { • int num; • float score; • struct node *next; • }; • struct node *create() • { 上一页 下一页 返回
9.3 链 表 • struct node *head,*s,*p; • int c; • float x; • head=(struct node *)malloc(sizeof(struct node)); /*生成头结点*/ • p=head; /*尾指针指向第一个结点*/ • printf("输入学生结点信息(学号和成绩),学号为0时输入结束:\n"); • scanf("%d%f",&c,&x); /*输入学生数据*/ • while(c!=0) • { • s=(struct node *)malloc(sizeof(struct node)); /*生成新结点s*/ • s->num=c; /*将读入的学生学号存放到新结点s的数据域中*/ 上一页 下一页 返回
9.3 链 表 • s->score=x; /*将读入的学生成绩存放到新结点s的数据域中*/ • p->next=s; /*将新结点s插入到表尾*/ • p=s; /*修改尾指针p指向当前的尾结点*/ scanf("%d%f",&c,&x); /*输入新的学生数据*/ • } • p->next=NULL; /*将最后一个结点的指针域置为空*/ • return(head); /*返回头指针*/ • } • 【程序分析】 • (1)本例链表建立采用的是尾插法,即新结点始终链接在链表的尾部。 上一页 下一页 返回
9.3 链 表 • (2)链表建立的具体过程为:首先用 malloc()函数申请头结点,并将指针 p也指向头结点,如图 9−5(a)所示,然后输入学生数据,判断学号是否为 0,并由此进入循环体,在循环体中为新结点 s 申请空间并存入数据,如图 9−5(b)所示,将新结点链接到链表尾部,如图 9−5(c) ,移动指针 p 使其指向新的链尾结点,如图 9−5(d) ,然后开始下一轮操作,如图 9−5(e)和如图 9−5(f)所示,如此反复,当用户输入 0 时候,表示操作结束,此时 p 依然指向链表的结尾,将其指针域置为 NULL,整个链表建立结束,返回头指针。 上一页 下一页 返回
9.3 链 表 • 3. 输出链表 • 【例 − 】输出链表函数。 • 【程序代码】 • void print(struct node *head) • { • struct node *p; • printf("\t 输出学生结点信息\n"); • p=head->next; /* 指针p指向第一个结点*/ • while (p!=NULL) • { • printf("学号:%d成绩:%5.1f\n",p->num,p->score); • p=p->next; /* 指针p后移,指向下一结点 */ • } • } 上一页 下一页 返回
9.3 链 表 • 4. 删除链表中的结点 • 从链表中删去一个结点,首先要找到这个结点,然后把它从链表中分离开来,撤销原来的链接关系,同时保证原有链表的链接关系。 • 【例 − 】删除结点函数,删除链表中学号为 num 的结点。 • 【编程思路】 • (1)删除结点操作分两步完成。第一步查找要删除的结点,第二步进行删除。 • (2)查找结点时,从 p 指向的第一个结点开始,检查该结点中的 num 值是否等于输入的要求删除的那个学号,如果相等,就找到了要删除的结点,如不相等,就将 p 后移一个结点,直到找到要删除的结点或者遇到链尾为止。在移动 p 的同时移动 q,使用 q 记录 p 的前驱结点,如图 9−6(a)所示。 • (3)找到待删除结点后,使 q 指向要删除结点 p 的后继结点,如 • 图 9−6(b)所示,然后释放结点 p 的内存空间,如图 9−6(c)所示。 上一页 下一页 返回
9.3 链 表 • 【程序代码】 • struct node *del(struct node *head,int num) • { • struct node *p,*q; • q=head; • p=head->next; • while(num!=p->num&&p!=NULL) • { • q=p; • p=p->next; • } • if(num==p->num) 上一页 下一页 返回
9.3 链 表 • { • q->next=p->next; • free(p); • } • else • printf("没有找到学号为%d的结点!\n",num); • return(head); • } • 5. 在链表中插入结点 • 对链表的插入是指将一个结点插入到一个已有的链表中,为了能做到正确插入,必须解决两个问题:如何找到插入的位置;如何实现插入。 上一页 下一页 返回
9.3 链 表 • struct node *ins(struct node *head,int c,float x) • { • struct node *p,*q,*s; • s=(struct node *)malloc(sizeof(struct node)); /*生成新结点s*/ • s->num=c; /*将要插入的学生学号存放到新结点s的数据域中*/ • s->score=x; /*将要插入的学生成绩存放到新结点s的数据域中*/ • q=head; • p=head->next; • while (p!=NULL&&c>p->num) • { • q=p; • p=p->next; • } 上一页 下一页 返回
9.3 链 表 • q->next=s; • if(p!=NULL) • s->next=p; • else • s->next=NULL; • return(head); • } • 【程序分析】 • 首先定义一个新结点存储待插入的结点信息(如图 9−7 中的结点 s) ,从指针p 指向第一个结点开始,将 p->num 与 c 相比较,如果 c>p->num,将 p 后移,并使 q 始终指向 p 的前驱结点,如图 9−7(a)所示,直到 p-num->c 为止,这时找到新结点的插入位置。 • 如果插入位置是链表的尾部,将新结点插到链尾即可。 • 如果插入位置在链表中间,则让 s->next 指向 p 结点,如图 9−7(b)所示,然后让 q->next 指向 s 结点,如图 9−7(c)所示。 上一页 下一页 返回
9.3 链 表 • 9.3.3 链表综合应用 • 【例 − 】编制主函数,调用链表建立函数,输出函数,删除函数及插入函数,完成链表的基本操作。 • 【程序代码】 • main() • { • struct node *h; • int del_num,in_num; • float in_score; • h=create(); /*建立链表*/ • print(h); /*输出链表*/ 上一页 下一页 返回
9.3 链 表 • printf("\n输入要删除的学生结点的学号:\n"); • scanf("%d",&del_num); • h=del(h,del_num); /*删除链表结点*/ • print(h); /*输出链表*/ • printf("\n输入要插入的学生结点信息:\n"); • scanf("%d%f",&in_num,&in_score); • h=ins(h,in_num,in_score); /*插入结点*/ • print(h); /*输出链表*/ • } • 程序运行过程为: 上一页 返回
9.4 结构体应用实例 • 【例 − 】某班有 45 名学生,现在对他们的期末考试成绩进行统计。假定期末考 3 门课,分别为物理、数学和化学,要求计算每个学生的平均成绩和总成绩,最后计算本班每门课的平均成绩。 • 【编程思路】 • (1)本程序分成三部分:学生数据输入(包括计算学生平均成绩和总成绩) 、学生成绩单输出、本班每门课总成绩和平均成绩的计算和输出,分别由三个函数来实现,在主程序中调用这三个函数。 • (2)定义结构体来存储学生数据,包括学生基本信息,学生三门课成绩(利用数组) ,平均成绩,总成绩。 • (3)将结构体数组地址作为实参传递给函数,以便在函数中使用结构体指针对学生数据进行操作。 下一页 返回
9.4 结构体应用实例 • 【程序代码】 • #include "stdio.h" • #include "conio.h" • #include "string.h" • #define NU 3 /*以3名学生为例*/ • struct student • { • long num; /*定义成员变量,存储学生学号*/ • char name[10]; /*定义成员变量,存储学生姓名*/ • float score[3]; /*定义成员变量,存储学生3门课的成绩*/ • float aver_person; /*定义成员变量,存储学生平均成绩*/ • float sum_person; /*定义成员变量,存储学生总成绩*/ 上一页 下一页 返回
9.4 结构体应用实例 • }; • void print(struct student *p) /*输出个人成绩单 */ • { • int i; • for(i=0;i<NU;p++,i++) • { • printf("\t\t 学生成绩单\n"); • printf("\t 学号:%ld\n",p->num); • printf("\t 姓名:%s\n",p->name); • printf("\t 数学:%5.1f |",p->score[0]); • printf(" 物理:%5.1f |",p->score[1]); • printf(" 化学:%5.1f\n",p->score[2]); • printf("\t 平均成绩:%5.1f\n",p->aver_person); 上一页 下一页 返回
9.4 结构体应用实例 • printf("\t 总成绩:%5.1f\n",p->sum_person); • printf("--------------------------------------------------------------\n"); • } • } • void scan(struct student *p) /*输入学生数据同时计算个人的平均成绩和总成绩 */ • { • int i,j; • printf(" 学生信息录入\n"); • for(i=0;i<NU;p++,i++) • { • p->sum_person=0; 上一页 下一页 返回
9.4 结构体应用实例 • printf("学号:"); • scanf("%ld",&p->num); /*使用结构体指针输入学生学号*/ • printf("姓名:"); • scanf("%s",&p->name); /*输入学生姓名*/ • printf("成绩录入:\n"); • for(j=0;j<3;j++) • { • printf("\t 第%d门成绩:",j+1); • scanf("%f",&p->score[j]); /*输入学生第j门课成绩*/ • p->sum_person=p->sum_person+p->score[j]; /*学生成绩累加求和*/ • } 上一页 下一页 返回
9.4 结构体应用实例 • p->aver_person=p->sum_person/3; /*计算单个学生的平均成绩*/ • } • printf("--------------------------------------------------------------\n"); • } • void average(struct student *p) /* 计算本班每门课的总成绩和平均成绩 */ • { • int i,j; • float sum[3]={0},aver[3]; • for(i=0;i<NU;p++,i++) • for(j=0;j<3;j++) • sum[j]=sum[j]+p-> score[j]; /*学生成绩累加求和*/ • for(j=0;j<3;j++) 上一页 下一页 返回
9.4 结构体应用实例 • aver[j]=sum[j]/3; /*分别计算每门课的平均成绩*/ • printf("\t\t 本班成绩信息统计\n"); • printf("\t 数学总成绩:%7.1f,平均成绩:%5.1f \n",sum[0],aver[0]); • printf("\t 物理总成绩:%7.1f,平均成绩:%5.1f \n",sum[1],aver[1]); • printf("\t 化学总成绩:%7.1f,平均成绩:%5.1f \n",sum[2],aver[2]); • printf("--------------------------------------------------------------\n"); • } • void main() • { • struct student stu[NU]; 上一页 下一页 返回