C语言教程第八章 结构体_第1页
C语言教程第八章 结构体_第2页
C语言教程第八章 结构体_第3页
C语言教程第八章 结构体_第4页
C语言教程第八章 结构体_第5页
已阅读5页,还剩61页未读 继续免费阅读

下载本文档

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

文档简介

C语言教程第八章结构体第8章结构体

结构体

共用体2024/4/232思考一个问题在程序里表示一个人的信息(姓名、年龄、性别、……),怎么表示?表示多个人呢?如何用计算机程序实现下述表格的管理?表8-1某学校学生成绩管理表学号姓名性别入学时间计算机原理英语数学音乐1令狐冲男1999908372822林平之男1999789288783岳灵珊女1999897298664任莹莹女1999789587905……6……数组的解决方法int studentId[30];/*最多可以管理30个学生,每个学生的学号用数组的下标表示*/char studentName[30][10]; char studentSex[30][2]; inttimeOfEnter[30];/*入学时间用int表示*/intscoreComputer[30];/*计算机原理课的成绩*/intscoreEnglish[30];/*英语课的成绩*/ intscoreMath[30]; /*数学课的成绩*/intscoreMusic[30]; /*音乐课的成绩*/数组的解决方法intstudentId[30]={1,2,3,4,5,6};char studentName[30][10]={{"令狐冲"},{"林平之"},{"岳灵珊"},{"任莹莹"}};char studentSex[30][2]={{"男"},{"男"},{"女"},{"女"}};int timeOfEnter[30]={1999,1999,1999,1999};int scoreComputer[30]={90,78,89,78};int scoreEnglish[30]={83,92,72,95};int scoreMath[30]={72,88,98,87};int scoreMusic[30]={82,78,66,90};数组的解决方法数据的内存管理方式90788978……83927295……72889887……82786690……1234……令狐冲林平之岳灵珊任莹莹……男男女女……1999199919991999……数组的解决方法分配内存不集中,寻址效率不高对数组进行赋初值时,容易发生错位结构显得比较零散,不容易管理希望的内存分配图

1令狐冲男1999908372822林平之男1999789288783岳灵珊女1999897298664任莹莹女199978958790结构体的解决方法structSTUDENT

{

intstudentID;/*每个学生的序号*/ charstudentName[10];/*每个学生的姓名*/ charstudentSex[4];/*每个学生的性别*/ int timeOfEnter;/*每个学生的入学时间*/ int scoreComputer;/*每个学生的计算机原理成绩*/ int scoreEnglish;/*每个学生的英语成绩*/ int scoreMath; /*每个学生的数学成绩*/ int scoreMusic;/*每个学生的音乐成绩*/

};structSTUDENT是一个类型structSTUDENTstudents[4];students[0].studentName

students[0].Sex它们都是变量,一般称为结构的成员变量§8.1结构体的定义结构体类型的定义结构体类型变量的引用结构体变量的初始化structstudent{intnum;charname[20];charsex;intage;charaddr[30];};是数据类型,不是变量名对各成员都要进行类型说明;成员名定名规则与变量名同。一、结构体类型的定义

一般形式为:struct结构体名{

成员表列

};方法一:先定义结构体类型再定义变量名structstudent{intnum;charname[20];charsex;intage;charaddr[30];};structstudentstudent1,student2;定义studet1和sudent2为structstudent类型变量结构体类型变量的定义

有时,可用符号常量代表一个结构体类型,如:#defineSTUDENTstructstudentSTUDENT{intnum;charname[20];charsex;intage;charaddr[30];};这样,可直接用STUDENT定义变量,如:STUDENTstudent1,student2;此时,不必再写关键字struct方法二:在定义类型的同时定义变量structstudent{intnum;charname[20];charsex;intage;charaddr[30];}student1,student2;一般形式是:struct结构体名{成员列表}变量名列表;方法三:直接定义结构类型变量。其一般形式是:struct{

成员表列}变量名表列;此时,不出现结构体名typedef的用法

