第六章结构体和共用体(正式)_第1页
第六章结构体和共用体(正式)_第2页
第六章结构体和共用体(正式)_第3页
第六章结构体和共用体(正式)_第4页
第六章结构体和共用体(正式)_第5页
已阅读5页,还剩41页未读 继续免费阅读

下载本文档

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

文档简介

1C语言程序设计计算机学院

第六章2第6章结构体与共用体6.1结构体概述6.1.1结构体的引入为了方便处理多个数据项的数据,常常把这些关系密切但类型不同的数据项组织在一起,即“封装”起来,并为其取一个名字,在C语言中,就称其为结构体(有些高级语言称之为记录)。所以,结构体通常是由不同数据类型的数据项组成,一般也称是由不同成员组成,因此可以说:一个结构体可包含若干成员,每一个成员可具有不同的名字及数据类型。结构体的引入为处理复杂的数据结构提供了有力的手段,也为函数间传递一组不同数据类型的数据提供了方便,特别是对于数据结构较为复杂的大型程序提供了方便。36.1.2结构体类型的定义结构体类型和简单类型不同,简单类型是由系统预定义的,如int、float、char,直接可以使用。而结构体类型是根据需要由程序员自行定义,因此在使用之前必须先定义结构体类型。结构体类型定义struct

[结构体名]{

类型标识符成员名;类型标识符成员名;

…………….};合法标识符可省:无名结构体成员类型可以是基本型或构造型struct是关键字,不能省略4例structstudent{intnum;charname[20];charsex;intage;floatscore;charaddr[30];};structstudents1;namenumsexagescoreaddr2字节2字节20字节1字节4字节30字节……..结构体类型定义描述结构的组织形式,定义类型时不分配内存,当定义变量时分配内存单元5说明(1)

定义一个结构体类型只是描述了此结构体的组织形式,在编译时并不为其分配存储空间,即仅描述此数据结构的形态或者说模型,故不能对定义的一个结构体类型进行赋值、存取或运算。(2)结构体的成员可以是简单变量、数组、指针、结构体或公用体等。(3)结构体类型定义可以放在函数内部,也可以放在函数外部。若放在内部,则只在函数内有效;若放在外部,则从定义点到源文件尾之间的所有函数都有效。(4)结构体成员的名字可以同程序中的其它变量同名,二者不会相混,系统会自动识别它。66.2结构体变量6.2.1结构体变量的定义与初始化1.结构体变量的定义同其它变量一样,结构体变量也必须先定义,然后才能引用。一个结构体变量的定义可以有以下三种方式:(1)先定义类型再定义变量(推荐)其形式:structstud_type{charname[10];longnum;charsex;intage;floatscore;charaddress[10];};structstud_typestudent1,student2;7(2)在定义类型的同时定义变量(推荐)其形式:structstud_type{┇}student1,student2;(3)直接定义结构体变量其形式:struct{┇}student1,student2;8说明(1)

在定义结构体类型时,系统并不分配内存空间,仅当定义结构体变量时,系统才为被定义的每一变量分配相应的存储单元。如上面定义的结构体变量student1、student2在内存中各占31个字节(10+4+1+2+4+10=31)(2)

结构体变量的定义一定要在结构体类型定义之后或同时进行,对尚未定义的结构体类型,不能用它来定义结构体变量。例如:对一个教师teacher的结构体类型未作定义,则下面的变量定义structteacherteah1

是错误的;反之亦然;对某变量birthday

(也称结构体成员变量),若其类型未作定义,就写structdate_typebirthday;也是错误的。92.结构体变量的初始化所谓结构体变量初始化,就是在定义结构体变量的同时,对其成员变量赋初值,在赋值时应注意按顺序及类型依次为每个结构体成员指定初始值。结构体初始化的一般格式为:struct结构体类型名结构体变量={初始化值};说明(1)初始化数据之间用逗号分隔。(2)

初始化数据的个数一般与成员的个数相同,若小于成员数,则剩余的成员将被自动初始化为0(若成员是指针,则初始化为NULL)。(3)

