1、Click to edit Master title style,Click to edit Master text styles,Second level,Third level,Fourth level,Fifth level,*,第,8,章 结构体,结构体,共用体,1,F,2,思考一个问题,在程序里表示一个人的信息(姓名、年龄、性别、,),怎么表示?,表示多个人呢?,如何用计算机程序实现下述表格的管理?,表,8-1,某学校学生成绩管理表,学号,姓名,性别,入学时间,计算机原理,英 语,数 学,音 乐,1,令狐冲,男,1999,90,83,72,82,2,林平之,男,1999,78,92,
2、88,78,3,岳灵珊,女,1999,89,72,98,66,4,任莹莹,女,1999,78,95,87,90,5,6,数组的解决方法,int studentId30;,/*,最多可以管理,30,个学生,每个学生的学号用数组的下标表示*,/,charstudentName3010;,charstudentSex302;,int timeOfEnter30;,/*,入学时间用,int,表示*,/,int scoreComputer30;,/*,计算机原理课的成绩*,/,int scoreEnglish30;,/*,英语课的成绩*,/,int scoreMath30;,/*,数学课的成绩*,/,i
3、nt scoreMusic30;,/*,音乐课的成绩*,/,数组的解决方法,int,studentId30=1,2,3,4,5,6;,char,studentName3010=,令狐冲,林平之,岳灵珊,任莹莹,;,char,studentSex302=,男,男,女,女,;,int,timeOfEnter30=1999,1999,1999,1999;,int,scoreComputer30=90,78,89,78;,int,scoreEnglish30=83,92,72,95;,int,scoreMath30=72,88,98,87;,int,scoreMusic30=82,78,66,90;,
4、数组的解决方法,数据的内存管理方式,90,78,89,78,83,92,72,95,72,88,98,87,82,78,66,90,1,2,3,4,令狐冲,林平之,岳灵珊,任莹莹,男,男,女,女,1999,1999,1999,1999,数组的解决方法,分配内存不集中,寻址效率不高,对数组进行赋初值时,容易发生错位,结构显得比较零散,不容易管理,希望的内存分配图,1,令狐冲,男,1999,90,83,72,82,2,林平之,男,1999,78,92,88,78,3,岳灵珊,女,1999,89,72,98,66,4,任莹莹,女,1999,78,95,87,90,结构体的解决方法,struct ST
5、UDENT int studentID;/*,每个学生的序号*,/,char studentName10;/*,每个学生的姓名*,/,char studentSex4;/*,每个学生的性别*,/,inttimeOfEnter;/*,每个学生的入学时间*,/,intscoreComputer;/*,每个学生的计算机原理成绩*,/,intscoreEnglish;/*,每个学生的英语成绩*,/,intscoreMath;/*,每个学生的数学成绩*,/,intscoreMusic;/*,每个学生的音乐成绩*,/;,struct STUDENT,是一个类型,struct STUDENT student
6、s4;,students0.studentNamestudents0.Sex,它们都是变量,一般称为结构的成员变量,8.1,结构体的定义,结构体类型的定义,结构体类型变量的引用,结构体变量的初始化,struct student,int num;,char name20;,char sex;,int age;,char addr30;,;,是数据类型,不是变量名,对各成员都要进行类型说明;,成员名定名规则与变量名同。,一、结构体类型的定义,一般形式为:,struct,结构体名,成员表列,;,方法一:先定义结构体类型再定义变量名,struct student,int num;,char name2
7、0;,char sex;,int age;,char addr30;,;,struct student,student1,student2;,定义,studet1,和,sudent2,为,struct student,类型变量,结构体类型变量的定义,有时,可用符号常量代表一个结构体类型,,如:,#,define,STUDENT,struct student,STUDENT,int num;,char name20;,char sex;,int age;,char addr30;,;,这样,可直接用,STUDENT,定义变量,如:,STUDENT student1,student2;,此时,不必
8、再写关键字,struct,方法二:在定义类型的同时定义变量,struct student,int num;,char name20;,char sex;,int age;,char addr30;,student1,student2;,一般形式是:,struct,结构体名,成员列表,变量名列表;,方法三:直接定义结构类型变量。,其一般形式是:,struct,成员表列,变量名表列;,此时,不出现结构体名,typedef,的用法,功能:定义新类型,即为,C,语言中已有的数据类型,名定义一个新名字。,定义格式:,typedef,标识符1 标识符2,struct,student,int,num;,ch
9、ar,name20;,char,sex;,int,age;,float,score;,char,addr30;,;,typedef,struct,student,STUD;,STUD,student1,student2;,用,typedef,为已存在的类型定义新名字,用,STUD,代替,struct,student,类型;,几点说明:,1.类型与变量是不同概念,不要混淆;,2.结构体中的成员,可以单独使用,其作 用与地位相当于普通变量;,3.成员名可以与程序中的变量名相同,二 者不代表同一对象。,struct date,int month;,int day;,int year;,;,Struc
10、t student,int num;,char name20;,int age;,struct date birthday;,student1,student2;,4.成员也可以是一个结构体变量;,例如:,规则:,1.,不能将一个结构体变量作为一个整体进行赋值和输出;只能对其各个成员分别输出,printf(“.”,student1);,printf(“%d”,student1.num);,错!,正确!,引用形式为:,结构体变量名.成员名,二、结构体类型变量的引用,3.,对成员变量可以象普通变量一样进行各种运算,如:,sumage=student1.age+student2.age;,4.,可以
11、引用成员的地址,也可以引用结构体变量的地址,如,scanf(“%d”,printf(“%x”,scanf(“%d,%s,%c,%d,%s”,错!,输入,student1.num,的值,输出,student1,的首地址,2.,若成员本身又属一个结构体类型,只能对最低级的,成员进行赋值或存取以及运算。,如:,student1.birthday.year,(一)对外部存储类型的结构体变量初始化,:,struct student,long int num;,char name20;,char sex;,char addr20;,a=9801,”Wang hong”,W,”2 Linggong Road
12、main(),printf(“No.:%ldnname:%snsex:%cnaddress:%sn”,a.num,a.name,a.sex,a.addr);,运行结果为:,No.:9801,name:Wang hong,sex:W,address:2 Linggong Road,三、结构体变量的初始化,main(),static struct student,long int num;,char name20;,char sex;,char addr20;,a=9801,”Wang hong”,W,”2 Linggong Road”;,printf(“No.:%ldnname:%snse
13、x:%cnaddress:%sn”,a.num,a.name,a.sex,a.addr);,(二)对静态存储类型的结构体变量初始化,(一)结构体数组的定义,struct student,int num;,char name20;,char sex;,int age;,char addr30;,;,struct studnt stu3;,也可直接定义,如,struct student,int num;,stu3;,或,struct,int num;,stu3;,8.2,结构体数组,(,每个数组元素都是一个结构体类型的数据,),struct student,int num;,char name20
14、char sex;int age;,char addr30;,stu3=111,”Li”,M,18,”Dalian”,;,结构体数组 初始化的一般形式是在,定义数组后面加上:,=初值表列;,也可采用:,struct student,int num;,;,struct student stu=,;,(二)结构体数组的初始化(只能对全局的或静态存储 类别的数组初始化),struct person,char name20;,int count;,leader3=“Li”,0,”zhang”,0,”Liu”,0;,main(),int i,j;char leader_name20;,for(i=1
15、i=10;i+),scanf(“%s”,leader_name);,for(j=0;j3;j+),if(strcmp(leader_name,leaderj.name)=0)leaderj.count+;,for(i=0;i,成员名,指向运算符。其优先级高于自增、自减运算符,试分析以下运算:,成员运算符,得到,p,指向的结构体变量中的成员,n,的值,使其先加1,+,(,p-n,),得到,p,指向的结构体变量中的成员,n,的值,用完后使它加1;,(,p-n,),+,得到,p,指向的结构体变量中的成员,n,的值,p-n,for,(pt=stu;ptscoreComputer;,sum1=sum1
16、pt-scoreEnglish;,sum2=sum2+pt-scoreMath;,sum3=sum3+pt-scoreMusic;,for,(i=0;i4;i+),averagei=sumi/4;,printf,(%20s:%4.2fn,namei,*(average+i);,例,8.2:,利用指向结构体数组的指针计算学生各科的平均成绩(教材,310,页),学号,姓名,性别,入学时间,计算机,原理,年,月,日,英语,数学,音乐,例,8.2,main,(),struct,STUDENT*pt;,float,sum4=0.0,average4=0.0;,int,i;,char,*,name=sc
17、ore of Computer,score of English,score of Math,score of Music;,pt=stu;/*pt,指向结构体数组的第一个元素*,/,for,(pt=stu;ptscoreComputer;,sum1=sum1+pt-scoreEnglish;,sum2=sum2+pt-scoreMath;,sum3=sum3+pt-scoreMusic;,for,(i=0;i4;i+),averagei=sumi/4;,printf,(%20s:%4.2fn,namei,*(average+i);,1.向函数传递结构体的单个成员,单向值传递,函数内对结构内容
18、的修改不影响原结构,2.用整个结构体变量作实参和形参,,向函数传递结构体的完整结构,单向值传递,函数内对结构内容的修改不影响原结构,开销大,8.4,结构体与函数,结构体参与函数运算的几种形式:,3.向函数传递结构体的首地址,用结构体数组或者结构体指针做函数参数,除提高效率外,还可以修改结构体指针所指向的结构体的内容,4、用结构体类型作为函数返回类型,一付扑克有,52,张牌,分为,4,种花色,(Suit),:,黑桃,(Spades),、红桃,(Hearts),、草花,(Clubs),、方块,(Diamonds),每种花色有,13,张牌面,(Face),:,A,,,2,,,3,,,4,,,5,,,
19、6,,,7,,,8,,,9,,,10,,,Jack,,,Queen,,,King,设计一个结构体表示一张牌,由两个成分组成:花色、牌面:,struct CARD,char suit10;,char face10;,;,struct CARD card52;/*,顺序存放扑克牌*,/,int result52;/*,存放洗牌发牌结果*,/,char*suit=Spades,Hearts,Clubs,Diamonds;,char*face=A,2,3,4,5,6,7,8,9,10,jack,Queen,King;,例,8.1:,洗牌和发牌模拟,发牌过程,将,52,张牌按照随机的顺序存放,算法步骤:
20、产生,051,的随机数,将其放于,resulti,内。,i=i+1,如果,i=51,,则重复第,2,步,否则,结束循环,输出结果,存在一个致命的问题:,在重复第,2,步时,产生的随机数可能与以前产生的随机数相同,相同意味着,52,张牌中出现,2,张以上相同的牌,例,8.1:,洗牌和发牌模拟,解决方法,增加一步,判断新产生的随机数以前是否出现过,如果出现过,则放弃;如果以前未出现过,则保留,算法步骤:,产生,051,的随机数,m,,将其放于,resulti,内。,判断,resulti,在以前,(result0resulti-1),是否出现过。如果出现过,则回到第,2,步;如果没出现过,则,i=
21、i+1,如果,i=51,,则重复第,23,步,否则,结束循环,输出结果,例,8.1:,洗牌和发牌模拟,算法缺陷,:,随着随机数数量的增加,新的随机数与已经产生的随机数相同的可能性越来越大,有可能出现算法延迟问题,高效算法,将按照花色与牌面的顺序存放的牌(,cardi,)随机打乱,每次循环,程序选择一个,051,的随机数,j,,然后将数组中当前的,CARD,结构,cardi,与随机选出的,j,所在的数组元素,cardj,结构进行交换,例,8.1:,洗牌和发牌模拟,用结构体数组做函数参数,void,FillCard(,struct,CARD wCard,char,*wFace,char,*wSui
22、t),int,i;,for,(i=0;i52;i+),strcpy,(wCardi.suit,wSuiti/13);,strcpy,(wCardi.face,wFacei%13);,例,8.1:,洗牌和发牌模拟(,P313,),用结构体指针做函数参数,void,Shuffle(,struct,CARD*wCard),int,i,j;,struct,card temp;,for,(i=0;i52;i+),j=rand()%52;,/*j=random(52);TC,的库函数*,/,temp=wCardi;,wCardi=wCardj;,wCardj=temp;,/*,洗牌过程*,/,例,8.1:
23、洗牌和发牌模拟(,P313,),用结构体指针做函数参数,void,Deal(,struct,CARD*wCard),int,i;,for,(i=0;ipt1.x,rt-pt1.x,实验九 结构体编程练习在屏幕上模拟显示一个数字式时钟,定义一个时钟结构体类型:,struct,clock,int,hour;,int,minute;,int,second;,;,typedef,struct,clock CLOCK;,void,update(CLOCK*t),t-second+;,if,(t-second=60),t-second=0;,t-minute+;,if,(t-minute=60),t-m
24、inute=0;,t-hour+;,if,(t-hour=24),t-hour=0;,void,display(CLOCK*t),printf(%2d:%2d:%2dr,t-hour,t-minute,t-second);,实验九 结构体编程练习在屏幕上模拟显示一个数字式时钟,内存动态分配函数,C,语言提供以下几个动态存储分配函数:,malloc(size),calloc(n,size),free(ptr),8.5,用指针处理链表,1.,malloc(size),功能:在内存的动态存储区分配,一个,长度为,size,的连续空间。,此函数的返回值是一个指针,它的值是该分配区域的起始地址。,若此函
25、数未能成功地执行,则返回值为0。,2.,calloc(n,size),功能:在内存的动态存储区中分配,n,个,长度为,size,的连续空间。,3.,free(ptr),功能:释放由,ptr,指向的内存区。,ptr,是最近一次调用,malloc,或,calloc,函数时返回的值。,函数返回分配域的起始地址;若分配不成功,返回0。,malloc(size),与,calloc(n,size),的区别,malloc(size),不能初始化所分配的内存空间,calloc(n,size),能初始化所分配的内存空间,如果由,malloc(size),函数分配的内存空间 原来没有被使用过,则其中的每一位都可能
26、是0;如果这部分内存空间曾经被分配、释放和重新分配,则其中可能遗留各种各样的数据。,calloc(n,size),函数会将所分配的内存空间 的每一位都初始化为0,malloc(size),与,calloc(n,size),的返回值处理,malloc(size),与,calloc(n,size),的返回值都是,void,类型的指针,具有一般性,是抽象类型的数据,若将函数调用的返回值赋予某指针,则应先根据该指针的基类型,对返回的指针进行强制类型转换。,链表的概念,链表,是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。,链表有一个“,头指针,”变量,它存放一个地址,该地址指向链表中的第
27、一个元素。如下图所示:,NULL,head,.,链表中每一个元素称为“,结点,”,每个结点都应包括两个部分:,数据域:用户需要用的实际数据,指针,域:下一个结点的地址,结点1,结点2,结点,n,可以看出:,头指针,head,指向第一个元素;,第一个元素又指向第二个元素;.直到最后一个元素,该元素不再指向其它元素,它称为“,链尾,”,其地址部分存放一个“,NULL,”(,表示“空地址”)。链表到此结束。,对于两个相邻的结点,p1、p2,p1,是,p2,的直接前驱结点,,p2,是,p1,的直接后继结点,NULL,head,.,p1,p2,由此可以看出:,链表中结点必须是结构体类型,其中一个成员是指
28、针类型,这个指针类型指向它所在的结构体类型。,其中,next,是成员名,是指针类型,它指向,struct link,类型数据,例如:,struct link,int data;,struct link*next;,;,Data next,数据域,指针域,前面只是定义了一个,struct link,类型,并未实际分配存储空间,可用前述方法在需要时动态地开辟和释放存储单元。例如:,#,include“stdlib.h”,p=(struct link*)malloc(sizeof(struct link);,if(p!=NULL),p-data=10;,p-next=NULL;,10,NULL,P,
29、其中,sizeof(),的功能是测试某种类型的变量在内存中所占用的字节数。,例如,,sizeof(float),的值是4,它表示,float,型变量在内存中占4个字节。,free(p);,struct Link,int data;,Struct Link*next;,线性表的链式存储结构,可用,C,语言中的,“,结构指针,”,来描述,a,1,a,2,a,n,a,3,L,.,带头结点的线性链表,data,next,a,1,a,2,a,n,a,3,L,.,不带头结点的线性链表,1、动态链表的建立,(新结点链接在链尾),NULL,head,初态,第一次插入,第,n,次插入,head,Pr,NULL,
30、a1,head,Pr,NULL,a1,an,2、在头指针为,h,的单链表中查找结点,x,Struct link *dlbcz(Struct link *h,int x),Struct link *p;,p=h;,while(p!=NULL&p-data!=x),p=p-next;,return(p);,struct Link,int data;,Struct Link*next;,3、单链表的插入运算(后插),void,dlbhcr(struct Link *p,int x),struct Link *s;,s=(struct Link*)malloc(sizeof(struct Link);
31、if(s!=NULL)s-data=x;s-next=p-next;p-next=s;,else printf(“unsucess!”);,b,a,P,b,a,x,P,S,a,n,a,i,a,1,a,2,a,i-1,x,head,S,P,a,i-1,a,1,a,i,a,i+1,L,p,q,Void dlbsc(,struct Link *p,),struct Link *q;,if(p-next!=NULL),q=p-next;p-next=q-next;free(q);,4、单链表的删除运算,(在单链表中删除,p,结点的直接后继结点,q),5、单链表中直接插入或删除某个结点,p,插入某个结
32、点,p,时需考虑:,1.插入点,p,在第一个结点之前,应修改头指针,head,及其指向,即:,p-next=head;head=p;,2.,插入点,p,在链表中间,应修改插入点前,pr,结点的指向,即:,p-next=pr-next;pr-next=p;,3.,插入点,p,在链尾,应修改原链表最后一个结点,pr,指针域的指向,并将新插入的结点,p,的指针域赋为,NULL.,即:,p-next=NULL;pr-next=p;,删除某个结点,p,时需考虑:,1.欲删除的结点,p,是第一个结点,应修改头指针,head,及其指向,即:,head,=,p-next;free(p);,2.,欲删除的结点,
33、p,在链表中间或链尾,应修改欲删除的结点,p,之前,pr,结点的指向,即:,pr-next,=,p-next;free(p);,动态数组(一般了解),用,calloc(n,size),函数开辟的存储单元相当于一个一维数组,第一个参数,n,决定了一维数组的大小,第二个参数,size,决定了数组元素的类型,函数的返回值就是数组的首地址,8.7,共 用 体(联合体),一、共用体类型的定义,一般形式为:,union,共用体名,成员表列,;,例:,union number,int x;,float y;,;,二、共用体变量的定义,例:,union number,int x;,float y;,s1,s2
34、变量,s1,的存储空间为:,S1.y,S1.x,三、共用体变量的引用,注意:不能引用共用体变量,仅能引用共用体变量中的成员。,如:,printf(“%d”,s1);,错,printf(“%d,%d”,s1.x,s1.y);,对,1.同一段内存允许有多种类型的成员,某一时刻仅 一个成员起作用。,2.共用体使用覆盖技术,起作用的是最后一次存放的成员。,如:,s1.x=1;s1.y=3.5;s1.y,有效,3.变量及各成员的地址相同。,4.不能对共用体变量名赋值。,5.共用体变量初始化时,只能对第一个成员的数据类型初始化。,6.两个,共用体变量不能进行比较操作,四、对,共用体变量的有关说明,与结
35、构体的异同:,相同之处:类型说明形式、变量定义方式与结构体相同。,不同之处:结构体变量中各成员有独立的存 储空间,而共用体中所有成员,共用,同一存储空间。,姓名,name,性别,sex,年龄,age,婚姻状况,婚姻状况,标记,未婚,已婚,离婚,配,偶,子,女,年,月,日,struct,person,char,name20;,char,sex;,int,age;,union,int,single;,struct,char,spouseName20;,int,child;,married;,struct,date divorcedDay;,marital;,int,marryFlag;,;,共用体的应用,这一章我们学习了,两种新的数据类型,结构体和共用体,几种重要的应用,结构体数组,结构体指针,用结构体指针做函数参数,用结构体指针实现动态数据结构,