功能:定义新类型,即为C语言中已有的数据类型名定义一个新名字。定义格式:typedef标识符1标识符2structstudent{intnum;charname[20];charsex;intage;floatscore;charaddr[30];};typedefstructstudentSTUD;STUDstudent1,student2;用typedef为已存在的类型定义新名字用STUD代替structstudent类型;几点说明:1.类型与变量是不同概念,不要混淆;2.结构体中的成员,可以单独使用,其作用与地位相当于普通变量;3.成员名可以与程序中的变量名相同,二者不代表同一对象。structdate{intmonth;intday;intyear;};Structstudent{intnum;charname[20];intage;structdatebirthday;}student1,student2;4.成员也可以是一个结构体变量;例如:规则:1.不能将一个结构体变量作为一个整体进行赋值和输出;只能对其各个成员分别输出printf(“………..”,student1);printf(“%d”,student1.num);错!正确!

引用形式为:结构体变量名.成员名二、结构体类型变量的引用3.对成员变量可以象普通变量一样进行各种运算,如:

sumage=student1.age+student2.age;4.可以引用成员的地址,也可以引用结构体变量的地址,如

scanf(“%d”,&student1.num);printf(“%x”,&student1);scanf(“%d,%s,%c,%d,%s”,&student1);错!输入student1.num的值输出student1的首地址2.若成员本身又属一个结构体类型,只能对最低级的成员进行赋值或存取以及运算。如:

(一)对外部存储类型的结构体变量初始化:

structstudent{longintnum;charname[20];charsex;charaddr[20];}a={9801,”Wanghong”,’W’,”2LinggongRoad”};main(){printf(“No.:%ld\nname:%s\nsex:%c\naddress:%s\n”,a.num,,a.sex,a.addr);}运行结果为:No.:9801name:Wanghongsex:Waddress:2LinggongRoad三、结构体变量的初始化main(){staticstructstudent{longintnum;charname[20];charsex;charaddr[20];}a={9801,”Wanghong”,’W’,”2LinggongRoad”};printf(“No.:%ld\nname:%s\nsex:%c\naddress:%s\n”,a.num,,a.sex,a.addr);}(二)对静态存储类型的结构体变量初始化(一)结构体数组的定义

structstudent{intnum;charname[20];charsex;intage;charaddr[30];};structstudntstu[3];也可直接定义,如structstudent{intnum;…}stu[3];或struct{intnum;…}stu[3];§8.2结构体数组(每个数组元素都是一个结构体类型的数据)structstudent{intnum;charname[20];charsex;intage;charaddr[30];}stu[3]={{111,”Li”,’M’,18,”Dalian”},{…},{…}};结构体数组初始化的一般形式是在定义数组后面加上:={初值表列};也可采用:structstudent{intnum;…};structstudentstu[]={{…},{…},{…}};(二)结构体数组的初始化(只能对全局的或静态存储类别的数组初始化)structperson{charname[20];intcount;}leader[3]={{“Li”,0},{”zhang”,0},{”Liu”,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++;}for(i=0;i<3;i++)printf(“%5s:%d\n”,leader[i].name,leader[i].count);}例题:设有三个候选人,每次输入一个得票的候选人的名字,要求最后输出各人得票结果。例如:

main(){structstudent{longintnum;charname[20];charsex;};structstudentstu_1;structstudent*p;p=&stu_1;Stu_1.num=9901;strcpy(stu_1.name,“LiMin”);stu_1.sex=‘W’;printf(“No.:%ld\nname%s\nsex:%c\n”,stu_1.num,stu_1.name,stu_1.sex);printf(“\nNo.:%ld\nname%s\nsex:%c\n”,(*p).num,(*p).name,(*p).sex);}结构体变量的指针:是该结构体变量所占居的内存段的起始地址。§8.3