初始化数据的类型要与相应成员变量的类型一致。初始化时只能对整个结构体变量进行,不能对结构体类型中的某个成员进行初始化赋值。10例:structdate_type{intyear;intmouth;intday;};structstud_type{charname[10];longnum;charsex;

structdate_typebirthday;floatscore;charaddress[10];};voidmain(){structstud_typestudent1={"wang",196103,'m',1978,10,12,98,"Xian"};structstud_typestudent2={"liu",196105,'m',1980,9,22,88,"Benjing"};}116.2.2结构体变量的引用1.对结构体变量成员的引用在C语言程序中,不准许对结构变量整体进行各种运算、赋值或输入输出操作,而只能是对其成员进行此类操作。引用结构体变量成员的一般形式:结构体变量名.成员名其中"."是结构体成员运算符,其优先级别最高,结合性是自左至右。由此对结构体成员就完全可以像操作简单变量一样操作它。如:对上例定义的结构体变量student1或student2,可作如下的赋值操作:[10]="wang";student1.num=196103;student1.sex='m';student1.birthday.year=1978;student1.birthday.mouth=10;student1.birthday.day=12;student1.score=98;122.对结构体变量整体的引用结构体变量和简单变量相比,除了上面所述在参加各种运算、赋值或输入输出方式上有所不同外——即是由结构体变量成员完成,其它同简单变量一样,如:(1)可以相互赋值,但注意相互赋值的两个结构体变量必须是同一个结构体类型;如:student1=student2;(2)可作为函数的形参、实参或函数返回值,详见下节。136.2.3结构体变量作为函数参数结构体变量成员作函数参数结构体变量中的所有成员都可作为函数参数structstud_type{charname[10];longnum;charsex;}student1;现将结构体变量student1的三个成员分别传递给函数func1(),func2(),func3():func1();func2(student1.num);func1(student1.sex);14若需要将成员地址传递给函数,则只需在其前加取地址符“&”。如:func1();func2(&student1.num);func1(&student1.sex);其中字符数组名name代表其成员地址,故不许要写“&”。2.结构体变量整体作函数参数老板本的C系统不允许用结构体变量作函数参数,只允许用指向结构体变量的指针作函数参数(第7章),传递的是结构体变量的首地址。而ANSIC取消了这一限制,规定按值传递方式。在函数调用时,系统为形参结构体变量分配存储空间,并从相应的实参结构体变量中取得各成员的值,若对形参中结构体变量各成员值进行修改,并不能修改实参结构体变量各成员的值。这里要注意,实参和形参结构体变量类型应当完全一致。156.3结构体数组6.3.1结构体数组的定义与初始化1.结构体数组的定义在定义结构体数组时其定义方法与定义结构体变量方法类似,也有三种形式。定义如下:structdate_type

{intyear;intmouth;intday;};structstud_type{charname[10];longnum;charsex;structdate_typebirthday;floatscore;charaddress[10];};structstud_typestudent[3];

