结构类型数据描述课件_第1页
结构类型数据描述课件_第2页
结构类型数据描述课件_第3页
结构类型数据描述课件_第4页
结构类型数据描述课件_第5页
已阅读5页,还剩35页未读 继续免费阅读

下载本文档

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

文档简介

第11章结构类型数据描述11.1结构体11.2共用体11.3枚举类型11.4

用typedef定义类型名11.5

位段结构第11章结构类型数据描述11.1结构体11.2共用体第11章结构类型数据描述

这种多项组合又有内在联系的的数据称为结构体(structure)。它是可以由用户自己定义的。11.1结构体

在实际应用中,有时需要将一些有相互联系而类型不同的数据组合成一个有机的整体,以便于引用。如学生学籍档案中的学号、姓名、性别、年龄、成绩、地址等数据,对每个学生来说,除了其各项的值不同外,但表示形式是一样的。numnamesexagescoreAddr10010LiFunF1887.5Beijing1.概述第11章结构类型数据描述这种多项组合又有内数据类型数据类型基本类型构造类型指针类型()空类型(void)字符型(char)数值类型枚举类型(enum)数组类型([])结构体类型(struct)共用体类型(union)整型(short,int,long,unsigbed)实型单精度型(float)双精度型(double)数据类型数据类型基本类型构造类型指针类型()空类型(voi2.结构体类型变量的定义两者缺一不可1)结构体类型的定义形式struct结构体名{分量表};其中“分量表”中的分量也应进行类型说明,例如:

struct

student

{

intnum; charname[20]; charsex; intage; floatscore; charaddr[30]; };即:类型标识符分量名;分量描述2.结构体类型变量的定义两者缺一不可1)结构体类型的由用户定义的“结构体类型”,可以同标准类型一样作为定义变量的类型。2)定义结构体类型变量的方法先定义结构体类型再定义变量定义了结构体类型struct

student后,可以用它定义变量。注:不能写成structst1,st2;必须同时指定结构体名。

为了方便起见,可以在程序开头定义符号常量进行简化。如:如:structstudentst1,st2;由用户定义的“结构体类型”,可以同标准类型一样则在程序中可以直接写成:

STUDENT {

intnum; charname[20]; charsex; intage; floatscore; charaddr[30]; }; #defineSTUDENTstructstudentSTUDENTst1,st2;则在程序中可以直接写成:#defineSTUDENTst

在定义类型的同时定义变量如:structstudent {

intnum; charname[20]; charsex; intage; floatscore; charaddr[30]; }st1,st2;struct结构体名{分量表;}变量表;则一般定义形式为:在定义类型的同时定义变量如:structstudent

直接定义结构类型变量定义形式为:

struct

{

分量表;

}

变量表;

在struct后不出现结构体名,因此也不能再以此定义相同的结构体变量。3.关于结构体类型的几点说明类型与变量是两个不同的概念。一般先定义结构体类型,再定义变量为该类型。变量可以赋值、存取或运算,而类型没有这些操作。在编译时,对变量分配空间,对类型来说不存在分配空间。对结构体中的分量可以单独使用。直接定义结构类型变量定义形式为:

struct

分量也可以是一个结构体变量。如student中要增加birthday,则可按如下方式进行定义:structdate{

intmonth;intday;intyear;};structstudent{…structdatebirthday;

…}st1,st2;先定义一个日期结构该分量也是一个结构体分量名可以与程序中的变量名相同,两者之间不会产生混淆。分量也可以是一个结构体变量。如student中要增加4.结构体类型变量的引用引用结构体变量应遵守如下规则:1)结构体变量中分量的引用方式结构体变量名

分量名[

二级分量名]其中:“”为分量运算符,在所有的运算符中优先级最高。2)结构体变量的分量本身又属于结构体类型时只能对最低级分量进行操作。如:st1.num;;st1.birthday.day;写成st1.birthday并不会访问st1中的birthday,只会引起警告错误。4.结构体类型变量的引用引用结构体变量应遵守如下规则:13)不能将一个结构体变量直接进行输入输出,只能对结构体变量的各分量进行输入输出。如:scanf(“%d,%s,%c,%d,%f,%s”,&st1);Xprintf(“%d,%s,%c,%d,%f,%s”,st1);Xprintf(“%s,%d”,,st1.birthday.day);√4)分量和结构体变量的地址均可以被引用如:scanf(“%d”,&st1.num);输入st1.num的值printf(“%x”,&st1);以十六进制输出st1的首地址3)不能将一个结构体变量直接进行输入输出,只能对结如:s5.结构体变量的初始化1)外部存储类的结构体变量初始化例11.1structstudent{longintnum;charname[20];charsex;charaddr[30];}a={89031,“LiLin”,‘M’,“123BeijingRoad”};voidmain(){printf(“%ld,%s,%c,%s\n”,a.num,,a.sex,a.addr);}输出结果:89031,LiLin,M,123BeijingRoad定义结构体的同时定义变量a并进行初始化。5.结构体变量的初始化1)外部存储类的结构体变量初始2)静态存储类的结构体变量初始化voidmain(){structstudent{longintnum;charname[20];charsex;charaddr[30];}a={89031,“LiLin”,‘M’,“123BeijingRoad”};printf(“%ld,%s,%c,%s\n”,a.num,,a.sex,a.addr);}可以将定义部分放在main函数中6.结构体数组