指向结构体类型数据的指针引用结构体成员的三种形式:结构体变量名.成员名(*p).成员名p->成员名指向运算符。其优先级高于自增、自减运算符试分析以下运算:成员运算符得到p指向的结构体变量中的成员n的值使其先加1++(p->n)得到p指向的结构体变量中的成员n的值,用完后使它加1;(p->n)++得到p指向的结构体变量中的成员n的值p->nfor(pt=stu;pt<stu+30;pt++){ sum[0]=sum[0]+pt->scoreComputer; sum[1]=sum[1]+pt->scoreEnglish; sum[2]=sum[2]+pt->scoreMath; sum[3]=sum[3]+pt->scoreMusic; }for(i=0;i<4;i++){average[i]=sum[i]/4; printf("%20s:%4.2f\n",name[i],*(average+i)); }例8.2:利用指向结构体数组的指针计算学生各科的平均成绩(教材310页)学号姓名性别入学时间计算机原理年月日英语数学音乐例8.2main(){ structSTUDENT*pt; floatsum[4]={0.0},average[4]={0.0}; int i; char*name[]={"scoreofComputer","scoreofEnglish", "scoreofMath","scoreofMusic"}; pt=stu;/*pt指向结构体数组的第一个元素*/ for(pt=stu;pt<stu+30;pt++) { sum[0]=sum[0]+pt->scoreComputer; sum[1]=sum[1]+pt->scoreEnglish; sum[2]=sum[2]+pt->scoreMath; sum[3]=sum[3]+pt->scoreMusic; } for(i=0;i<4;i++) { average[i]=sum[i]/4; printf("%20s:%4.2f\n",name[i],*(average+i)); }}1.向函数传递结构体的单个成员单向值传递,函数内对结构内容的修改不影响原结构2.用整个结构体变量作实参和形参,向函数传递结构体的完整结构单向值传递,函数内对结构内容的修改不影响原结构,开销大§8.4结构体与函数结构体参与函数运算的几种形式:3.向函数传递结构体的首地址用结构体数组或者结构体指针做函数参数除提高效率外,还可以修改结构体指针所指向的结构体的内容4、用结构体类型作为函数返回类型

一付扑克有52张牌,分为4种花色(Suit):黑桃(Spades)、红桃(Hearts)、草花(Clubs)、方块(Diamonds)每种花色有13张牌面(Face):A,2,3,4,5,6,7,8,9,10,Jack,Queen,King设计一个结构体表示一张牌,由两个成分组成:花色、牌面:structCARD{ char suit[10]; char face[10];};

structCARDcard[52];/*顺序存放扑克牌*/intresult[52]; /*存放洗牌发牌结果*/char*suit[]={"Spades","Hearts","Clubs","Diamonds"};char*face[]={"A","2","3","4","5","6","7","8","9","10","jack","Queen","King"};

例8.1:洗牌和发牌模拟发牌过程将52张牌按照随机的顺序存放算法步骤:产生0~51的随机数,将其放于result[i]内。i=i+1如果i<=51,则重复第2步,否则,结束循环输出结果存在一个致命的问题:在重复第2步时,产生的随机数可能与以前产生的随机数相同,相同意味着52张牌中出现2张以上相同的牌例8.1:洗牌和发牌模拟解决方法增加一步,判断新产生的随机数以前是否出现过如果出现过,则放弃;如果以前未出现过,则保留算法步骤:产生0~51的随机数m,将其放于result[i]内。判断result[i]在以前(result[0]~result[i-1])是否出现过。如果出现过,则回到第2步;如果没出现过,则i=i+1如果i<=51,则重复第2~3步,否则,结束循环输出结果例8.1:洗牌和发牌模拟算法缺陷:随着随机数数量的增加,新的随机数与已经产生的随机数相同的可能性越来越大,有可能出现算法延迟问题高效算法将按照花色与牌面的顺序存放的牌(card[i])随机打乱每次循环,程序选择一个0~51的随机数j,然后将数组中当前的CARD结构card[i]与随机选出的j所在的数组元素card[j]结构进行交换例8.1:洗牌和发牌模拟用结构体数组做函数参数voidFillCard(structCARDwCard[],char*wFace[],char*wSuit[]){ int i; for(i=0;i<52;i++) { strcpy(wCard[i].suit,wSuit[i/13]); strcpy(wCard[i].face,wFace[i%13]); }}例8.1:洗牌和发牌模拟(P313)用结构体指针做函数参数voidShuffle(structCARD*wCard){ inti,j; structcardtemp; for(i=0;i<52;i++) { j=rand()%52;/*j=random(52);TC的库函数*/ temp=wCard[i]; wCard[i]=wCard[j]; wCard[j]=temp; /*洗牌过程*/ }}例8.1:洗牌和发牌模拟(P313)用结构体指针做函数参数voidDeal(structCARD*wCard){ inti; for(i=0;i<52;i++) /*输出发牌结果*/ printf("%10s%10s\n",wCard[i].suit,wCard[i].face);}例8.1:洗牌和发牌模拟(P313)思考题structpoint

{

intx;

inty;

};

structrect

