• 1.15 MB
  • 2022-04-29 14:22:10 发布

C语言程序设计课件PPT(A套)之第十章结构、联合与枚举类型

  • 69页
  • 当前文档由用户上传发布,收益归属用户
  1. 1、本文档共5页,可阅读全部内容。
  2. 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,可选择认领,认领后既往收益都归您。
  3. 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细先通过免费阅读内容等途径辨别内容交易风险。如存在严重挂羊头卖狗肉之情形,可联系本站下载客服投诉处理。
  4. 文档侵权举报电话:19940600175。
'结构、联合与枚举类型 第一节结构类型第二节结构数组第三节结构指针第四节在函数之间传递结构第五节联合类型第六节枚举类型第七节用typedef定义类型第八节链表基础 问题的引出用学号、姓名、性别、年龄、住址等属性来描述一个学生。intnum;charname[20];charsex;intage;charaddr[30];问题一:在程序中这些变量没有的内在联系。问题二:如果有成百上千的学生,可能造成混乱。一、结构类型的概念第一节结构类型 这些数据存放在内存的某个区域。将此区域统一来使用,形成了结构体的概念。结构是逻辑上相互联系的一组分量的集合。结构中的分量可以有不同的类型数据,结构中的分量称为结构的成员。numnamesexageaddr10010LiFunM18Beijing第一节结构类型 比较简单数据类型时的变量说明语句:inti;struct结构体名{数据类型成员名1;数据类型成员名2;……数据类型成员名n;};二、结构类型的定义struct为关键字结构体名是用户定义的类型标识。{}中包围的是组成该结构的成员。成员的数据类型既可以是简单的数据类型(int、char、float、double...),也可以是复杂的数据类型(数组类型和结构类型)。第一节结构类型 结构定义实例为了描述日期可以定义如下结构:structdate{intyear;/*年结构成员的*/intmonth;/*月数据类型是*/intday;/*日整型*/};为了处理通信录,可以定义如下结构:structaddress{charname[30];/*姓名。字符数组*/charstreet[40];/*街道名称*/charcity[20];/*城市*/charstate[2];/*省市代码*/unsignedlongzip;/*邮政编码。*/};第一节结构类型 在定义了某种类型的结构体后,就可以使用该类型的结构变量。用类型说明语句说明结构变量struct结构体名结构变量名;系统为所说明的结构变量按照结构定义时说明的组成(成员分量),分配存储数据的实际内存单元。例:将变量today说明为date型的结构变量:structdatetoday;说明多个address型的结构变量:structaddresswang,li,zhang;结构变量同样有存储类型,存储特性与一般变量完全相同。三、结构变量的说明第一节结构类型 结构变量占用内存情况结构变量的各个成员分量在内存中占用连续存储区域,所占内存大小为结构中每个成员的占用内存的长度之和。结构变量today和wang占用在内存的情况如图所示。2字节2字节2字节today(structdate)6个字节yearmonthdaywang(structaddress)96个字节30字节40字节20字节2字节4字节namestreetcitystatezip表示int表示char表示unsignedlong第一节结构类型 关于结构类型的说明类型与变量是不同的概念。在定义结构变量时一般先定义一个结构类型,然后定义变量为该类型。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。对结构中的成员,可以单独使用,它的作用与地位相当于普通变量。成员也可以是结构变量。成员名可以与程序中的变量名相同时,二者不代表同一对象。第一节结构类型 在定义结构时说明结构变量例如:structstudent{intnum;charname[20];charsex;intage;charaddr[30];}student1,student2;直接说明结构变量例如:struct{charname[20];charaddr[30];}zhang;第一节结构类型 结构成员是另一个结构例如:structdate{intmonth;intday;intyear;};structstudent{intnum;charname[20];charsex;intage;structdatebirthday;charaddr[30];}student1,student2;daymonthyearagesexnamnumaddbirthdaybirthdaybirthdaybirthday第一节结构类型 访问结构中的成员是通过成员的名字,称为“按名引用”。在程序中使用结构中成员的方法为:结构变量名.成员名称例:将“92.10.01”送入today,对其各个成员分别赋值:today.year=92;today.month=10;today.day=1;指明结构成员的符号“.”是运算符,含义是访问结构中的成员。“.”操作的优先级在C语言中是最高的。其结合性为从左到右。四、引用结构变量的成员第一节结构类型 例:用结构描述一个人的基本情况,可以定义如下结构:structperson/*定义person结构类型*/{charname[30];charsex;structdatebirthday;/*结构的嵌套定义*/}man;输入zhang先生的情况,如生日,可用如下语句:strcpy(man.name,“zhang”);/*注意:不能写成man.name="zhang";*/man.sex=’M’;/*为结构中的字符成员赋值*/man.birthday.year=1960;man.birthday.month=3;man.birthday.day=28;/*为嵌套定义的结构中的成员赋值*/第一节结构类型 输入zhang先生的情况,可用如下语句:strcpy(man.name,“zhang”);/*注意:不能写成man.name="zhang";*/man.sex=’M’;/*为结构中的字符成员赋值*/man.birthday.year=1960;man.birthday.month=3;man.birthday.day=28;/*为嵌套定义的结构中的成员赋值*/如果要将“zhang”改为“zhong”,只要将结构变量man中的数组成员name下标为2的元素‘a’改为‘o’即可。可以使用下列语句:man.name[2]="o";./*为结构变量中的数组成员的一个元素赋值*/第一节结构类型 五、对结构变量的整体操作要对结构进行整体操作有很多限制,C语言中能够对结构进行整体操作的运算不多,只有赋值“=”和取地址“&”操作。例如:有structdatesunday,today;如果today被赋值后,可用语句sunday=today;为sunday赋值。第一节结构类型 结构类型的引用说明不能将一个结构变量作为一个整体直接访问。例如已定义student1为结构变量并且已有值。不能这样引用:printf(“%s,%c,%d,%d,%dn”,student1);如果成员本身又是一个结构类型,则要用若干个成员运算符,一级一级地找到最低的一级的成员。只能对最低级的成员进行赋值或存取等运算。例如,对上面定义的结构变量student1,可以这样访问各个成员:student1.namestudent1.sexstudent1.birthday.monthstudent1.birthday.daystudent1.birthday.year第一节结构类型 对成员变量可以象普通变量一样进行各种运算。student2.birthday.year=student1.birthday.year;sum=student1.birthday.month+12;student1.age++;++student1.age;可以引用成员的地址,也可以引用结构变量的地址。如:scanf(“%d”,&student1.num);printf(“%p”,&student1);但不能用以下语句整体读入结构变量,如:scanf(“%d,%s,%c,%d,%d,%d,%s”,&student1);第一节结构类型 例:输入今天的日期,然后输出该日期。#includemain(){structdate/*在函数中定义结构类型date*/{intyear,month,day;};structdatetoday;/*说明结构变量today*/printf("Entertodaydate(YYYY/MM/DD):");scanf("%d/%d/%d",&today.year,&today.month,&today.day);printf("Today:%d/%d/%dn",today.year,today.month,today.day);}例C10_103第一节结构类型 对结构变量进行初始化在说明变量的同时,可以对每个成员置初值,称为结构变量的初始化,其一般形式为:定义结构时说明变量struct结构体名{……}结构变量={初始化数据};类型说明语句struct结构体名结构变量={初始化数据};说明:{}中的初始化数据用逗号分隔。注意数据的个数、数据类型、顺序要一一对应。六、结构变量的初始化第一节结构类型 例:用结构描述个人基本情况,打印个人档案。structdate/*在所有函数的外部定义结构date*/{intyear,month,day;};structperson/*在所有函数的外部定义结构person*/{charname[14],sex;structdatebirthday;};structpersonxu={"Xulihui","M",{1962,10,4}};main(){structpersonfang={"Fangjin","M",{1963,9,13}};structpersonyuan={"Yuanzhiping","M",{1963,10,5}};/*说明结构变量fang、yuan,并初始化结构变量*/第一节结构类型 printf("namesexbirthdayn");printf("-------------------------------n");printf("%-14s%-4c%4d.%2d.%2dn",xu.name,xu.sex,xu.birthday.year,xu.birthday.month,xu.birthday.day);printf("%-14s%-4c%4d.%2d.%2dn",fang.name,fang.sex,fang.birthday.year,fang.birthday.month,fang.birthday.day);printf("%-14s%-4c%4d.%2d.%2dn",yuan.name,yuan.sex,yuan.birthday.year,yuan.birthday.month,yuan.birthday.day);}例C11_104第一节结构类型 结构体数组说明语句的格式对结构体数组的认识是一个数组。数组中的每一个元素的数据类型是结构类型。例:为记录100个人的基本情况。可以说明一个有100个元素的数组。数组元素的基类型为结构。structpersonman[100];man就是有100个元素的结构数组,数组的每个元素为person型。标识符[数组长度]struct结构体名第二节结构数组 访问结构数组元素成员必须遵守数组使用和访问结构成员的规定。访问数组元素按下标进行访问。访问数组元素的成员,使用“.”运算符和成员名。例如:要将数组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";/*为数组中元素的数组成员中的一个字符赋值*/注意结构数组遵循数组的性质数组元素的起始下标从0开始,数组名表示该结构数组的存储首地址。结构数组存放在连续的内存区域中,所占内存大小为结构类型的大小乘以数组元素的数量。sizeof(structperson)301222301222301222......namesymdnamesymdnamesymdman[0]man[1]man[99]structpersonman[100]长度==37*100=3700字节?第二节结构数组 例:简单的密码加密程序。加密过程是先定义一张字母加密对照表。将需要加密的文字输入加密程序,程序根据加密表中的对应关系,将输入的文字加密输出。对加密表中未出现的字符则不加密。输入输出输入输出输入输出输入输出输入输出adbwckd;eiiakb;cwestructtable/*定义结构table*/{charinput;/*成员input存输入的字符*/charoutput;/*成员output存输出的字符*/};/*外部结构数组translate并初始化*/structtabletranslate[]={"a","d","b","w","c","k","d",";","e","i","i","a","k","b",";","c","w","e’};/*建立加密对照表*/第二节结构数组 “structtabletranslate[]={...}”有三个作用:说明了一个外部的结构数组translate,表示数组的大小由后面给出的初始化数据决定,对结构数组进行初始化。在程序中给出了数组初始化数据,所以结构数组translate有9个元素。adbwckd;eiiakb;cwetranslate[0]translate[1]translate[2]translate[3]translate[4]translate[5]translate[6]translate[7]translate[8]第二节结构数组 structtable{charinput,output;};structtabletranslate[]={"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”进行操作。结构指针->成员名“->”运算符有最高的优先级,结合性从左至右。通过结构指针pdate访问成员year的操作就可以写成:pdate->year=1963;等价于:today.year=1963;(*pdate).year=1963;辨疑:pdate->year*pdate->year二、通过结构指针访问结构体的成员例C10_301第三节结构指针 例:用结构指针改写加密程序structtable{charinput,output;};structtabletransl[]={"a","d","b","w","c","k","d",";","e","i","i","a","k","b",";","c","w","e’,};main(){charch;structtable*p,*pend;/*p和pend为向结构指针*/pend=&transl[sizeof(transl)/sizeof(structtable)-1];/*pend指向结构数组transl的最后一个元素*/while((ch=getchar())!="n"){for(p=transl;p->input!=ch&&p!=pend;p++);if(p->input==ch)putchar(p->output);elseputchar(ch);}}adbwckd;eiiakb;cwetranslate[0]translate[1]translate[2]translate[3]translate[4]translate[5]translate[6]translate[7]translate[8]ppend第三节结构指针 例.C:请分析程序的运算结果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("%dn",p->x);printf("%dn",(*p).x);printf("%dn",*p->y);printf("%dn",*(*p).y);printf("%dn",++p->x);printf("%dn",(++p)->x);printf("%dn",p->x++);printf("%dn",p->x);printf("%dn",++(*p->y));printf("%dn",++*p->y);printf("%dn",*++p->y);printf("%dn",p->x);printf("%dn",*(++p)->y);printf("%dn",p->x);printf("%dn",*p->y++);printf("%dn",p->x);printf("%dn",*(p->y)++);printf("%dn",p->x);printf("%dn",*p++->y);printf("%dn",p->x);}第三节结构指针 结构数组array的初始化后的状态如图所示。①p->x取结构指针p指向的结构的成员x的值,输出②(*p).x取结构指针p的内容的成员x的值,输出③*p->y取结构指针p的指针成员y的内容,输出④*(*p).y取指针p的内容的指针成员y的内容,输出⑤++p->xp所指向的x加1,x先加1后再输出,p不加11002003004005001020304050array[0]array[1]array[2]array[3]array[4]data[0]data[1]data[2]data[3]data[4]p100101011001001010101第三节结构指针 ①(++p)->xp先加1后再取x的值,x不加1,输出②p->x++先取x的值,输出,然后x再加1,③p->x输出④++(*p->y)p所指的y的内容先加1,输出,p不加1,y也不加1⑤++*p->y同上,由运算的结合性隐含了括号,输出1012003004005001020304050array[0]array[1]array[2]array[3]array[4]data[0]data[1]data[2]data[3]data[4]p2002012021222002002012122第三节结构指针 ①*++p->yp所指的y先加1后再取y的内容,输出,p不加1,y的内容不加1②p->x输出③*(++p)->yp先加1后再取所指y的内容,输出30④p->x输出⑤*p->y++取p所指的y的内容输出,然后p所指的y加1⑥p->x输出1012013004005001022304050array[0]array[1]array[2]array[3]array[4]data[0]data[1]data[2]data[3]data[4]p30201300302013030030300第三节结构指针 ①*(p->y)++取p所指的y的内容,输出,然后p所指的y再加1②p->x输出③*p++->y取p所指的y的内容,输出,然后p再加1④p->x输出1012013004005001022304050array[0]array[1]array[2]array[3]array[4]data[0]data[1]data[2]data[3]data[4]p40300504003004050400例C10_303第三节结构指针 指针运算与++运算规律小结由运算符的优先级和结合性决定++操作的对象;由++的前缀/后缀形式,决定操作的时机。++p->xp->x++++*p->y*++p->y*(++p)->y*p->y++;*(p->y)++*p++->y第三节结构指针 结构与函数的关系:向结构中传递函数的成员;在函数之间传递整个结构;向函数传递结构的地址(指针)。向函数中传递结构的成员在函数中传递结构成员的方法与传递简单变量的方法相同:在函数之间传递成员的值;在函数之间传递成员的地址。一、结构、结构指针作为函数的参数第四节在函数之间传递结构 实例printf(“%d”,man.birthday.year);传递成员的值scanf(“%d”,&man.birthday.year);传递成员的地址gets(man.name);传递结构成员的地址第四节在函数之间传递结构 在函数之间传递整个结构将结构作为整体,在函数之间传递:将结构变量作为形参;函数的返回值为一个结构类型。第四节在函数之间传递结构 例:利用结构变量求解两个复数之积。①、(3+4i)×(5+6i)②、(10+20i)×(30+40i)structcomplx{intreal;/*real为复数的实部*/intim;/*im为复数的虚部*/};structcomplxcmult(za,zb)/*函数返回值为结构类型*/structcomplxza,zb;/*形式参数为结构类型*/{structcomplxw;w.real=za.real*zb.real-za.im*zb.im;w.im=za.real*zb.im+za.im*zb.real;return(w);/*返回计算结果,返回值的类型为结构*/}例C10_401第四节在函数之间传递结构 向函数传递结构的地址向函数中传递结构的地址要将函数的形参定义为指向结构的指针,在调用时要用结构的地址作为实参。例:输入10本书的名称和单价,按照单价排序。程序中使用插入排序算法。第四节在函数之间传递结构 插入排序的基本思想是:在数组中,有N个已经从小到大已经排好序的元素,要加入1个新的元素时,可以从数组的第1个元素开始,依次与新元素进行比较。当数组中首次出现第i个元素的值大于新元素时,则新元素就应当插在原来数组中的第i-1个元素与第i个元素之间。此时可以将数组中第i个元素之后(包括第i个元素)的所有元素向后移动1个位置,将新元素插入,使它成为第i个元素。这样就可以得到已经排好序的N+1个元素。第四节在函数之间传递结构 5552367911555555555555222555535555555597611插入排序法示例第四节在函数之间传递结构 #defineNUM10structbook/*定义结构book*/{charname[20];/*书名*/floatprice;/*单价*/};main(){structbookterm,books[NUM];intcount;/*数组books的元素计数器*/for(count=0;countprice>term.price)break;for(q=pend-1;q>=pbook;q--)*(q+1)=*q;*pbook=term;/*在pbook处插入新元素term*/}第四节在函数之间传递结构 printbook(pbook)structbook*pbook;{printf("%-20s%6.2fn",pbook->name,pbook->price);}例C10_402第四节在函数之间传递结构 定义结构变量stu:structstudent{intnum;floatscore;charsex;}stu;结构变量stu占用内存情况numscoresex2个字节4个字节1个字节sizeof(stu)是7。第五节联合类型 union定义联合变量stu:student{intnum;floatscore;charsex;}stu;联合变量stu占用内存情况4个字节2个字节1个字节unionunionunion联合变量占用空间的大小等于成员分量中最长的成员占用内存的长度。4个字节第五节联合类型 0x780x560x340x12union{longi;intk;charc;}mix;mix.i=0x12345678;printf(“%xn”,mix.i);printf(“%xn”,mix.k);printf(“%xn”,mix.c);ffe0ffe1ffe2ffe3高地址低地址1234567800010010001101000101011001111000低高ffe3ffe2ffe1ffe0第五节联合类型 mix.c=‘A’;1234567800010010001101000101011001111000低高ffe3ffe2ffe1ffe01234564100010010001101000101011001000001低高ffe3ffe2ffe1ffe0printf(“%ldn”,mix.i);printf(“%dn”,mix.k);printf(“%cn”,mix.c);30541984122081A例C10_501第五节联合类型 枚举类型的特点:数据的取值是有限个数的数据类型。定义枚举类型的格式enum枚举类型名{可能的取值表};例如:enumweekday{sun,mon,tue,wed,thu,fri,dat};说明枚举类型变量的格式enum枚举类型名变量标识符;第六节枚举类型 用户自定义类型标准类型(如int、char、float等):系统已经定义好的类型,用户可以直接使用,无须再进行定义。用户自定义类型:用户根据自己的实际要求,自己定义的新的数据类型。除结构和联合等类型之外,还可以用类型说明语句typedef定义新的类型标识符来代替已有的类型。typedef语句的一般形式typedef已定义的类型新的类型实例typedefintINTEGER;typedeffloatREAL;等价:inti,j;INTEGERi,j;floatpai;REALpai;第七节用typedef定义类型 用链表处理不定长数组。什么是链表?结构定义:structstudent{intnum;floatscore;structstudent*next;};链表的分类单向链表、双向链表等。一、链表概述8910189.5ffcdff028910390fffd……ffcd8910785NULL……fffd第八节链表基础 动态存储分配函数原型:void*malloc(intsize)头文件:stdlib.h。功能:分配size个字节的存储区。返回值:分配成功,所分配区域的首返回地址。分配失败,返回0。例如:structstudent*ps;ps=(structstudent*)malloc(sizeof(structstudent)); 释放内存函数原型:voidfree(void*p)头文件:stdlib.h。功能:释放p所指向的内存空间。返回值:无。例如:前面说明结构指针ps,为其分配了内存,释放内存,则写:free(ps); 创建链表的过程:按照结构的大小分配一块内存区域。将该区域的首地址赋给一个头指针。继续分配一块内存区域。将该区域的首地址分配给前一个结点的结点指针变量。继续上述过程,直到链表的尾。二、创建链表 psf1aa8019189.5NULL8910785NULL8910380NULLps=(structstudent*)malloc(sizeof(structstudent))scanf(“%ld,%f”,&ps->num,&ps->score);ps->next=NULL;p1=(structstudent*)malloc(sizeof(structstudent))p1ffe4ps->next=p1ffe4ff4d例C11_701 headp1p2n=0headp1p2n=1p1n=2p2p1n=3p2NULL例C11_701ap1=p2=(structstudent*)malloc(sizeof(structstudent))head=NULLp2->next=p1 structstudent*creat(){……do{scanf("%ld,%d",&num,&a);if(num!=0){if(head==NULL)head=tail;elsetail=tail->next;tail->num=num;tail->score=a;tail->next=(structstudent*)malloc(LEN);}elsetail->next=NULL;}while(num!=0);return(head);} {if(head==NULL)head=tail;elsetail=tail->next;tail->num=num;tail->score=a;tail->next=(structstudent*)malloc(LEN);}headtail 从头结点开始,到尾结点结束。尾结点的特征:其指向为空。三、输出一个链表 删除一个结点,既让上一个结点指向下一个结点。三、在链表中删除一个节点f1aa8019189.5ffe48910785NULL8910380ff4d头指针ps(ps-1)->next=ps->next8019189.5ffe4ff4d 插入一个结点,既插入处前一个结点,指向新结点,新结点指向一个结点。四、在链表中插入一个节点f1aa8019189.5ffe48910785NULL头指针ff4d8910380ff4dpsffddffddps->next=head->next;ps=(structstudent*)malloc(sizeof(structstudet));head->next=ps->next;'