结构体数组与普通数组的不同之处在于每个数组元素都是一个结构体类型的数据,且这些数据又分别包括各个分量。结构体数组的定义、初始化等操作和内存中的存放方式与普通数组相类似。2)静态存储类的结构体变量初始化voidmain()7指向结构体类型数据的指针

同普通变量一样,也可以定义一个指针变量指向一个结构体变量,则此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组中的元素,同样也可以用指向结构体的指针作函数参数。7指向结构体类型数据的指针同普通变量一样,例11.11用指向结构体的指针作函数参数#include“string.h”main(){structstudent{longintnum;charname[20];charsex;floatscore;};structstudentstu;

structstudent*p;

p=&stu;stu.num=89101;strcpy(,“LiLin”);stu.sex=‘M’;stu.score=89.5;printf(“No.:%d\nname:%s\nsex:%c\nscore:%f\n”, stu.num,,stu.sex,sru.score);printf(“\nNo.:%d\nname:%s\nsex:%c\nscore:%f\n”,

(*p).num,(*p).name,(*p).sex,(*p).score);}注意这里的引用格式,也可写成p–>num,…。若写成p.num,…或

*p.num,…则是错误的例11.11用指向结构体的指针作函数参数注意这里的引用格注意:(*p)表示p指向的结构体变量,不得省去括号。而*p.num等价于*(p.num)。

称为指向运算符。(*p).num可写成p─>num,使之直观,余类推。“–>”结构体变量

分量名、(*p)

分量名、p–>分量名,三

者是等价的。p–>n得到p指向的结构体变量中的分量n的值。

p–>n++得到p指向的结构体变量中的分量n的值,

用完该值后加1。++p–>n得到p指向的结构体变量中的分量n的值,

并在用该值前先加1。注意:(*p)表示p指向的结构体变量,不得省去括8动态数据结构静态数据结构(例如数组)占据内存空间的位置和大小是在它们被说明的同时由系统分配的,在程序运行期间是不变的,因此可以有效地访问它们的任何一个元素。但要删除和插入一个元素则比较困难,往往要引起大量的数据移动。而且数据量的扩充更受到它们所占用的有限内存空间的限制。C中的动态数据结构有效地解决了这一问题动态数据结构中最基本的形式是链表和二叉树,它们在数据处理中起着十分重要的作用。动态数据结构中的每个组成数据在逻辑上是连续排列的,但在物理上即在内存中存储时并不占用连续的内存空间,它们可以根据需要随机地增加或减少其元素,相应地占用或释放内存空间。8动态数据结构静态数据结构(例如数组)1.动态存储分配C语言实现动态存储分配的函数:

malloc(size)在内存的动态存储区中分配一个结点长度为size的连续存储空间,并返回一个指向其起始地址的指针,若分配不成功,则返回值为0。size为整型。

calloc(n,size)在内存的动态存储区中分配n个结点长度为size的连续存储空间,并返回一个指向其起始地址的指针,若分配不成功,则返回值为0。n、size为整型。

free(ptr)释放由指针ptr所指向的存储空间。ptr是最近一次调用malloc或calloc函数或链表指针返回的值。ptr为字符型指针。1.动态存储分配C语言实现动态存储分配的函数:ma2.链表1)链表概念单向链表是按照输入数据的顺序建立的。它有一个“头指针”(图中为

head

),指向第一个元素;每一个元素称为“结点”,每个结点包括两个域:数据域和指向下一个结点的指针域;最后一个元素的指针域为“NULL”(“空地址”),表示链表的结束,称为“表尾”。headABBCENULL链表是一种常见的动态地进行存储分配的数据结构。链表有“单向链表”、“双向链表”、“循环链表”、“双向循环链表”之分。下图是一个“单向链表”的示例。2.链表1)链表概念单向链表是按照输入2)建立链表例11.12链表的建立和遍历(队列)#defineNULL0#defineLENsizeof(structnode)structnode{intdata;structnode*next;}voidmain(){structnode*head,*rear,*p;intn=0;p=(structnode*)malloc(LEN);p–>data=n+1;head=rear=p;for(n=1;n<10;n++){p=(structnode*)malloc(LEN);p–>data=n+1;rear–>next=p;rear=p;}rear–>next=NULL;p=head;while(p!=NULL){printf(“%3d”,p–>data);p=p–>next;}}恢复指针head12345678910ppppppppp0rearprearrearrearrearrearrearrearrearrear2)建立链表例11.12链表的建立和遍历(队列)#d例11.13链表的建立和遍历(栈)#defineNULL0#defineLENsizeof(structnode)structnode{intdata;structnode*next;};voidmain(){structnode*base,*p;intn;base=NULL;for(n=0;n<10;n+

