C语言程序设计-结构体与共用体.ppt
第12章结构体与共用体,程序设计语言,C,2,本章主要内容,结构体数据类型,共用体数据类型、枚举数据类型、定义数据类型的别名结构体变量、结构体数组、结构体指针的定义和初始化结构体成员的引用、成员选择运算符、指向运算符向函数传递结构体变量、结构体数组、结构体指针动态数据结构、动态链表,3,只能定义单一的数据类型,反映事物单一属性,如定义学生成绩:floatscore;,能定义复杂的数据类型,反映事物多个属性,存放相同数据类型的一组数据,如:floatscore30;,12.1从基本数据类型到抽象数据类型,4,4,12.1从基本数据类型到抽象数据类型,用户自己构造数据类型复合数据类型由基本数据类型迭代派生而来,表示复杂的数据对象典型的代表就是“结构体”抽象数据类型(AbstractDataType,ADT)在复合数据类型基础上增加了对数据的操作抽象数据类型进而进化为“类(Class)”这是一个跨时代的进步Class是Object-Oriented的一个重要概念,5,12.2.1问题的提出12.2.2结构体类型(结构体模板)定义12.2.3结构体变量的定义12.2.4结构体变量的初始化12.2.5结构体变量的引用12.2.6结构体数组12.2.7结构体指针12.2.8结构体作为函数参数,12.2结构体,6,12.2.1问题的提出,一个学生的信息有学号、姓名、性别、年龄、成绩等一本图书的信息有分类编号、书名、作者、出版社、出版日期、价格、库存量等如何描述和管理这些类型不同的相关数据?(使用二维数组行吗),问题:,7,12.2.1问题的提出,解决方案:,1)独立的变量表示:,8,12.2.1问题的提出,2)使用一维数组,age,no,sex,name,分配内存不集中,寻址效率不高;对数组赋初值时,易发生错位;结构显得零散,不易管理;,score,9,12.2.1问题的提出,解决方案:,C语言引入了称为结构体的数据存储方式,“结构体”是一种构造数据类型,它是由若干数据项组合而成的复杂数据对象,这些数据项称为结构体的成员。把关系紧密且逻辑相关的多种不同类型的变量,组织到统一的名字之下,占用相邻的一段内存单元,结构体变量表示:把不同类型的数据组合成一个整体,10,12.2.2结构体类型定义,struct结构体名数据类型名1成员名1;数据类型名2成员名2;数据类型名n成员名n;,struct是关键字,不能省略,合法标识符可省:无名结构体,成员类型可以是基本型或构造型,以分号;结尾,structStudentcharno9;/学号charname20;/姓名charsex;/性别unsignedintage;/年龄floatscore;/成绩;,structDateshortyear;/年shortmonth;/月shortday;/日;,11,12.2.2结构体类型定义,structStudentcharno9;/学号charname20;/姓名charsex;/性别shortintage;/年龄floatscore;/成绩;,结构体类型定义描述结构的组织形式,注意:结构体类型只是用户自定义的一种数据类型,用来定义描述结构的组织形式,不分配内存,只有用它来定义某个变量时,才会为该变量分配结构类型所需要大小的内存单元。,12,在结构体中数据类型相同的成员,既可逐个、逐行分别定义,也可合并成一行定义,就象一次定义多个变量一样。,structStudent_Infocharno9;/学号charname20;/姓名charsex;/性别unsignedintage;/年龄unsignedintclassno;/班级floatgrade;/成绩;,structStudent_Infocharno9,name20,sex;unsignedintage,classno;floatgrade;,12.2.2结构体类型定义,13,12.2.3结构体变量定义,struct结构体类型名数据类型名1成员名1;数据类型名n成员名n;struct结构体类型名变量列表;,先定义结构类型,再定义结构变量,structStudentcharno9;charname20;charsex;unsignedintage;floatscore;structStudentstu1,stu2;,定义一个类型为structstudent结构体的变量,将会为该变量分配内存,大小是等于其所有成员变量的大小之和。sizeof(structStudent),14,12.2.3结构体变量定义,定义结构体类型的同时定义结构体变量,struct结构体类型名数据类型名1成员名1;数据类型名n成员名n;变量名列表;,structStudentcharno9;charname20;charsex;unsignedintage;floatscore;stu1,stu2;,structcharno9;charname20;charsex;unsignedintage;floatscore;stu1,stu2;,或,无名结构体定义,15,12.2.3结构体变量定义,成员可以是结构体,结构体可以嵌套,structdateintmonth;intday;intyear;structstudentintno;charname20;structdatebirthday;stu;,structstudentintno;charname20;structdateintmonth;intday;intyear;birthday;stu;,16,12.2.4结构体变量的初始化,定义结构体变量时给结构体成员赋值,注意:赋初值时,中间的数据顺序必须与结构体成员的定义顺序一致,否则就会出现混乱。,structStudentstu=“09122325","YangFan",M,19,90;,structStudentstu=19,"YangFan",M,“09122325",90;,17,12.2.4结构体变量的初始化,定义结构体变量时给结构体成员赋值,structdateintyear,month,day;structStu_Infocharno9;/学号charname20;/姓名charsex;/性别structdatebirthday;/生日floatscore;/成绩;,structStu_Infostu="20020306","ZhangMing",M,1986,12,10,90;,18,12.2.5结构体变量的引用,引用规则:不能整体引用,只能引用变量的成员,引用方式:,结构体变量名.成员名,成员(分量)运算符结合性:从左向右,structstudentcharno9;charname20;charsex;unsignedintage;floatscore;stu1,stu2;,if(stu1=stu2).(),stu1.score=85.5;,stu1.age=stu2.age;,strcpy(stu1.no,“09122414”;),19,12.2.5结构体变量的引用,可以将一个结构体变量赋值给另一个结构体变量结构体嵌套时逐级引用,structstudentintno;charname20;structdateintmonth;intday;intyear;birthday;stu1,stu2;,stu1.birthday.month=12;,结构体变量名.成员名.子成员名最低级子成员名,20,12.2.5结构体变量的赋值,strcpy(stu1.no,stu.no);strcpy(stu1.name,stu.name);stu1.sex=stu.sex;stu1.age=stu.age;stu1.score=stu.score;,structStudentstu;strcpy(stu.no,“09122424");strcpy(stu.name,“XuTeng");stu.sex=M;stu.age=21;stu.score=90;structStudentstu1;stu1=stu;,如果在定义结构体变量时并未对其赋初始值,那么在程序中要对它赋值的话,就只能一个一个地对其成员逐一赋值,或者用已赋值的同类型的结构体变量对它赋值,21,12.2.5结构体变量应用举例,【例】计算某个学生5门课的平均成绩,最高分和最低分,#includestructStudentfloatscore5;floatavescore,maxscore,minscore;voidmain()inti;structStudentm;printf("inputthescoreoffivecourse:n");for(i=0;i<5;i+)/输入5门课的成绩scanf("%f",m.avescore=0;m.maxscore=m.score0;m.minscore=m.score0;for(i=0;im.maxscore)m.maxscore=m.scorei;if(m.scorei<m.minscore)m.minscore=m.scorei;m.avescore/=5;printf(“avescore=%4.1f,maxscore=%4.1f,minscore=%5.1fn",m.avescore,m.maxscore,m.minscore);,运行结果(设5门课的成绩为:7580869068):avescore=79.8maxscore=90.0minscore=68.0,22,12.2.6结构体数组,元素为结构体类型的数组称为结构体数组。在实际应用中,经常用结构体数组来表示具有相同数据结构体的一个群体。例如一个班的学员档案,一个公司的职工档案等。,结构体数组的定义,形式一:structStudentcharno9,name20,sex;unsignedintage;floatscore;structStudentstu10;,形式二:structStudentcharno9,name20,sex;unsignedintage;floatscore;stu10;,形式三:structcharno9,name20,sex;unsignedintage;floatscore;stu10;,23,12.2.6结构体数组与二维表的对应关系,结构体数组就相当于一张二维表,表的框架对应的就是某种结构体类型,表中的每一列对应该结构体的成员,表中每一行信息对应该结构体数组元素各成员的具体值,表中的行数对应结构体数组的大小。,结构体类型Student,structStudentcharno9;charname20;charsex;unsignedintage;floatscore;stu10;,24,12.2.6结构体数组的初始化,基本格式:struct结构体类型数组size=初值表1,初值表n;,例:,全部初始化时维数可省,25,12.2.6结构体数组的引用,引用格式:结构体数组名下标.成员名;,structStudentcharno9;charname20;charsex;unsignedintage;floatscore;stu10;,strcpy(stu0.name,"WangFei");,stu1.age+;,printf("%s",stu0.name);,26,12.2.6结构体数组举例,#include#includestructpersoncharname20;/候选人姓名intcount;/得票数leader3="Li",0,"Zhang",0,"Wang",0;,voidmain()inti,j;charleader_name20;printf("inputname:n");while(1)/统计候选人得票数gets(leader_name);/输入候选人姓名if(strcmp(leader_name,"0")=0)/输入为"0"结束break;for(j=0;j<3;j+)/比较是否为合法候选人if(strcmp(leader_name,leaderj.name)=0)/合法leaderj.count+;/得票数加1for(i=0;i成员名或(*指针变量名).成员名,stu.age=18;(*p).age=18;p->age=18;,30,12.2.7指向结构体类型数据的指针,#include#includestructStudentlongintnum;charname20;charsex;floatscore;voidmain()structStudentstu_1;structStudent*p;p=,31,12.2.7指向结构体数组的指针,#includestructStudentlongintnum;charname20;charsex;intage;voidmain()structStudent*p;structStudentstu=10101,"李林",M,18,10102,"张奋",M,19,10103,"王敏",F,20;printf("学号姓名性别年龄n");for(p=stu;pnum,p->name,p->sex,p->age);,32,12.2.7指向结构体数组的指针,p=stu,p+1,p+2,stu0,stu1,stu2,33,12.2.8结构体作为函数参数,可以将结构体作为参数传递给函数,也可以定义返回结构体值的函数。结构体作为函数参数有三种不同方法:将结构体变量成员的值传递给函数处理。将整个结构体变量作为参数值传递给函数。将结构体指针变量做函数的参数。,把结构体作为整体来处理,但作用方式和效果不同。,34,整个结构体作为参数,structdateintyear;intmonth;intday;voidfunc(structdatep)p.year=2000;p.month=5;p.day=22;,voidmain()structdated;d.year=1999;d.month=4;d.day=23;printf("%d,%d,%dn",d.year,d.month,d.day);func(d);printf("%d,%d,%dn",d.year,d.month,d.day);,1999,4,23,1999,4,23,12.2.8结构体作为函数参数,35,函数返回值为结构体,structdateintyear;intmonth;intday;structdatefunc(structdatep)p.year=2000;p.month=5;p.day=22;returnp;,voidmain()structdated;d.year=1999;d.month=4;d.day=23;printf(“%d,%d,%dn”,d.year,d.month,d.day);d=func(d);printf(“%d,%d,%dn”,d.year,d.month,d.day);,12.2.8结构体作为函数参数,1999,4,23,2000,5,22,36,结构体指针做为参数,structdateintyear;intmonth;intday;voidfunc(structdate*p)p->year=2000;p->month=5;p->day=22;,voidmain()structdated;d.year=1999;d.month=4;d.day=23;printf(“%d,%d,%dn”,d.year,d.month,d.day);func(,1999,4,23,2000,5,22,12.2.8结构体作为函数参数,37,【例12.7】修改例12.3程序,用结构体数组作函数参数编程并输出计算学生的平均分,12.2.8结构体作为函数参数,38,12.2.8结构体作为函数参数,39,12.2.8结构体作为函数参数,40,12.2.8结构体作为函数参数,41,12.3共用体(P362-365),共用体(union)又称联合体,把情形互斥但逻辑相关的多种类型的数据组织在一起,共同占用同一段内存的用户自定义数据类型。,该栏目按性别填写不同内容,共用体,42,12.3共用体,共用体类型的定义,union共用体类型名数据类型名1成员名1;数据类型名2成员名2;数据类型名n成员名n;,类型定义不分配内存,共占4字节sizeof(unionUData)=sizeof(f),共用体的大小是成员中占内存最大的成员的大小,unionUDatashorti;charch;floatf;,43,12.3共用体,共用体与结构体的异同共用体与结构体都是由多个成员分量组成的一个整体;共用体与结构体在定义、说明和使用(成员引用、指针)上十分相似。结构体:多个成员分量分别占用不同的存储空间构成一个整体;成员分量之间是相互独立的,所进行的各种操作互不影响。共用体:多个成员分量共同占用同一存储空间;成员分量之间是相互联系的,所进行的操作相互依赖。共用体:同一内存单元在每一瞬时只能存放其中一种类型的成员;起作用的成员是最后一次存放的成员,不能作为函数参数,不能进行比较操作,只能对第一个成员初始化,44,【例1】设有一个教师与学生通用的表格,教师数据有姓名、年龄、职业,教研室四项。学生有姓名、年龄、职业、班级四项。编程输入人员数据,再以表格输出。,#includestructStu_Teacharname10;/姓名intage;/年龄charjob;/工作s-表示学生,t-表示教师unionintclassno;/学生班级号charoffice10;/教师教研室名depart;,voidmain()structStu_Teabody2;inti;for(i=0;i<2;i+)/输入学生或教师信息printf("inputname,age,jobanddepartmentn");scanf("%s%d%c",bodyi.name,/显示输入的学生、教师信息printf("nametagejobclass/officen");for(i=0;inext=NULL,12.6链表的基本操作-链表的建立,56,若原链表为非空,则将新建节点p添加到表尾,(1)pr->next=p,(2)pr=p,(3)pr->next=NULL,next,12.6链表的基本操作-链表的建立,57,structLink*AppendNode(structLink*head)structLink*p=null,*pr=head;intdata;p=(structLink*)malloc(sizeof(structLink);if(p=NULL)printf(“Noenoughmemorytoallocate!n”);exit(0);if(head=NULL)head=p;elsewhile(pr->next!=NULL)pr=pr->next;pr->next=p;printf(“Inputnodedata:”);scanf(“%d”,若原链表为空表,则退出程序若待删除节点p是头节点,则将head指向当前节点的下一个节点即可删除当前节点,(1)head=p->next,head,(2)free(p),从链表中删除一个节点,12.6链表的基本操作-链表的删除,58,若待删除节点不是头节点,则将前一节点的指针域指向当前节点的下一节点即可删除当前节点,(1)pr->next=p->next,若已搜索到表尾(p->next=NULL)仍未找到待删除节点,则显示“未找到”,(2)free(p),12.6链表的基本操作-链表的删除,59,structLink*DeleteNode(structLink*head,intdata)structLink*p=head,*pr=head;if(p=NULL)printf(“LinkTableisempty!n”);returnhead;while(data!=p->data,若原链表为空表,则将新节点p作为头节点,让head指向新节点p,(1)head=p,p=(structlink*)malloc(sizeof(structlink);p->next=NULL;p->data=nodeData;,12.6链表的基本操作-链表的插入,62,若原链表为非空,则按节点值(假设已按升序排序)的大小确定插入新节点的位置若在头节点前插入新节点,则将新节点的指针域指向原链表的头节点,且让head指向新节点,(2)head=p,(1)p->next=head,12.6链表的基本操作-链表的插入,63,若在链表中间插入新节点,则将新节点的指针域指向下一节点且让前一节点的指针域指向新节点,(2)pr->next=p,(1)p->next=pr->next,12.6链表的基本操作-链表的插入,若在表尾插入新节点,则末节点指针域指向新节点,(1)pr->next=p,next,12.6链表的基本操作-链表的插入,structLink*InsertNode(structLink*head,intdata)structLink*p=head,*pr=head,*temp=NULL;p=(structLink*)malloc(sizeof(structLink);if(p=NULL)printf(“Noenoughmemoryn”);exit(0);p->data=data;p->next=NULL;if(head=NULL)head=p;else,while(pr->datanext!=NULL)temp=pr;pr=pr->next;if(pr->data>=data)if(pr=head)p->next=head;head=p;elsepr=temp;p->next=pr->next;pr->next=p;elsepr->next=p;returnhead;,67,遍历链表的所有节点,12.6链表的基本操作-链表的输出,68,对于动态链表,必须由程序员自己来进行内存的分配与释放。,voidDeleteMemory(structLink*head)structLink*p,*q;p=head;while(p!=NULL)q=p;p=p->next;free(q);,12.6链表的基本操作-链表的释放,69,数据,指针,数据,前指针,后指针,12.6链表的类型,70,12.6链表的类型,环形链表:一种特殊的链表,其尾结点的next指针,又指向了链表的首结点,从而形成了一个圆环。从环形链表的任何一个结点出发,都可以遍历整个的链表。,71,Question?,