第十一章 结构类型及其它构造类型.docx
- 文档编号:4701658
- 上传时间:2022-12-07
- 格式:DOCX
- 页数:21
- 大小:56.07KB
第十一章 结构类型及其它构造类型.docx
《第十一章 结构类型及其它构造类型.docx》由会员分享,可在线阅读,更多相关《第十一章 结构类型及其它构造类型.docx(21页珍藏版)》请在冰豆网上搜索。
第十一章结构类型及其它构造类型
第十一章结构类型及其它构造类型
在实际生活中,有着大量由不同性质的数据构成的实体,如日期就是由年、月、日组成的,通信录就是由姓名、地址、电话、邮政编码等组成的,对于象日期或通信录这样的实体,用数组是难于描述的。
因此,在C语言中提供了一种新的称为结构的构造型数据类型。
结构是一组相关的不同类型的数据的集合。
结构类型为处理复杂的数据提供了便利的手段。
本章详细讨论结构的定义、说明和使用,结构与数组和指针等基本问题,并介绍联合的基本概念,以及怎样用typedef定义新的类型。
上一页 下一页
11.1结构类型
11.1.1结构类型的概念与定义
结构与数组类似,都是由若干分量组成的。
数组是由相同类型的数组元素组成,但结构的分量可以是不同类型的,结构中的分量称为结构的成员。
访问数组中的分量(元素)是通过数组的下标,而访问结构中的成员是通过成员的名字。
在程序中使用结构之前,首先要对结构的组成进行描述,称为结构的定义。
结构的定义说明了该结构的组成成员,以及每个成员的数据类型。
结构定义的一般形式如下:
struct结构类型名称
{数据类型成员名1;
数据类型成员名2;
……
数据类型成员名n;
};
其中:
struct为关键字,是结构的标识符;结构类型名称是所定义的结构的类型标识,由用户自己定义;{}中包围的是组成该结构的成员项;每个成员的数据类型既可以是简单的数据类型,也可以是复杂的数据类型。
整个定义作为一个完整的语句用分号结束。
结构类型名称是可以省略的,此时定义的结构称为无名结构。
虽然结构定义时并不要求其内部成员之间有任何内在的联系,但一般来说,结构中所有的成员在逻辑上都是彼此紧密相关的,将毫无任何逻辑关系的一组成员放入同一结构中没有任何实际意义。
为了描述日期可以定义如下结构:
structdate
{intyear; /*年:
整型作为结构中的成员*/
intmonth;/*月*/
intday;/*日*/
};
在这个结构定义中,结构类型名称为date,可以称这个结构类型为date。
在date结构中,有三个成员year,month和day,三个成员均为整型。
为了处理通信录,可以定义如下结构:
structaddress
{charname[30];/*姓名。
字符数组作为结构中的成员*/
charstreet[40];/*街道名称*/
charcity[20];/*城市*/
charstate[2];/*省市代码*/
unsignedlongzip;/*邮政编码。
无符号长整型作为结构中的成员*/
};
结构的定义明确了结构的组成形式,定义了一种C语言中原来没有、而用户实际需要的新的数据类型。
与其他的数据类型不同,在程序编译的时候结构的定义并不会使系统为该结构分配内存空间,只有在说明结构变量时才分配内存空间。
在程序中,结构的定义可以在一个函数的内部,也可以在所有函数的外部,在函数内部定义的结构,仅在该函数内部有效,而定义在外部的结构,在所有函数中都可以使用。
上一页 下一页
11.2结构数组
结构与数组的关系有两重:
其一是在结构中使用数组类型作为结构的一个成员;其二是用结构类型作为数组元素的基类型构成数组。
前者在前面的例题中已多次见到;后者是本节要讨论的内容。
结构数组是一个数组,其数组中的每一个基本元素都是结构类型。
说明结构数组的方法是:
先定义一个结构,然后用结构类型说明一个数组变量。
例如:
为记录100个人的基本情况。
可以说明一个有100个元素的数组。
每个元素的基类型为一个结构,在说明数组时可以写成:
structpersonman[100];
man就是有100个元素的结构数组,数组的每个元素为person型结构。
要访问结构数组中的具体结构,必须遵守数组使用的规定,按数组名及其下标进行访问,要访问结构数组中某个具体结构下的成员,又要遵守有关访问结构成员的规定,使用"."访问运算符和成员名。
访问结构数组成员的一般格式是:
结构数组名[下标].成员名
同一般的数组一样,结构数组中每个元素的起始下标从0开始,数组名称表示该结构数组的存储首地址。
结构数组存放在一连续的内存区域中,它所占内存数目为结构类型的大小乘以数组元素的个数。
结构数组man在内存中的存储如图11-3所示:
例如,我们要将数组man中的3号元素赋值为:
"Fangjin",'M',1963,9,13,就可以使用下列语句:
strcpy(man[3].name,"Fangjin");
man[3].sex='M';
man[3].birthday.year=1963;
man[3].birthday.month=9;
man[3].birthday.day=13;/*为结构数组中一个元素的各个成员赋值*/
为了将"Fangjin"改为"Fangjun",修改其中的字母'i',可以使用下列语句,为结构数组中一个元素的数组成员中的一个字符赋值。
man[3].name[5]='u';
利用有3个元素的结构数组,可以很方便地改写例11-3.C,请读者自己编写。
例11-4:
分析运行结果。
structs
{intx;
int*y;/*y:
结构中的成员是指向整型的指针*/
};
intdata[5]={10,20,30,40,50};/*data:
整型数组*/
structsarray[5]=
{100,&data[0],200,&data[1],300,&data[2],400,&data[3],500,&data[4]
};/*array:
结构数组,初始化*/
#include"stdio.h"
main()
{inti=0;/*说明变量i并赋初值*/
structss_var;/*s_ver:
一般的结构变量*/
s_var=array[0];/*将结构数组的array[0]整体赋给s_var*/
printf("%d\n",s_var.x);/*按照结构变量的方式引用结构的成员*/
printf("%d\n",*s_var.y);
printf("Forarray:
\n");/*以下是按结构数组元素方式引用结构成员*/
printf("%d\n",array[i].x);
printf("%d\n",*array[i].y);
printf("%d\n",++array[i].x);
printf("%d\n",++*array[i].y);
printf("%d\n",array[++i].x);
printf("%d\n",*++array[i].y);
printf("%d\n",(*array[i].y)++);
printf("%d\n",*(array[i].y++));
printf("%d\n",*array[i].y++);
printf("%d\n",*array[i].y);
}
程序中说明了一个结构数组array,结构数组array的每个元素有两个成员,其一为整型x,其二为指向整型的指针y。
结构数组array的初始化后的状态如图11-4所示。
程序各个printf语句中对数组操作的含义如下:
s_var.x/*取s_var的成员x的值,输出100*/
*s_var.y/*取s_var的成员指针y所指的内容,输出10*/
array[i].x/*取array[i]的x的值,输出100*/
*array[i].y/*取array[i]的指针y所指的内容,输出10*/
++array[i].x/*取array[i]的x的值,x加1后输出101*/
++*array[i].y/*取array[i]的指针y所指的内容,y的内容加1后输出11*/
array[++i].x/*i先加1后取array[i]的x的值,输出200*/
*++array[i].y/*将array[i]的指针y先加1后再取y所指的内容,输出30*/
(*array[i].y)++/*取array[i]的指针y的内容,输出30后,y的内容再加1*/
*(array[i].y++)/*取array[i]的指针y的内容,输出31后,指针y再加1*/
*array[i].y++/*同上,由于运算的结合性隐含了括号,输出40*/
*array[i].y/*输出50*/
程序运行结束时,结构数组array的状态如图11-5所示。
例11-5:
简单的密码加密程序。
其加密过程是先定义一张字母加密对照表。
将需要加密的一行文字输入加密程序,程序根据加密表中的对应关系,可以很简单地将输入的文字加密输出,对于表中未出现的字符则不加密。
可以定义一个结构来表示加密表。
结构table中的成员input存入输入的字符,成员output保存加密后对应的字符。
#include"stdio.h"
structtable/*定义结构table*/
{charinput;/*成员input存输入的字符*/
charoutput;/*成员output存输出的字符
};
structtabletranslate[]=/*说明外部的结构数组translate并初始化*/
{'a','d','b','w','c','k','d',';','e','i',
'i','a','k','b',';','c','w','e'};/*建立加密对照表*/
main()
{charch;
intstr_long,i;
str_long=sizeof(translate)/sizeof(structtable);/*计算数组元素个数*/
while((ch=getchar())!
='\n')
{for(i=0;translate[i].input!
=ch&&i if(i putchar(translate[i].output);/*对表中的字符加密输出*/ elseputchar(ch);/*对其它字符原样输出*/ } } 语句"structtabletranslate[]={...}"有三个作用,一是说明了一个外部的结构数组translate;二是表示数组的大小由后面给出的初始化数据决定,三是对结构数组进行初始化。 在程序中给出了数组初始化数据,所以结构数组translate有9个元素。 程序中语句"str_long=sizeof(translate)/sizeof(structtable);"是用sizeof运算计算结构数组translate中元素的数目。 sizeof(translate)求出数组translate所占用的字节总数,sizeof(structtable)求出数组中每个元素所占用的字节总数。 运行程序时,从键盘逐个读取输入的字符存入变量ch中,将ch的值与结构translate中的input比较,如果是要加密的字符,则输入加密后的字符output,否则ch原样输出。 例11-6: 有N个小孩围成一圈并依次编号,教师指定从第M个小孩开始报数,当报到第S个小孩时,即令其出列,然后再从下一个孩子起从1开始继续报数,数到第s个小孩又令其出列,这样直到所有的孩子都依次出列。 求小孩出列的顺序。 这就是约瑟夫问题。 由于问题中的小孩围成一个圈,因而启发我们用一个环形链来表示。 我们用结构数组构成一个环形链。 结构名为child。 数组名为link。 nextp的含义是排在当前这个孩子后面的下一个孩子的序号。 由nextp可构成一个环型链,no是孩子的序号。 这样就可以从第M个小孩开始沿着nextp连成的闭合链不断计数S次,输出对应的no表示让他出列。 #include"stdio.h" structchild/*定义结构child*/ {intnextp;/*排在后面下一个位置上的孩子的序号*/ intno;/*孩子的序号*/ }link[100];/*说明结构数组link*/ main() {inti,n,s,y,k,m,count=0;/*count为输出计数器*/ printf("\nTellmehowmanychildrenarethere? "); scanf("%3d",&n); printf("\nFromwhichtocount? "); scanf("%3d",&m); printf("\nHowmanyshallIcount? "); scanf("%3d",&s); for(i=1;i<=n;i++)/*根据孩子总数n建立一个环*/ {if(i==n) link[i].nextp=1;/*若是最后一个,则他的下一个是第一个人*/ elselink[i].nextp=i+1;/*否则,第i个人的下一个为第i+1个人*/ link[i].no=i;/*为第i个孩子建立序号*/ } printf("\nStandout: \n"); if(m>=i)k=n; elsek=m-1;/*k定位在应开始计数的孩子的前一个人上*/ while(count! =n) {for(i=0;i! =s;)/*s个孩子报数*/ {k=link[k].nextp;/*取下一个孩子*/ if(link[k].no! =0)++i;/*若序号不为0表示没出列,则计数*/ } printf("%7d",link[k].no);/*输出出列的孩子序号*/ link[k].no=0;/*将出列孩子的序号清为0*/ if(++count%10==0)printf("\n"); } } 程序中首先输入小孩总数n,报数起始位置m和需要出列的计数步长s,然后由总数n初始化结构数组link。 为了程序中处理的方便,link数组从下标1开始使用,下标为0的元素不用,由于数组说明长度为100,所以输入的n值不能大于99。 变量k记录下一次需要计数的数组下标,初始化时,变量k的值在要开始报数的小孩的前一个位置。 在while循环中,使用count作为出列小孩计数器,对于已出列的小孩,将no清为0,变量i是报数计数器,当link[k].no不为0时,才操作++i。 语句"k=link[k].nextp;"的含义是将下一个孩子所在数组中的下标位置送入变量k中。 运行程序,输入n=35、m=5、s=3,可得到如下结果: 7101316192225283134 259141823273216 1220263341524351129 83021317 本例完全可以用一维数组实现,请读者自己编写程序。 上一页 下一页 11.3结构指针 指针结构与指针的关系亦有两重: 其一是在定义结构时,将指针作为结构中的一个成员;其二是指向结构的指针(称为结构指针)。 前者同一般的结构成员一样可直接进行访问,后者是本节讨论的重点。 结构指针说明的一般形式是: struct结构类型名称*结构指针变量名; 例如: structdate*pdate,today; 说明了两个变量,一个是指向结构date的结构指针pdate,today是一个date结构变量。 语句: pdate=&today; 其含义如图11-6所示。 pdatetoday(structdate) year month day 图11-6结构指针指向结构 通过结构变量today访问其成员的操作,也可以用等价的指针形式表示: today.year=2001; 等价于 (*pdate).year=2001; 由于运算符"*"的优先级比运算符"."的优先级低,所以必须有"()"将*pdate括起来。 若省去括号,则含义就变成了"*(pdate.year)"。 在C语言中,通过结构指针访问成员可以采用运算符"->"进行操作,对于指向结构的指针,为了访问其成员可以采用下列语句形式: 结构指针->成员名; 这样,上面通过结构指针pdate访问成员year的操作就可以写成: pdate->year=2001; 如果结构指针p指向一个结构数组,那么对指针p的操作就等价于对数组下标的操作。 结构指针是指向一种结构类型的指针变量,它是结构在内存中的首地址,结构指针具有一般指针的特性,如在一定条件下两个指针可以进行比较,也可以与整数进行加减。 但在指针操作时应注意: 进行地址运算时的放大因子由所指向的结构的实际大小决定。 例11-7: 用结构指针改写加密程序。 #include"stdio.h" structtable {charinput,output; }; structtabletranslate[]= {'a','d','b','w','c','k','d',';','e','i', 'i','a','k','b',';','c','w','e' }; /*建立加密对照表*/ main() {charch; structtable*p,*pend;/*p和pend为指向结构table的指针*/ pend=&translate[sizeof(translate)/sizeof(structtable)-1]; /*pend指向结构数组translate的最后一个元素*/ while((ch=getchar())! ='\n') {for(p=translate;p->input! =ch&&p! =pend;p++); if(p->input==ch) putchar(p->output); else putchar(ch); } } 读者可以将两个程序对照阅读,体会结构指针特点。 程序中用pend指向数组的最后一个元素。 由于结构指针和在结构中将指针作为成员,使得对于结构变量的运算和对成员的操作变得较为复杂。 由于取内容的"*"与"."和"->"运算符的优先级与结合性不同,使得对成员的访问和操作又增加了一层难度,再因为"++"和"--"运算所具有的"先操作"与"后操作"的特性,以及"++"和"--"运算的结合性,使得"++"和--"运算与结构操作混合在一起时,实际操作会更为复杂。 例11-8: 请分析程序的运算结果。 #include"stdio.h" structs {intx,*y;/*y: 结构中的成员是指向整型的指针*/ }*p;/*p: 指向结构的指针*/ intdata[5]={10,20,30,40,50,};/*data: 整型数组*/ structsarray[5]= {100,&data[0],200,&data[1],300,&data[2], 400,&data[3],500,&data[4] };/*array: 结构数组*/ main() {p=array;/*指针p指向结构数组的首地址*/ printf("Forprinter: \n"); printf("%d\n",p->x); printf("%d\n",(*p).x); printf("%d\n",*p->y); printf("%d\n",*(*p).y); printf("%d\n",++p->x); printf("%d\n",(++p)->x); printf("%d\n",p->x++); printf("%d\n",p->x); printf("%d\n",++(*p->y)); printf("%d\n",++*p->y); printf("%d\n",*++p->y); printf("%d\n",p->x); printf("%d\n",*(++p)->y); printf("%d\n",p->x); printf("%d\n",*p->y++); printf("%d\n",p->x); printf("%d\n",*(p->y)++); printf("%d\n",p->x); printf("%d\n",*p++->y); printf("%d\n",p->x); } 结构数组array的初始化后的状态如图11.4所示。 程序中指针操作的含义如下: p->x/*取结构指针p指向的结构的成员x的值,输出100*/ (*p).x/*取结构指针p的内容的成员x的值,功能同上,输出100*/ *p->y/*取结构指针p的指针成员y的内容,输出10*/ *(*p).y/*取结构指针p的内容的指针成员y的内容,功能同上,输出10*/ ++p->x/*p所指的x加1,x先加1后再输出101,p不加1*/ (++p)->x/*p先加1后再取x的值,x不加1,输出200*/ p->x++/*先取x的值后x再加1,输出200*/ p->x/*输出201*/ ++(*p->y)/*p所指的y的内容先加1,输出21,p不加1,y也不加1*/ ++*p->y/*同上,由运算的结合性隐含了括号,输出22*/ *++p->y/*y先加1后再取y的内容,输出30,p不加1,y的内容不加1*/ p->x/*输出201*/ *(++p)->y/*p先加1后取所指y的内容,输出30*/ p->x/*输出300*/ *p->y++/*取p所指的y的内容,输出30,然后p所指的y加1*/ p->x/*输出300*/ *(p->y)++/*取p所指的y的内容,输出40,然后p所指的y加1*/ p->x/*输出300*/ *p++->y/*取p所指的y的内容,输出50,然后p加1*/ p->x/*输出400*/ 程序运行结束时,指针与结构数组array的状态如图11-7所示。 例11-9: 可用一个结构表示学生的学号和成绩,编写程
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第十一章 结构类型及其它构造类型 第十一 结构 类型 及其 构造