+){p=(structnode*)malloc(LEN);p>data=n

+1;p>next=base;base=p;}p=base;while(p!

=NULL){printf(“%3d”,p>data);p=p>next;}}102345678910pbase输出结果:10987654321恢复指针例11.13链表的建立和遍历(栈)#defineNUL3)删除链表元素例11.14删除链表中指定的结点。structnode*delete(head,data)structnode*head;intdata;{

structnode*p1,*p2;if(head!=NULL){

p1=head;while(p1>data!=data&&p1>next!=NULL){p2=p1;p1=p1>next;}if(p1>data=

=data){

if(p1==head)head=p1>next;else{

p2>next=p1>next;printf(“deleted:%d\n”,data);n=n

1;}elseprintf(“%dnotbeenfound!\n”,data);}return(head);}p1p2p1p2p1p2p1p2p1123456789100prearhead3)删除链表元素例11.14删除链表中指定的结点。4)链表的插入操作例11.15在链表中插入一个新结点。structnode*insert(head,new)structnode*head,*new;{

structnode*p,*p1,*p2;p=new;p1=head;if(head==NULL){head=p;p>next=NULL;}else{while(p1>data!=p>data&&p1>next!=NULL){

p2=p1;p1=p1>next;}if(p1>next==NULL){p1>next=p;p>next=NULL;}else{p2>next=p;p>next=p1;}}n=n1;}12346789100prearp1p2p1p2p1p2p1p2p1p50newhead4)链表的插入操作例11.15在链表中插入一个新结点11.2共用体1.共用体的概念

二个以上不同类型的变量采用“覆盖技术”占用同一段内存单元的结构称为共用体。共用体类型变量的定义形式如下:union共用体名{分量表;}变量表;例如:uniondata{inti;charch;floatf;}a,b,c;uniondata{inti;charch;floatf;}uniondataa,b,c;union{inti;charch;floatf;}a,b,c;11.2共用体1.共用体的概念二个以上说明:虽然“共用体”与“结构体”的定义形式相似,但是:

一个结构体变量所需的存储容量为每个分量所需存储容量之和,而一个共用体变量所需的存储容量为各个分量中占用存储容量最多的分量所需的存储容量。一个结构体变量的各个分量在任何时刻都同时存在,且可同时引用。而一个共用体变量的各个分量在同一时刻只存在其中一个,也只能引用其中的一个分量。即起作用的只是最后一次存放的分量,在存入一个新的分量后,原有分量的值被覆盖而失去作用。一个结构体变量的各个分量的地址各不相同,分别拥有各自的存储空间。而一个共用体变量的各个分量的地址相同,共同拥有同一存储空间。共用体变量可作为参数传递给函数,也可以作函数的返回值。同样,可以使用地址传送方式将共用体变量的地址作为参数或返回值在函数间传递。说明:虽然“共用体”与“结构体”的定义形式相似,但是:共用体类型可以出现在结构体类型定义中,也可以定义共用体类型数组,数组也可以作为共用体的分量。同样,结构体类型也可以出现在共用体类型定义中。不能在定义共用体变量时对其初始化,也不能对共用体变量名赋值,更不能企图引用共用体变量名去得到分量的值。2.共用体变量的引用

不能引用共用体变量,只能采用分量运算符

”引用共用体变量的分量。与引用结构体变量的方法是一致的。共用体类型可以出现在结构体类型定义中,也可以定不能在

通常,在定义嵌套有共用体变量的结构体变量时,在其中附加一个类型标志,以方便对共用体分量的操作。如:struct{union{inti;charch;floatf;doubled;}data;inttype;}a;