16由此就定义了一个结构体数组student[3],它有3个元素,每个元素都是structstud_type类型,各占35个字节(10+4+1+(2+2+2)+4+10=35)。172.结构体数组的初始化结构体数组在定义的同时可以初始化。其一般格式是在定义之后紧跟一个用花括号括起来的一组初始数据,为了增强可读性,最好使每一个数组元素的初始数据也用花括弧括起来,以此来区分各个数组元素。对上所定义的结构体数组student初始化如下:stuctstud_typestudent[2]={{"wang",196103,'m',1978,10,12,98,"xian"},{"zhang",196102,'f',1977,1,10,87,Beijing"}};18说明(1)

可以将一个结构体数组元素赋值给同一结构体类型数组中另一个元素,或赋给同一类型的变量。如:structstud_typestudent[3],student1;现在就定义了一个结构体数组student[],又定义了一个结构体变量student1,则下面的赋值合法。studentl=student[0];student[0]=student[1];studnet[1]=student1;(2)

不能把结构体数组元素作为一个整体直接进行输入或输出。如printf("%d",student[0]);或scanf("%d",&student[0]);只能以单个成员为对象进行输入输出,如:scanf("%s",student[0].name);scanf("%ld",&student[0].num);printf("%s%ld\n",student[0].name,student[0].num);19例统计后选人选票structperson{charname[20];intcount;}leader[3]={“Li”,0,“Zhang”,0,”Wang“,0};voidmain(){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);}namecountLiZhangWang000206.3.3结构体数组作函数参数与结构体变量一样,结构体数组作为函数参数传递也只有在C的高版本中才支持,但它们是有本质区别的,当然在定义形参与实参的结构体类型时还是必须一致,当实参为结构体数组时,其形参须定义为同类型结构的结构体数组或结构体指针;结构体数组作函数参数21例6.3键盘输入n名学生信息,要求输出用函数print完成。(P141)#include<stdio.h>structstud_type{charname[10];intnum;floatscore[3];};voidprint(structstud_typestu[],intn);voidmain(){inti,n;structstud_typestu1[30];printf(“请输入学生人数n:\n”);scanf(“%d”,&n);printf(“请输入%d名学生信息(姓名,学号3门课成绩):\n”,n);for(i=0;i<n;i++)scanf(“%s%d%f%f%f”,stu1[i].name,&stu1[i].num,&stu1[i].score[0],&stu1[i].score[1],&stu1[i].score[2]);print(stu1,n);}22voidprint(structstud_typestu[],intn){intI;printf(“姓名学号成绩1成绩2成绩3:\n”);for(i=0;i<n;i++)printf(%-8s%8d%8.2f%8.2f%8.2f\n”,stu[i].name,stu[i].num,stu[i].score[0],num,stu[i].score[1],num,stu[i].score[2]);}例6.4键盘输入10名学生信息,每个学生有姓名

学号成绩,要求用一个排序函数sort完成按学生成绩降序排列,并输出学生成绩排行榜。(主函数完成输入,输出)P14323#defineN10#include<stdio.h>#include<string.h>structstud_type{charname[10];intnum;intscore;};voidsort(structstud_typestu[]);voidmain(){inti;structstud_typestu[N];printf(“请输入%d名学生信息(姓名,学号成绩):\n”,N);for(i=0;i<N;i++)scanf(“%s%d%d”,stu[i].name,&stu[i].num,&stu[i].score);sort(stu);printf(“排序后\n”);for(i=0;i<N;i++)printf(“%-8s%5d%5d\n”,stu[i].name,stu[i].num,stu[i].score);}24voidsort(structstud_typestu[])

{inti,k,j;structstud_typet;for(i=0;i<N-1;i++){k=i;for(j=i+1;j<N;j++)if(stu[k].score<stu[j].score)k=j;if(k!=i){t=stu[i];stu[i]=stu[k];stu[k]=t;}}}256.4共用体在C语言中,允许不同数据类型使用同一存储区域,共用体就是一种同一存储区域由不同类型变量共享的数据类型。它提供—种方法能在同一存储区中操作不同类型的数据,也就是说共用体采用的是覆盖存储技术,准许不同类型数据互相覆盖。6.4.1共用体类型定义共用体类型的定义与结构体类似,其一般定义格式如下:union共用体名{共用体成员表;};其中union是关键字,称为共用体定义标识符,共用体名同样由程序员来命名。大括号中的共用体成员表包含若干成员,每一个成员都具有如下的形式:

数据类型标识符成员名;26如:uniondata{inti;charch;floatf;};6.4.2共用体变量定义与引用1.共用体变量的定义union共用体名{共用体成员表;}变量列表;如:uniondata{inti;charch;floatf;}a,b,c;272.共用体变量的引用(例6.5p133)

共用体变量名.成员名;如上例所示:a.i;a.ch;a.f说明:(1)共用体变量不能同时存放多个成员的值,而只能存放其中一个值,即只能存放当前(最新)的一个成员的值;(2)就共用体变量整体而言,和结构体变量一样是不能进行整体的输入、输出,但可以在两个同一类型的共用体变量之间赋值;(3)由于共用体变量不能同时存放多个成员的值,因此共用体变量不能进行初始化。28例6.5共用体变量的引用voidmain(){unionint_char{inti;charch[2];}x;x.i=24897;printf(“i=%d\ni=%0\n”,x.i,x.i);printf(“ch0=%0,ch1=%0\nch0=%c,ch1=%c\n”,x.ch[0],x.ch[1],x.ch[0],x.ch[1]);}29结构体与共用体区别:存储方式不同structnode{charch[2];intk;}a;unionnode{charch[2];intk;}b;achkbchk变量的各成员同时存在任一时刻只有一个成员存在联系:两者可相互嵌套306.5枚举类型在实际应用中,有些变量的取值范围是有限的,仅可能只有几个值,如一个星期7天,一年12个月,一副扑克有4种花色,每一花色有13张牌等等。此时用整型数来表示这些变量的取值,其直观性很差,如在程序中使用1,对于非编程者来说,它是代表星期一呢?还是一月份?很难区分。若在程序中使用“Mon”,则不会有人认为是代表一月份。由此看出,为提高程序的可读性,引入非数值量,即一些有意义的符号是非常必要的。对于这种应用,C语言引入枚举类型,所谓“枚举”,就是将变量可取的值一一列举出来。31对枚举类型也要先定义其类型,再定义其变量。枚举类型定义的一般形式是:enum枚举名{枚举值列表;};其中enum是关键字,称为枚举类型定义标识符,枚举名由程序员命名。32标识符也是由程序员自定义,都是一些描述性标识符,要求不能重名,这些标识符分别代表不同枚举元素,通常称为枚举常量。如:enumweekday{sun,mon,tue,wed,thu,fri,sat};由此定义了一个枚举类型enumweekday,它有7个枚举元素(常量)。在定义了类型之后,就可以用该类型来定义变量:如:enumweekdayworkday;33说明(1)

在C语言中,每一个枚举常量的值取决于在说明时排列的先后次序,第一个枚举常量的序号为0(规定序号从0编起),因此,此枚举常量值为0,以后顺序加1,故不允许对枚举常量进行赋值操作。若想改变枚举常量的值,在枚举变量定义时可由程序员指定,如:enumfruit{apple=7,pear,orange=3,lemon,peach}t;此时apple的值为7,pear的值为8,orange的值为3,lemon,peach的值分别为4,5。34(2)

一个枚举变量的值只能是这几个枚举常量之一,可以将枚举常量赋给一个枚举变量,但不能将一个整数赋给它。如:

workday=sun;正确

workday=7;错误(3)若想将整数值赋给枚举变量须作强制类型转换。如:

workday=(enumweekday)2;相当于workday=tue;此时,转换后的值亦应在枚举范围内。356.6用typedef定义类型功能:用自定义名字为已有数据类型命名类型定义简单形式:typedeftype

name;例typedefintINTEGER;类型定义语句关键字已有数据类型名用户定义的类型名例typedeffloatREAL;类型定义后,与已有类型一样使用例INTEGERa,b,c;REALf1,f2;

inta,b,c;floatf1,f2;说明:1.typedef没有创造新数据类型2.typedef是定义类型,不能定义变量3.typedef与define

不同

define

typedef预编译时处理

编译时处理简单字符置换

为已有类型命名

36typedef定义类型步骤按定义变量方法先写出定义体如inti;将变量名换成新类型名如int

INTEGER;最前面加typedef如typedefintINTEGER;用新类型名定义变量如INTEGERi,j;例定义数组类型

inta[100];intARRAY[100];typedefintARRAY[100];ARRAYa,b,c;例定义结构体类型变量

structdate{intmonth;intday;intyear;}d;例定义结构体类型变量

structdate{intmonth;intday;intyear;}DATE;例定义结构体类型DATEtypedefstructdate{intmonth;intday;intyear;}DATE;37说明:(1)定义的新类型名一般使用大写字母,以便与系统的标准类型标识符相区别。(2)仅给已有的类型名重新命名,并不产生新的数据类型,原有的数据类型也没有被取代,即只是此类型的一个“别名”。如typedefintINTEGER;,只是给int起了一个新的名字而已,int仍可用。(3)定义一个新的数据类型名,并没有定义变量,因而谈不上分配存储单元。(4)typedef与#define有相似之处,如typedefintINTEGER;#defintINTEGERint;作用都是用INTEGER代替int,但二者有本质的区别,前者是为int定义了一个别名,而后者是宏代换。

38第九章编译预处理作用:对源程序编译之前做一些处理,生成扩展C源程序种类宏定义#define文件包含#include条件编译#if--#else--#endif等格式:“#”开头占单独书写行语句尾不加分号39如if(x==YES)printf(“correct!\n”);elseif(x==NO)printf(“error!\n”);展开后:if(x==1)printf(“correct!\n”);elseif(x==0)printf(“error!\n”);9.1宏定义不带参数宏定义一般形式:#define宏名[宏体]功能:用指定标识符(宏名)代替字符序列(宏体)宏展开:预编译时,用宏体替换宏名---不作语法检查如#defineYES1#defineNO0#definePI3.1415926#defineOUTprintf(“Hello,World”);宏体可缺省,表示宏名定义过或取消宏体定义位置:任意(一般在函数外面)作用域:从定义命令到文件结束#undef可终止宏名作用域格式:

#undef宏名例#defineYES

11main(){……..}

#undefYES#defineYES0max(){……..}YES原作用域YES新作用域宏定义可嵌套,不能递归例#defineMAXMAX+10()引号中的内容与宏名相同也不置换例#definePI3.14159printf(“2*PI=%f\n”,PI*2);宏展开:printf(“2*PI=%f\n”,3.14159*2);宏定义中使用必要的括号()例#defineWIDTH80#defineLENGTH

WIDTH+40var=LENGTH*2;宏展开:var=80+40*2;()()例#defineWIDTH80#defineLENGTH

WIDTH+40var=LENGTH*2;宏展开:var=80+40*2;40带参数宏定义一般形式:#define宏名(参数表)宏体例#defineS(r)PI*r*r#defineS(r)PI*r*r相当于定义了不带参宏S,代表字符串“(r)PI*r*r”宏展开:形参用实参换,其它字符保留宏体及各形参一般应加括号()例#defineS(a,b)a*b………..area=S(3,2);宏展开:area=3*2;不能加空格例#definePOWER(x)x*xx=4;y=6;z=POWER(x+y);宏展

温馨提示

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

评论

0/150

提交评论