《C语言程序设计能力》-第9章_第1页
《C语言程序设计能力》-第9章_第2页
《C语言程序设计能力》-第9章_第3页
《C语言程序设计能力》-第9章_第4页
《C语言程序设计能力》-第9章_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第9章结构体及其应用

学习目标掌握构造类型—结构体类型及其使用学习内容结构体类型及其定义结构体变量的定义及使用结构体数组的使用结构体指针的使用链表及其基本操作9.1一个程序实例【例9-1】一个学生的信息包括学号、姓名、平时成绩、期末成绩和总评成绩,其中总评成绩的计算公式为:总评成绩=平时成绩×30%+期末成绩×70%。根据给定的平时成绩和期末成绩计算总评成绩,并输出学生的信息。

根据本题的情况,用以下形式构造名为student的结构体类型。

structstudent/*student为结构体类型名*/ {intnum;/*学号为int型*/ charname[10]/*姓名用字符数组*/ floats1,s2,score;/*3个成绩为float型*/};structstudent是一种结构体类型,它由5个数据项组成,此处的数据项称为结构体成员或者域。接下来可以用structstudent这个数据类型定义变量,只有变量才能存储数据。例如,下面语句定义了一个结构体变量:structstudentwang;结构体变量中成员的引用形式为:结构体变量.成员名。比如:wang.num、、wang.s1等。结构体成员在程序中的作用和用法与普通变量相同。【程序代码】【程序代码】#include"stdio.h"#include"string.h"structstudent/*定义结构体类型*/{ intnum; charname[10]; floats1,s2,score;};main(){ structstudentwang;/*定义结构体变量*//*以下给变量名为wang的学生赋值*/ wang.num=101; strcpy(,"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",); 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;};例如:structstud {intnum; charname[20]; charsex; intage; floatscore[3]; charaddress[30]; };注意事项:(1)struct是关键字,标志结构体类型。struct后面是所定义的结构体类型的名字,结构体名应符合标识符的命名规则。这里结构体名可以省略,省略后将成为无名结构体。(2)结构体的各个成员用花括号括起来,结构体成员的定义方式和变量的定义方式一样,成员名的命名规则和变量相同;各成员之间用分号分隔;结构体类型的定义以分号结束。(3)结构体成员的数据类型可以是基本类型的,也可以是构造类型,如数组或其他结构体类型。9.2.2结构体变量的定义及引用结构体变量的定义(1)先声明结构体类型再定义变量名例如:structstud/*定义结构体类型*/ { intnum; charname[20]; charsex; intage; floatscore[3]; charaddress[30]; };structstudstudent1,student2;/*定义结构体变量*/结构体变量student1和student2中各成员的赋值情况如图所示。(2)定义结构体类型的同时定义结构体变量这种方法定义的一般形式为:

struct结构体名

{

成员表列

}变量名表列;例如,上面的结构体类型structstud也可以采取以下形式定义:structstud {intnum; charname[20]; charsex; intage; floatscore[3]; charaddress[30]; }student1={101,"ghz",'M',18,75.4,89.3,92.5,"xian"},student2;这里只对变量student1进行了赋初值操作。(3)定义无名结构体类型的同时定义结构体变量(即不出现结构体名)一般定义形式为:

struct{

成员表列

}变量名表列;例如:

struct { intnum; charname[20]; charsex; intage; floatscore[3]; charaddress[30]; }student1,student2;

结构体变量中成员的引用结构体变量本身不能代表一个特定的值,只有它的成员才会有特定的值。因此使用结构体变量时,要引用其成员。结构体变量中成员的引用形式是:

结构体变量.成员名例如,结构体变量student1中各个成员引用形式如下:

student1.num、、student1.sex、student1.age、student1.addressstudent1.score[0]、student1.score[1]、student1.score[2]结构体类型嵌套以上给出的例子中,结构体成员的类型都是基本类型和数组类型。实际上,成员的类型可以是任何数据类型。下面给出成员类型是另一个结构体类型的例子。例如:structdate/*日期结构*/ { intyear; intmonth; intday; };structstudent { intnum; charname[20]; charsex; intage; structdatebirthday;/*structdate为结构体类型*/ charaddress[30]; }stu={102,"xhy",'M',16,1977,5,8,"beijing"};9.2.3结构体数组在例9-1中一个结构体变量只能处理一个人的信息(如一个学生的学号、姓名、成绩等数据)。但在实际应用中经常需要处理一批人的信息,这时应该使用结构体类型的数组。定义结构体数组与定义结构体变量的方法相同。例如:structstudent { intnum; charname[20]; charsex; intage; floatscore[3]; charaddress[30]; }stu[3];【例9-2】候选人得票统计程序。设有3个候选人,10个投票人,输入得票人的名字并进行统计,最后输出各人得票结果。【程序代码】#include"string.h"#include"stdio.h"structperson{ charname[20];/*候选人姓名*/ intcount;/*候选人票数*/}leader[3]={"star",0,"mery",0,"sun",0};/*定义结构体数组并初始化*/main(){ inti,j; charleader_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"); for(i=0;i<3;i++) printf("%5s:%d\n",leader[i].name,leader[i].count);}9.2.4结构体指针结构体指针是指基类型为结构体类型的指针变量。通过结构体指针可以间接访问结构体中的成员。【例9-3】使用结构体指针输出学生基本信息。【程序代码】#include"string.h"#include"stdio.h"main(){ structstudent/*定义一个结构体类型*/{ longnum;charname[20]; charsex;floatscore;}; structstudentstu,*p;/*定义结构体变量stu和结构体指针p*/ p=&stu;/*结构体指针p指向结构体变量stu*/ stu.num=101;strcpy(,"Xuhuayu"); stu.sex='M';stu.score=90.0; printf("No.:%ld\nname:%s\nsex:%c\nscore:%f\n",stu.num,,stu.sex,stu.score); printf("No.:%ld\nname:%s\nsex:%c\nscore:%f\n",(*p).num,(*p).name,(*p).sex,(*p).score);}程序分析:程序中将结构体变量stu的地址赋给指针变量p,也就是使p指向stu,然后对stu的各成员赋值,第一个printf()函数输出stu的各个成员的值,第二个printf函数也是用来输出stu各成员的值,但使用的是(*p).num这样的形式。通过结构体指针引用成员的方式有两种:①(*p).成员名②p->成员名(->为指向运算符)指针变量可以指向结构体变量,当然也可以指向结构体数组,其使用方法与指向数组的指针的使用方法类似,只不过把普通数组换成了结构体数组。【例9-4】使用指向结构体数组的指针实现多名学生信息的输出。【程序代码】#include"stdio.h"structstudent{intnum; charname[20]; charsex; intage;};structstudentstu[3]={{101,"Xuhy",'M',18},{102,"Liuhm",'M',19},{103,"Lp",'F',20}};main(){ structstudent*p;/*定义结构体指针*/ printf("No.Namesexage\n"); for(p=stu;p<stu+3;p++)/*利用结构体指针输出数据*/ printf("%4d%-6s%-2c%4d\n",p->num,p->name,p->sex,p->age);}9.3链表9.3.1链表的基本结构链表是一种动态数据结构,可根据需要动态地开辟存储空间,随时释放不再需要的存储空间。这样可以有效利用存储空间,提高存储空间利用率。下图是一种单向链表结构示意图。链表中的每个元素称为链表的结点,每个结点中包括两部分内容,即用户需要的数据和下一个结点的地址,也就是说,链表中的每个结点是由数据域和指针域组成。在链表中通常用一个指针指向链表开头的结点,该指针称为头指针。图9-3中head即为头指针,它指向第一个结点。单向链表中前一个结点的指针域指向后一个结点,这样可以通过前一个结点引用后一个结点。最后一个结点不再指向其他结点,称为尾结点(即表尾),它的指针域的值是NULL(空指针),表示整个链表到此结束。【例9-5】建立一个简单链表,它由3个存放学生数据(包括学号和姓名)的结点组成,然后输出各个结点数据。【程序代码】#include"stdio.h"structnode{ intnum;/*存储学生学号*/ floatscore;/*存储学生成绩*/ structnode*next;/*定义结构体指针,指向下一个结点*/};main(){ structnodea,b,c,*head,*p; 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/*依次输出各结点数据*/ { printf("学号:%d成绩:%5.2f\n",p->num,p->score);p=p->next;/*指针p后移,指向下一结点*/ }while(p!=NULL);}9.3.2链表的基本操作1.动态分配和释放存储区动态开辟存储空间需要使用malloc()函数,释放存储空间使用free()函数。这些函数包含在头文件”stdlib.h”中。(1)malloc()函数函数调用的一般形式为:malloc(size)功能:在内存申请分配一个size字节的存储区。调用结果为新分配的存储区的首地址,是一个void*类型指针,若申请失败,则返回NULL。例如:structnode*p;p=(structnode*)malloc(sizeof(structnode));上面语句中sizeof是C语言的运算符,功能是计算数据类型或变量所占的字节数,sizeof(structnode)是计算structnode类型所占的字节数,那么malloc(sizeof(structnode))的功能是申请分配一个structnode类型所需大小的存储区。由于malloc()的返回值是无类型指针,而指针p的基类型是structnode类型,因此需要进行强制类型转换,将malloc()函数的返回值转换为指向structnode类型的指针。(2)free()函数函数调用的一般形式为:free(p)功能:释放指针p所指向的动态存储区。2.建立单向链表建立动态链表是指在程序执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入结点数据,并建立起前后链接关系。【例9-6】建立链表函数。建立一个有若干名学生数据的单向动态链表,当输入的学生学号为0时结束操作。【程序代码】#include"stdio.h"#include"stdlib.h"structnode{ intnum; floatscore; structnode*next;};structnode*create(){ structnode*head,*s,*p; intc; floatx; head=(structnode*)malloc(sizeof(structnode));/*生成头结点*/ p=head;/*尾指针指向第一个结点*/ printf("输入学生结点信息(学号和成绩),学号为0时输入结束:\n"); scanf("%d%f",&c,&x);/*输入学生数据*/ while(c!=0) { s=(structnode*)malloc(sizeof(structnode));/*生成新结点s*/ s->num=c;/*将读入的学生学号存放到新结点s的数据域中*/ s->score=x;/*将读入的学生成绩存放到新结点s的数据域中*/ p->next=s;/*将新结点s插入到表尾*/ p=s;/*修改尾指针p指向当前的尾结点*/ scanf("%d%f",&c,&x);/*输入新的学生数据*/ } p->next=NULL;/*将最后一个结点的指针域置为空*/ return(head);/*返回头指针*/}3.输出链表【例9-7】输出链表函数。【程序代码】voidprint(structnode*head){ structnode*p; printf("\t输出学生结点信息\n"); p=head->next;/*指针p指向第1个结点*/ while(p!=NULL) { printf("学号:%d成绩:%5.1f\n",p->num,p->score); p=p->next;/*指针p后移,指向下一结点*/ }}4.删除链表中的结点从链表中删去一个结点,首先要找到这个结点,然后把它从链表中分离开来,撤销原来的链接关系,同时保证原有链表的链接关系。【例9-8】删除结点函数,删除链表中学号为num的结点。【编程思路】(1)删除结点操作分两步完成。第一步查找要删除的结点,第二步进行删除。(2)查找结点时,从p指向的第一个结点开始,检查该结点中的num值是否等于输入的要求删除的那个学号,如果相等,就找到了要删除的结点,如不相等,就将p后移一个结点,直到找到要删除的结点或者遇到链尾为止。在移动p的同时移动q,使用q记录p的前驱结点,如图9-6(a)所示。(3)找到待删除结点后,使q指向要删除结点p的后继结点,如图9-6(b)所示,然后释放结点p的内存空间,如图9-6(c)所示。【程序代码】structnode*del(structnode*head,intnum){ structnode*p,*q; q=head; p=head->next; while(num!=p->num&&p!=NULL) { q=p; p=p->next; } if(num==p->num) { q->next=p->next; free(p); } else printf("没有找到学号为%d的结点!\n",num); return(head);}5.在链表中插入结点对链表的插入是指将一个结点插入到一个已有的链表中,为了能做到正确插入,必须解决两个问题:如何找到插入的位置;如何实现插入。【例9-9】插入结点函数。假定原链表结点已经按学号从小到大排列。【程序代码】structnode*ins(structnode*head,intc,floatx){ structnode*p,*q,*s; s=(structnode*)malloc(sizeof(structnode));/*生成新结点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; } 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.3链表综合应用【例9-10】编制主函数,调用链表建立函数,输出函数,删除函数及插入函数,完成链表的基本操作。【程序代码】main(){ structnode*h; intdel_num,in_num; floatin_score; h=create();/*建立链表*/ print(h);/*输出链表*/ 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结构体应用实例【例9-10】某班有45名学生,现在对他们的期末考试成绩进行统计。假定期末考3门课,分别为物理、数学和化学,要求计算每个学生的平均成绩和总成绩,最后计算本班每门课的平均成绩。【编程思路】(1)本程序分成三部分:学生数据输入(包括计算学生平均成绩和总成绩)、学生成绩单输出、本班每门课总成绩和平均成绩的计算和输出,分别由三个函数来实现,在主程序中调用这三个函数。(2)定义结构体来存储学生数据,包括学生基本信息,学生三门课成绩(利用数组),平均成绩,总成绩。(3)将结构体数组地址作为实参传递给函数,以便在函数中使用结构体指针对学生数据进行操作。【程序代码】#include"stdio.h"#include"conio.h"#include"string.h"#defineNU3/*以3名学生为例*/structstudent{ longnum;/*定义成员变量,存储学生学号*/ charname[10];/*定义成员变量,存储学生姓名*/ floatscore[3];/*定义成员变量,存储学生3门课的成绩*/ floataver_person;/*定义成员变量,存储学生平均成绩*/ floatsum_person;/*定义成员变量,存储学生总成绩*/};voidprint(structstudent*p)/*输出个人成绩单*/{ inti; 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); printf("\t总成绩:%5.1f\n",p->sum_person); printf("--------------------------------------------------------------\n"); }}voidscan(structstudent*p)/*输入学生数据同时计算个人的平均成绩和总成绩*/{ inti,j; printf("学生信息录入\n"); for(i=0;i<NU;p++,i++) { p->sum_person=0; printf("学号

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论