1 / 87

第 9 章 结构体及其应用

第 9 章 结构体及其应用. 第 9 章 结构体及其应用. 学习目标 掌握构造类型 — 结构体类型及其使用。 学习内容 结构体类型及其定义,结构体变量的定义及使用,结构体数组的使用,结构体指针的使用,链表及其基本操作。. 下一页. 返 回. 第 9 章 结构体及其应用. 9.1 一个程序实例 9.2 结构体类型的使用 9.3 链表 9.4 结构体应用实例 9.5 本章小结 9.6 实训. 上一页. 返 回. 9.1 一个程序实例.

sezja
Download Presentation

第 9 章 结构体及其应用

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第9章 结构体及其应用

  2. 第9章 结构体及其应用 • 学习目标 • 掌握构造类型—结构体类型及其使用。 • 学习内容 • 结构体类型及其定义,结构体变量的定义及使用,结构体数组的使用,结构体指针的使用,链表及其基本操作。 下一页 返 回

  3. 第9章 结构体及其应用 • 9.1 一个程序实例 • 9.2 结构体类型的使用 • 9.3 链表 • 9.4 结构体应用实例 • 9.5 本章小结 • 9.6 实训 上一页 返 回

  4. 9.1 一个程序实例 • 【例9-1】一个学生的信息包括学号、姓名、平时成绩、期末成绩和总评成绩,其中总评成绩的计算公式为: • 总评成绩=平时成绩×30%+期末成绩×70% • 根据给定的平时成绩和期末成绩计算总评成绩,并输出学生的信息。 • 【编程思路】 • 本实例中学生的信息包含5个数据项,这些数据项具有内在的联系(同属于一个学生),然而数据类型却不尽相同。那么,能否将不同类型的数据项组合成一个有机的整体,以方便引用呢?C语言可以做到。C语言允许编程者自己构造一种数据类型——结构体类型,把多个数据项(类型可以相同也可以不相同)组合在一起,作为一个整体进行处理。 • 根据本题的情况,用以下形式构造名为student的结构体类型。 下一页 返 回

  5. 9.1 一个程序实例 • struct student /*student为结构体类型名*/ • { int num; /*学号为int型*/ • char name[10] /*姓名用字符数组*/ • float s1,s2,score; /*3个成绩为float型*/ • }; • struct student是一种结构体类型,它由5个数据项组成,此处的数据项称为结构体成员或者域。接下来可以用struct student这个数据类型定义变量,只有变量才能存储数据。 • 例如,下面语句定义了一个结构体变量:struct student wang; • 结构体变量wang包括学号、姓名、平时成绩、期末成绩和总评成绩等5个成员。程序中结构体变量不能整体引用,要引用到其中的成员。 • 结构体变量中成员的引用形式为:结构体变量.成员名。比如:wang.num、wang.name、wang.s1等。结构体成员在程序中的作用和用法与普通变量相同。 上一页 下一页 返 回

  6. 9.1 一个程序实例 • 【程序代码】 • #include "stdio.h" • #include "string.h" • struct student /*定义结构体类型*/ • { • int num; • char name[10]; • float s1,s2,score; • }; • main() • { • struct student wang; /*定义结构体变量*/ 上一页 下一页 返 回

  7. 9.1 一个程序实例 • /*以下给变量名为wang的学生赋值 */ • 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); • } 上一页 下一页 返 回

  8. 9.1 一个程序实例 • 程序输出结果为: • 在解决实际问题时经常需要使用结构体类型。使用时先定义结构体类型,然后再定义结构体变量或结构体数组。 上一页 返 回

  9. 9.2 结构体类型的使用 • 一组相关的数据可能是相同类型的,也可能是不同类型的。为了封装相关的数据,就需要采用可以包含不同类型成员的类型来定义这样的数据,这种类型就是结构体类型。 • 9.2.1 结构体类型的定义 • 定义结构体类型的一般形式为: • struct 结构体类型名 • { • 类型名1 成员名1; • 类型名2 成员名2; • …… • 类型名1 成员名1; • }; 下一页 返 回

  10. 9.2 结构体类型的使用 • 例如: • struct stud • { int num; • char name[20]; • char sex; • int age; • float score[3]; • char address[30]; • }; 上一页 下一页 返 回

  11. 9.2 结构体类型的使用 • 说明: • (1)struct是关键字,标志结构体类型。struct后面是所定义的结构体类型的名字,结构体名应符合标识符的命名规则。这里结构体名可以省略,省略后将成为无名结构体。 • (2)结构体的各个成员用花括号括起来,结构体成员的定义方式和变量的定义方式一样,成员名的命名规则和变量相同;各成员之间用分号分隔;结构体类型的定义以分号结束。 • (3)结构体成员的数据类型可以是基本类型的,也可以是构造类型,如数组或其他结构体类型。 • 提示:结构体类型定义后面的分号“;”不能省略,它经常被遗漏而导致程序错误。 上一页 下一页 返 回

  12. 9.2 结构体类型的使用 • 9.2.2 结构体变量的定义及引用 • 有了结构体数据类型,接下来需要定义结构体类型变量,以便存放结构体类型的数据。 • 1. 结构体变量的定义 • C语言中,结构体变量定义可以采取3种方法。 • (1) 先声明结构体类型再定义变量名 • 例如: • struct stud /*定义结构体类型*/ • { int num; • char name[20]; • char sex; • int age; • float score[3]; 上一页 下一页 返 回

  13. 9.2 结构体类型的使用 • char address[30]; • }; • struct stud student1,student2; /*定义结构体变量*/ • 以上定义了两个结构体变量student1和student2,它们均包含6个成员:编号、姓名、性别、年龄、3门课成绩和地址。 • 与普通变量一样,结构体变量也可以通过初始化赋值。例如: • 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所示。 上一页 下一页 返 回

  14. 图9-1 结构体变量存储情况 返 回

  15. 9.2 结构体类型的使用 • 注意:上面定义的结构体类型有6个成员,而赋值的时候有8项数据,原因是第5个成员score是数组,它有3个元素,用来存放3门课成绩。 • 从图9-1中可以看到,各成员分配在连续的存储区域内,而且各个成员所占的字节数之和就是结构体变量的字节数。 • (2) 定义结构体类型的同时定义结构体变量 • 这种方法定义的一般形式为: • struct 结构体名 • { • 成员表列 • }变量名表列; 上一页 下一页 返 回

  16. 9.2 结构体类型的使用 • 例如,上面的结构体类型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; • 这里只对变量student1进行了赋初值操作。 上一页 下一页 返 回

  17. 9.2 结构体类型的使用 • (3) 定义无名结构体类型的同时定义结构体变量(即不出现结构体名) • 一般定义形式为: • struct • { • 成员表列 • }变量名表列; • 例如: • struct • { int num; • char name[20]; • char sex; 上一页 下一页 返 回

  18. 9.2 结构体类型的使用 • int age; • float score[3]; • char address[30]; • }student1,student2; • 2. 结构体变量中成员的引用 • 结构体变量本身不能代表一个特定的值,只有它的成员才会有特定的值。因此使用结构体变量时,要引用其成员。 • 结构体变量中成员的引用形式是: • 结构体变量.成员名 • 例如,结构体变量student1中各个成员引用形式如下: • student1.num、student1.name、student1.sex、student1.age、student1.address 上一页 下一页 返 回

  19. 9.2 结构体类型的使用 • student1.score[0]、student1.score[1]、student1.score[2] • 结构体中成员的作用与地位相当于普通变量,因此可以进行与普通变量一样的操作,比如赋值、输入输出等,例如有以下语句: • student1.num=101; • scanf(“%d”,&student1.num); • printf("%d \n",student1.num); • distance=student1.age- student2.age; • 提示:不能对结构体变量整体进行输入输出等操作。以下输入输出是错误的: • scanf("%d",%s,%c,%d,%f,%s",&student1); • printf("%d,%s,%c,%d,%f,%d\n",student1); 上一页 下一页 返 回

  20. 9.2 结构体类型的使用 • 3. 结构体类型嵌套 • 以上给出的例子中,结构体成员的类型都是基本类型和数组类型。实际上,成员的类型可以是任何数据类型。下面给出成员类型是另一个结构体类型的例子。 • 例如: • struct date /*日期结构*/ • { • int year; • int month; • int day; • }; • struct student 上一页 下一页 返 回

  21. 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所示。 上一页 下一页 返 回

  22. 图9-2 结构体变量stu的存储情况 返 回

  23. 9.2 结构体类型的使用 • 当成员本身又属于一个结构体类型,引用时要逐级找到最低一级成员,只能对最低级的成员进行赋值或存取操作。 • 例如,对上面定义的结构体变量stu,可以这样访问其中的日期成员: • stu. birthday. year • stu.birthday.month • stu.birthday. day • 注意:不能用stu.birthday来访问stu变量中的成员birthday,因为birthday本身也是一个结构体变量。 上一页 下一页 返 回

  24. 9.2 结构体类型的使用 • 9.2.3 结构体数组 • 在例9-1中一个结构体变量只能处理一个人的信息(如一个学生的学号、姓名、成绩等数据)。但在实际应用中经常需要处理一批人的信息,这时应该使用结构体类型的数组。 • 定义结构体数组与定义结构体变量的方法相同。例如: • struct student • { • int num; • char name[20]; • char sex; • int age; • float score[3]; 上一页 下一页 返 回

  25. 9.2 结构体类型的使用 • char address[30]; • } stu[3]; • 以上定义了一个数组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] • 可见,结构体数组元素也是通过数组名和下标来引用的。因为各个元素都是结构体类型,因此对结构体数组元素的引用与对结构体变量的引用一样,也要逐级引用,只能对最低的成员进行存取和运算。 上一页 下一页 返 回

  26. 9.2 结构体类型的使用 • 【例9-2】候选人得票统计程序。设有3个候选人,10个投票人,输入得票人的名字并进行统计,最后输出各人得票结果。 • #include "string.h" • #include "stdio.h" • struct person • { • char name[20]; /*候选人姓名*/ • int count; /*候选人票数*/ • }leader[3]={"star",0, "mery",0, "sun",0}; /*定义结构体数组并初始化*/ • main( ) • { 上一页 下一页 返 回

  27. 9.2 结构体类型的使用 • int i,j; • char leader_name[20]; • for(i=1;i<=10;i++) • { • 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"); 上一页 下一页 返 回

  28. 9.2 结构体类型的使用 • for(i=0;i<3;i++) • printf("%5s:%d\n",leader[i].name,leader[i].count); • } • 程序运行结果为: 上一页 下一页 返 回

  29. 9.2 结构体类型的使用 • 程序定义了一个结构体数组leader,它有3个元素,每一个元素包含两个成员name(候选人姓名)和count(得票数),在定义数组时使之初始化,使3位候选人的票数都先置零。 • 主函数中定义了字符数组leader_name,它接受被选人的姓名,在10次循环中每次先输入一个被选人名,然后与3个候选人名相比,决定是否计数。在输入和统计结束之后,将3人的名字和得票数输出。 • 小测验 • 统计选票时,如果投票人数不确定,程序该如何修改? 上一页 下一页 返 回

  30. 9.2 结构体类型的使用 • 9.2.4 结构体指针 • 结构体指针是指基类型为结构体类型的指针变量。通过结构体指针可以间接访问结构体中的成员。 • 下面通过实例说明结构体指针的应用。 • 【例9-3】使用结构体指针输出学生基本信息。 • 【程序代码】 • #include "string.h" • #include "stdio.h" • main( ) • { • struct student /* 定义一个结构体类型*/ • { 上一页 下一页 返 回

  31. 9.2 结构体类型的使用 • long num; • char name[20]; • char sex; • float score; • }; • struct student stu,*p; /* 定义结构体变量stu和结构体指针p */ • p=&stu; /* 结构体指针p指向结构体变量stu */ • stu.num=101; • strcpy(stu.name,"Xuhuayu"); • stu.sex='M'; • stu.score=90.0; 上一页 下一页 返 回

  32. 9.2 结构体类型的使用 • 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); • } • 程序运行结果为: 上一页 下一页 返 回

  33. 9.2 结构体类型的使用 • 程序分析: • 程序中将结构体变量stu的地址赋给指针变量p,也就是使p指向stu,然后对stu的各成员赋值,第一个printf()函数输出stu的各个成员的值,第二个printf函数也是用来输出stu各成员的值,但使用的是(*p).num这样的形式。 • 通过结构体指针引用成员的方式有两种: • ① (*p).成员名 • ② p->成员名 (->为指向运算符) • 指针变量可以指向结构体变量,当然也可以指向结构体数组,其使用方法与指向数组的指针的使用方法类似,只不过把普通数组换成了结构体数组。 上一页 下一页 返 回

  34. 9.2 结构体类型的使用 • 【例9-4】使用指向结构体数组的指针实现多名学生信息的输出。 • 【程序代码】 • #include "stdio.h" • struct student • { int num; • char name[20]; • char sex; • int age; • }; • struct student stu[3]={{101,"Xuhy",'M',18},{102,"Liuhm",'M',19},{103,"Lp",'F',20}}; • main( ) 上一页 下一页 返 回

  35. 9.2 结构体类型的使用 • { • struct student *p; /* 定义结构体指针*/ • printf(" No. Name sex age\n"); • for(p=stu;p<stu+3;p++) /* 利用结构体指针输出数据*/ • printf("%4d %-6s %-2c%4d\n",p->num,p->name,p->sex,p->age); • } • 程序运行结果为: 上一页 下一页 返 回

  36. 9.2 结构体类型的使用 • 程序分析: • p是指向struct student结构体类型的指针变量。在for语句中先使p的初值为stu,即数组stu的起始地址,循环第一次输出stu[0]的各个成员值,然后执行p++,使p自加1(以struct student结构体类型所占的字节数为单位)后指向stu[1],循环第二次输出stu[1]的各成员值,再执行p++后,p指向stu [2],输出stu [2]的各成员值后循环结束。 上一页 返 回

  37. 9.3 链表 • 9.3.1 链表的基本结构 • 链表是一种动态数据结构,可根据需要动态地开辟存储空间,随时释放不再需要的存储空间。这样可以有效利用存储空间,提高存储空间利用率。 • 图9-3是一种单向链表结构示意图。链表中的每个元素称为链表的结点,每个结点中包括两部分内容,即用户需要的数据和下一个结点的地址,也就是说,链表中的每个结点是由数据域和指针域组成。 • 在链表中通常用一个指针指向链表开头的结点,该指针称为头指针。图9-3中head即为头指针,它指向第一个结点。 • 单向链表中前一个结点的指针域指向后一个结点,这样可以通过前一个结点引用后一个结点。最后一个结点不再指向其他结点,称为尾结点(即表尾),它的指针域的值是NULL(空指针),表示整个链表到此结束。 下一页 返 回

  38. 图9-3 链表结构图 返 回

  39. 9.3 链表 • 从链表的特点来看,结构体类型最适合描述链表。比例,有以下结构体类型定义: • struct node • { • int num; • float score; • struct node *next; • }; • 其中成员num和score用来存放结点中的有用数据(即数据域),next是指针域,它的类型是struct node类型,用来指向一个结点。 • 【例9-5】建立一个简单链表,如图9-4所示,它由3个存放学生数据(包括学号和姓名)的结点组成,然后输出各个结点数据。 上一页 下一页 返 回

  40. 图9-4 简单链表 返 回

  41. 9.3 链表 • 【程序代码】 • #include "stdio.h" • struct node • { • int num; /* 存储学生学号 */ • float score; /* 存储学生成绩 */ • struct node *next; /* 定义结构体指针,指向下一个结点 */ • }; • main( ) • { • struct node a,b,c,*head,*p; 上一页 下一页 返 回

  42. 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指针指向第1个结点 */ • do /* 依次输出各结点数据 */ • { 上一页 下一页 返 回

  43. 9.3 链表 • printf("学号:%d 成绩:%5.2f\n",p->num,p->score); • p=p->next; /* 指针p后移,指向下一结点 */ • }while (p!=NULL); • } • 程序运行结果为: • 程序说明: • 本例中链表结点是在程序中定义的,不是临时开辟,这种方法生成的链表成为静态链表。当然,有使用价值的应该是动态链表。 上一页 下一页 返 回

  44. 9.3 链表 9.3.2 链表的基本操作 • 1. 动态分配和释放存储区 • 动态开辟存储空间需要使用malloc()函数,释放存储空间使用free()函数。这些函数包含在头文件”stdlib.h”中。 • (1)malloc()函数 • 函数调用的一般形式为:malloc(size) • 功能:在内存申请分配一个size字节的存储区。调用结果为新分配的存储区的首地址,是一个void *类型指针,若申请失败,则返回NULL。 • void *类型指针是一个指向非具体数据类型的指针,称为无类型指针,因此一般在使用该函数时,要用强制类型转换将其转换为所需要的类型。例如: 上一页 下一页 返 回

  45. 9.3 链表 • int *p; • p=(int *)malloc(2); • 上面语句完成向内存申请2字节的存储区,用来存放1个整数,并让指针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类型的指针。 上一页 下一页 返 回

  46. 9.3 链表 • (2)free()函数 • 函数调用的一般形式为:free(p) • 功能:释放指针p所指向的动态存储区。 • 2. 建立单向链表 • 建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入结点数据,并建立起前后链接关系。 • 【例9-6】建立链表函数。建立一个有若干名学生数据的单向动态链表,当输入的学生学号为0时结束操作。 • 【程序代码】 • #include "stdio.h" • #include "stdlib.h" • struct node 上一页 下一页 返 回

  47. 9.3 链表 • { • int num; • float score; • struct node *next; • }; • struct node *create( ) • { • struct node *head,*s,*p; • int c; • float x; • head=(struct node *)malloc(sizeof(struct node)); /*生成头结点*/ 上一页 下一页 返 回

  48. 9.3 链表 • 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的数据域中*/ • s->score=x; /*将读入的学生成绩存放到新结点s的数据域中*/ • p->next=s; /*将新结点s插入到表尾*/ 上一页 下一页 返 回

  49. 9.3 链表 • p=s; /*修改尾指针p指向当前的尾结点*/ • scanf("%d%f",&c,&x); /*输入新的学生数据*/ • } • p->next=NULL; /*将最后一个结点的指针域置为空*/ • return(head); /*返回头指针*/ • } • 程序分析: • (1)本例链表建立采用的是尾插法,即新结点始终链接在链表的尾部。 (2)链表建立的具体过程为:首先用malloc()函数申请头结点,并将指针p也指向头结点,如图9-5 (a)所示,然后输入学生数据,判断学号是否为0,并由此进入循环体,在循环体中为新结点s申请空间并存入数据,如图9-5 (b)所示,将新结点链接到链表尾部,如图9-5 (c), 上一页 下一页 返 回

  50. 9.3 链表 • 移动指针p使其指向新的链尾结点,如图9-5 (d),然后开始下一轮操作,如图9-5 (e)和如图9-5 (f)所示,如此反复,当用户输入0时候,表示操作结束,此时p依然指向链表的结尾,将其指针域置为NULL,整个链表建立结束,返回头指针。 • 2. 输出链表 • 【例9-7】输出链表函数。 • 【程序代码】 • void print(struct node *head) • { • struct node *p; • printf("\t输出学生结点信息\n"); 上一页 下一页 返 回

More Related