{

structpointpt1;

structpointpt2;

};structrectrt,*rp=&rt;下面表达式哪些合法?(*rp).pt1.xrp->pt1.xrt->pt1.x实验九结构体编程练习

在屏幕上模拟显示一个数字式时钟定义一个时钟结构体类型:structclock{inthour;intminute;intsecond;};typedefstructclockCLOCK;voidupdate(CLOCK*t){t->second++;if(t->second==60){t->second=0;t->minute++;}

if(t->minute==60){t->minute=0;t->hour++;}if(t->hour==24)t->hour=0;}voiddisplay(CLOCK*t){printf("%2d:%2d:%2d\r",t->hour, t->minute, t->second);}实验九结构体编程练习

在屏幕上模拟显示一个数字式时钟

内存动态分配函数

C语言提供以下几个动态存储分配函数:malloc(size)calloc(n,size)free(ptr)§8.5用指针处理链表1.malloc(size)

功能:在内存的动态存储区分配一个长度为size的连续空间。此函数的返回值是一个指针,它的值是该分配区域的起始地址。若此函数未能成功地执行,则返回值为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)函数分配的内存空间原来没有被使用过,则其中的每一位都可能是0;如果这部分内存空间曾经被分配、释放和重新分配,则其中可能遗留各种各样的数据。calloc(n,size)函数会将所分配的内存空间的每一位都初始化为0malloc(size)与calloc(n,size)的返回值处理malloc(size)与calloc(n,size)的返回值都是void类型的指针,具有一般性,是抽象类型的数据若将函数调用的返回值赋予某指针,则应先根据该指针的基类型,对返回的指针进行强制类型转换。链表的概念链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。链表有一个“头指针”变量,它存放一个地址,该地址指向链表中的第一个元素。如下图所示:NULLhead…...链表中每一个元素称为“结点”每个结点都应包括两个部分:数据域:用户需要用的实际数据指针域:下一个结点的地址

结点1结点2结点n可以看出:头指针head指向第一个元素;第一个元素又指向第二个元素;…...直到最后一个元素,该元素不再指向其它元素,它称为“链尾”,其地址部分存放一个“NULL”(表示“空地址”)。链表到此结束。对于两个相邻的结点p1、p2,p1是p2的直接前驱结点,p2是p1的直接后继结点NULLhead…...p1p2由此可以看出:链表中结点必须是结构体类型,其中一个成员是指针类型,这个指针类型指向它所在的结构体类型。其中next是成员名,是指针类型,它指向structlink类型数据例如:structlink{intdata;structlink*next;};

Datanext数据域指针域前面只是定义了一个structlink类型,并未实际分配存储空间,可用前述方法在需要时动态地开辟和释放存储单元。例如:#include“stdlib.h”p=(structlink*)malloc(sizeof(structlink));if(p!=NULL){p->data=10;p->next=NULL;}10NULLP其中sizeof()的功能是测试某种类型的变量在内存中所占用的字节数。例如,sizeof(float)的值是4,它表示float型变量在内存中占4个字节。free(p);

structLink{intdata;StructLink*next;};线性表的链式存储结构——可用C语言中的“结构指针”来描述a1a2∧ana3L…..带头结点的线性链表datanexta1a2∧ana3L…..不带头结点的线性链表1、动态链表的建立(新结点链接在链尾)NULLhead初态第一次插入第n次插入headPrNULLa1headPrNULLa1an2、在头指针为h的单链表中查找结点xStructlink*dlbcz(Structlink*h,intx){Structlink*p;p=h;while(p!=NULL&&p->data!=x)p=p->next;return(p);}

structLink{intdata;StructLink*next;};3、单链表的插入运算(后插)

voiddlbhcr(structLink*p,intx){structLink*s;s=(structLink*)malloc(sizeof(structLink));if(s!=NULL){s->data=x;s->next=p->next;p->next=s;}elseprintf(“unsucess!”);}baPbaxPS∧anaia1a2ai-1xheadSPai-1a1aiai+1LpqVoiddlbsc(structLink*p){structLink*q;if(p->next!=NULL){q=p->next;p->next=q->next;free(q);}}4、单链表的删除运算(在单链表中删除p结点的直接后继结点q)5、单链表中直接插入或删除某个结点p插入某个结点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=

温馨提示

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

评论

0/150

提交评论