…switch(a.type){

case0: /*int*/printf(“%d\n”,a.data.i);break;case1:/*char*/printf(“%d\n”,a.data.ch);break;case2:/*float*/printf(“%d\n”,a.data.f);break;case3:/*double*/printf(“%d\n”,a.data.d);break;通常,在定义嵌套有共用体变量的结构体变量时,如11.3枚举类型所谓“枚举”是指变量的取值只限于所列举出来的值的范围内。枚举类型的定义以enum开头。如:enumweekday{sun,mon,tue,wed,thu,fri,sat};enumweekdayworkday,week_end;enumweekday{sun,mon,tue,wed,thu,fri,sat}workday;说明:{}中的枚举元素是常量而不是变量,也不代表什么实际的含义。枚举型变量workday,week_end的取值只限于{}中列举的元素范围内。{}中枚举元素的值按其排列顺序为0、1、2、…,可用于输出。11.3枚举类型所谓“枚举”是指变量的取枚举值可按其定义时的顺序号用作判断比较。不得直接将一个整数赋给一个枚举变量。如: Workday=2;是不对的,因为它们不属于同一数据类型。但可以进行强制类型转换赋值。如:

workday=(enumweekday)2;甚至可以是表达式,如:

workday=(enumweekday)(5-3);可用如下定义改变枚举元素中的序号值:enumweekday{sun,mon,tue,wed,thu=7,fri,sat};则枚举元素的序号值依次为: 0、1、2、3、7、8、9。枚举值可按其定义时的顺序号用作判断比较。不得直接将一例11.2口袋中有若干个红、黄、蓝、白、黑五种颜色的球,试编程求出每次从口袋中取出三个不同颜色的球的可能取法,并输出每种组合的三种颜色。例11.2口袋中有若干个红、黄、蓝、白、黑五种颜色main(){

enumcolor{red,yellow,blue,white,black};enumcolori,j,k,pri;intn,loop;n=0;for(i=red;i<=black;i++)for(j=red;j<=black;j++)if(i!=j){for(k=red;k<=black;k++)if((k!=i)&&(k!=j)){

n=n+1;printf(“%4d”,n);for(loop=1;loop<=3;loop++){switch(loop){

case1:pri=i;break;case2:pri=j;break;case3:pri=k;break;default:break;}switch(pri){

casered

:printf(“%10s”,“red”);

break;caseyellow

:printf(“%10s”,“yellow”);

break;caseblue:printf(“%10s”,“blue”);

break;casewhite:printf(“%10s”,“white”);break;caseblack:printf(“%10s”,“black”);break;default:break;}}printf(“\n”);}}printf(“\ntotal:%5d\n”,n);}main()default:br

使用关键字typedef说明一个新的类型名,往往可以在程序中简化变量的类型定义。例如:typedefstructstudent{intnum;

}REC;RECx,y,*p;语句:p=(structstudent*)malloc(sizeof(structstudent));可以写成:p=(REC*)malloc(sizeof(REC))11.4用typedef定义类型名相当于structstudentx,y,*p;使用关键字typedef说明一个新的类型名,往说明:用typedef不是也不能建立新的数据类型,也不能用来定义变量,只是以一个新的类型名(通常用大写字母表示)代替已存在的类型名,以此简化程序中变量的类型定义。

使用typedef有利于程序的通用性和可移植性。例如:程序中有:inta,b,c;

要修改为:longa,b,c;则可用typedef定义:

typedefintINTEGER;在程序中用INTEGER定义变量,当修改程序时再用typedef定义即可:

typedeflongINTEGER;说明:使用typedef有利于程序的通用性和可移植性。11.5位段结构1.位运算

C既具有高级语言的特点,又具有低级语言的功能,位运算能力就是其特色之一。所谓位运算就是指进行二进制位的运算。C提供的位运算符有: 运算符含义 & 按位与 ¦ 按位或 按位异或 ~ 取反 << 左移 >> 右移11.5位段结构1.位运算C既具有高级说明:位运算符中除“~”外,其余均为二目运算符,即要求两侧各有一个运算量。运算量只能是整型或字符型的数据,不能为实型数据。1)“按位与”运算符&参加运算的两个运算量之对应位都为1,则该位的结果为1,否则为0。例: 3&5=1 3的补码: 00000011 5的补码: 00000101& 00000001即: 0&0=00&1=01&0=01&1=1说明:运算量只能是整型或字符型的数据,不能为实型数据。&运算符的用途:清零如果想将一个单元清零(全部二进位为),则只要找一个数的补码的对应位0与被清零数的对应位1刚好对应,然后使两者进行&运算。如: 00101011 & 1001010000000000取一个数中的某些指定位如: a: 0010110010101100 b: 0000000011111111(377)8&0000000010101100得到a的低8位&运算符的用途:清零如: 0010101100000保留一个数的某一位如: 01010100(84)10& 00111011(59)1000010000(16)102)“按位或”运算符¦参加运算的两个运算量之对应位只要有一位为1,则该位的结果为1。即:0¦0=00¦1=11¦0=1

温馨提示

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

评论

0/150

提交评论