C语言程序设计-基于计算思维的培养 课件 第11章 自定义数据类型_第1页
C语言程序设计-基于计算思维的培养 课件 第11章 自定义数据类型_第2页
C语言程序设计-基于计算思维的培养 课件 第11章 自定义数据类型_第3页
C语言程序设计-基于计算思维的培养 课件 第11章 自定义数据类型_第4页
C语言程序设计-基于计算思维的培养 课件 第11章 自定义数据类型_第5页
已阅读5页,还剩52页未读 继续免费阅读

下载本文档

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

文档简介

第十一章自定义数据类型目录/Contents结构体数据类型,共用体数据类型、枚举数据类型、定义数据类型的别名结构体变量、结构体数组、结构体指针的定义和初始化结构体成员的引用、成员选择运算符、指向运算符向函数传递结构体变量、结构体数组、结构体指针动态数据结构、动态链表问题的提出在程序里怎样表示一个人的信息(姓名、年龄、性别…)?想表示多个人呢?如何用计算机程序实现下述表格的管理?结构体类型的声明structstudent{longid;charname[20];charsex;intage;floatscore[5];charaddr[30];};声明了一个结构体类型构成结构体的变量称为结构体的成员(StructureMember)结构体的名字称为结构体标签(StructureTag)结构体类型声明structstudent{longid;charname[20];charsex;intage;floatscore[5];charaddr[30];};structstudent{longid;charname[20];charsex;intage;floatmath;floatenglish;floatcomputer;floatprogramming;floatdatabase;charaddr[30];};结构体模板(StructureTemplate)不要遗忘分号!!形成一个类型声明的样板用于生成结构体变量但并未声明结构体变量因而编译器不为其分配内存

结构体变量定义(1)先定义结构体类型,再定义变量名(2)在定义类型的同时定义变量(3)直接定义结构体变量(即无名结构体)structstudent{longid;charname[20];charsex;intage;floatscore[5];charaddr[30];}stu;struct{longid;charname[20];charsex;intage;floatscore[5];charaddr[30];}stu;typedef定义数据类型struct

student

stu1,stu2;/*Itworks*/student

stu1,stu2;/*Canthiswork?*/struct

stu1,stu2;/*Canthiswork?*/STUDENT

stu1,stu2;

/*Itworks!*/关键字typedef为一种已存在的类型定义一个别名,并未定义新类型STUDENT与structstudent类型是同义词typedefstructstudent{longid;charname[20];charsex;intage;floatscore[5];charaddr[30];}STUDENT;结构体变量初始化structstudentstu={1232019101,"张三丰",'M',20,{85,78,90,83,77},"北京"};STUDENTstu={1232019101,"张三丰",'M',20,{85,78,90,83,77},"北京"};等价于typedefstructstudent{longid;charname[20];charsex;intage;floatscore[5];charaddr[30];}STUDENT;stu.id=1232019101;strcpy(,”张三丰”);stu.sex=‘M’;stu.age=20;stu.score[]={85,78,90,83,77};Stu.addr=“北京”;等价于注意!!!结构体嵌套嵌套的结构体(NestedStructure)就是在一个结构体内包含了另一个结构体作为其成员typedefstructstudent{longid;charname[20];charsex;intage;floatscore[5];DATEbirthday;charaddr[30];}STUDENT;typedefstructdate{ intmonth; intday; intyear;}DATE;结构体嵌套结构体变量的引用访问结构体变量的成员必须使用成员选择运算符(也称圆点运算符)当出现结构体嵌套时,必须以级联方式访问结构体成员typedefstructstudent{longid;charname[20];charsex;intage;floatscore[5];DATEbirthday;charaddr[30];}STUDENT;typedefstructdate{ intmonth; intday; intyear;}DATE;结构体.成员名stu.id=1232019101;stu.birthday.year=2000;stu.birthday.month=5;stu.birthday.day=12;结构体变量的引用【例11.1】

编写程序,从键盘输入两个学生的学号、姓名、性别、年龄、出生日期、出生地和某门课成绩,输出成绩较高的学生的所有信息。#include<stdio.h>typedefstructdate{ intmonth; intday; intyear;}DATE;typedefstructstudent{ longid; charname[20]; charsex; intage; DATEbirthday; charaddr[30]; floatscore;}STUDENT;结构体变量的引用intmain(){STUDENTstu1,stu2;printf("Entertherecordofthefirststudent:\n");scanf("%ld%s%c%d%d%d%d%s%f",&stu1.id,,&stu1.sex,&stu1.age,&stu1.birthday.month,&stu1.birthday.day,&stu1.birthday.year,stu1.addr,&stu1.score);printf("Entertherecordofthesecondstudent:\n");scanf("%ld%s%c%d%d%d%d%s%f",&stu2.id,,&stu2.sex,&stu2.age,&stu2.birthday.month,&stu2.birthday.day,&stu2.birthday.year,stu2.addr,&stu2.score);printf("Thehigherscorestudentis:\n");if(stu1.score>stu2.score){ printf("%10ld%8s%3c%4d%04d/%02d/%4d%6s%4.1f",stu1.id,,stu1.sex,stu1.age,stu1.birthday.month,stu1.birthday.day,stu1.birthday.year,stu1.addr,stu1.score);}

格式符%02d中2d前面的前导符0表示输出数据时,若左边有多余位,则补0结构体变量的引用elseif(stu1.score<stu2.score) {printf("%10ld%8s%3c%4d%04d/%02d/%4d%6s%4.1f",stu2.id,,stu2.sex,stu2.age,stu2.birthday.month,stu2.birthday.day,stu2.birthday.year,stu2.addr,stu2.score);}else{printf("%10ld%8s%3c%4d%04d/%02d/%4d%6s%4.1f",stu1.id,,stu1.sex,stu1.age,stu1.birthday.month,stu1.birthday.day,stu1.birthday.year,stu1.addr,stu1.score);printf("%10ld%8s%3c%4d%04d/%02d/%4d%6s%4.1f",stu2.id,,stu2.sex,stu2.age,stu2.birthday.month,stu2.birthday.day,stu2.birthday.year,stu2.addr,stu2.score);}return0;}结构体所占内存大小struct类型用内存字节数=?是所有成员变量的内存总和吗?printf("%d\n",sizeof(struct

sample));用运算符sizeof获得结构体大小sizeof(变量或表达式)sizeof(类型)12Why?printf("%d\n",sizeof(SAMPLE));事实上,所有数据类型在内存中都是从偶数地址开始存放的且结构所占的实际空间一般是按照机器字长对齐的不同的编译器、平台,对齐方式会有变化结构体变量的成员的存储对齐规则是与机器相关的具有特定数据类型的数据项大小也是与机器相关的所以一个结构体在内存中的存储格式也是与机器相关的非所有成员变量的内存总和12个字节m1m2m3m1m3m2结构体所占内存大小结构体数组的定义和初始化typedefstructstudent{longid;charname[20];charsex;intage;floatscore[5];DATEbirthday;charaddr[30];}STUDENT;typedefstructdate{ intmonth; intday; intyear;}DATE;结构体数组的定义和初始化STUDENTstu[5]={{1232019101,"张三丰",'M',20,{5,12,1999},"北京",{88,86,90,75}},{1232019102,"张

磊",'M',20,{4,2,1999},"上海",{80,86,93,79}},{1232019103,"王大年",'M',20,{1,16,1999},"南京",{78,66,90,77}},{1232019104,"赵

刚",'M',21,{11,24,1998},"大连",{85,80,98,95}},{1232019105,"李云龙",'M',20,{8,10,1999},"深圳",{78,86,80,75}},};for(i=0;i<5;i++){scanf("%ld%s%c%d%d%d%d%s",&stu[i].id,stu[i].name,&stu[i].sex,&stu[i].age,&stu[i].birthday.month,&stu[i].birthday.day,&stu[i].birthday.year,stu[i].addr);for(j=0;j<4;j++){ scanf("%f",&stu[i].score[j]);}}结构体数组的定义和初始化结构体数组的定义和初始化#include<stdio.h>#defineM5#defineN4typedefstructdate{ intmonth; intday; intyear;}DATE;typedefstructstudent{ longid; charname[20]; charsex; intage; DATEbirthday; charaddr[30]; floatscore[4];}STUDENT;【例11.3】

编写程序,使用结构体数组从键盘输入5个学生4门课的成绩,计算并输出每个学生4门课的平均分。结构体数组的定义和初始化intmain(){STUDENTstu[M]; /*定义结构体数组*/inti,j;floatsum[M];for(i=0;i<M;i++){ /*输入M个学生的信息*/printf("EntertherecordofNo.%dstudent:\n",i+1);scanf("%ld%s%c%d%d%d%d%s",&stu[i].id,stu[i].name,&stu[i].sex,&stu[i].age, &stu[i].birthday.month,&stu[i].birthday.day,&stu[i].birthday.year,stu[i].addr);for(j=0;j<N;j++){scanf("%f",&stu[i].score[j]);}}for(i=0;i<M;i++){sum[i]=0.0;for(j=0;j<N;j++){ sum[i]=sum[i]+stu[i].score[j];}printf("%10ld%6s%3c%4d%02d/%02d/%4d%6s%6.1f%6.1f%6.1f%6.1f%6.1f\n",stu[i].id,stu[i].name,stu[i].sex,stu[i].age,stu[i].birthday.month,stu[i].birthday.day,stu[i].birthday.year,stu[i].addr,stu[i].score[0],stu[i].score[1],stu[i].score[2],stu[i].score[3],sum[i]/4);/*显示结构体成员信息*/}return0;}结构体指针的定义和初始化ptstu1

STUDENT

stu1;

STUDENT

*pt;pt=&stu1;成员1成员2成员3成员4成员5如何定义指向结构体变量的指针?STUDENT

*pt=&stu1;等价于typedefstructstudent{longid;charname[20];charsex;intage;floatscore[5];DATEbirthday;charaddr[30];}STUDENT;typedefstructdate{ intmonth; intday; intyear;}DATE;结构体指针的定义和初始化ptstu1

STUDENT

stu1;

STUDENT

*pt;pt=&stu1;成员1成员2成员3成员4成员5如何访问结构体指针变量所指向的结构体成员呢?typedefstructstudent{longid;charname[20];charsex;intage;floatscore[5];DATEbirthday;charaddr[30];}STUDENT;typedefstructdate{ intmonth; intday; intyear;}DATE;通过stu1和成员选择运算符访问结构体成员stu1.id=1;通过pt和指向运算符访问结构体成员(*pt).id=1;

pt->id=1;结构体指针的定义和初始化

STUDENT

stu;

STUDENT

*pt;pt=&stu;成员1成员2成员3成员4成员5typedefstructstudent{longid;charname[20];charsex;intage;floatscore[5];DATEbirthday;charaddr[30];}STUDENT;typedefstructdate{ intmonth; intday; intyear;}DATE;当结构体嵌套时,结构体指针变量应逐级访问其所指向的结构体成员,直到最后一级成员。

stu.birthday.day=21;

(*pt).birthday.day=21;pt->birthday.day=21;ptstu

STUDENT

stu[20];

STUDENT

*pt;pt=stu;

相当于如何定义指向结构体数组的指针?STUDENT

*pt=stu;STUDENT

*pt=&stu[0];stu[0]stu[1]stu[2]stu[3]ptstu[20]typedefstructstudent{longid;charname[20];charsex;intage;floatscore[5];DATEbirthday;charaddr[30];}STUDENT;typedefstructdate{ intmonth; intday; intyear;}DATE;stu[4]stu[5]……stu[19]或结构体指针的定义和初始化结构体做函数参数①结构体成员作为函数参数。复制单个成员的内容,函数内部对结构体内容的修改不影响其结构。②结构体变量作为函数参数。③结构体数组或结构体指针作为函数参数。结构体变量作函数参数typedefstructemployee{ intemID; char*name; charsex; intage;}EMPLOYEE;voidFun(EMPLOYEEem){ em.emID=1001; ="张大彪"; em.sex='M'; em.age=25;}#include<stdio.h>voidFun(EMPLOYEEem);intmain(){ EMPLOYEEemp; emp.emID=1003; ="王妙可"; emp.sex='F'; emp.age=18; printf("Beforefunctioncall:%d%8s%3c%4d\n",emp.emID,,emp.sex,emp.age); Fun(emp); printf("Afterfunctioncall:%d%8s%3c%4d\n",emp.emID,,emp.sex,emp.age); return0;}【例11.4结构体变量作为函数参数】结构体指针作函数参数typedefstructemployee{ intemID; char*name; charsex; intage;}EMPLOYEE;voidFun(EMPLOYEE*em){ em->emID=1001; em->name="张大彪"; em->sex='M'; em->age=25;}#include<stdio.h>voidFun(EMPLOYEE*em);intmain(){ EMPLOYEEemp; emp.emID=1003; ="王妙可"; emp.sex='F'; emp.age=18; printf("Beforefunctioncall:%d%8s%3c%4d\n",emp.emID,,emp.sex,emp.age); Fun(&emp); printf("Afterfunctioncall:%d%8s%3c%4d\n",emp.emID,,emp.sex,emp.age); return0;}【例11.5结构体指针作为函数参数】结构体变量作为函数的返回值typedefstructemployee{ intemID; char*name; charsex; intage;}EMPLOYEE;EMPLOYEEFun(EMPLOYEEem){ em.emID=1001; ="张大彪"; em.sex='M'; em.age=25; returnem;}#include<stdio.h>EMPLOYEEFun(EMPLOYEEem);intmain(){ EMPLOYEEemp; emp.emID=1003; ="王妙可"; emp.sex='F'; emp.age=18; printf("Beforefunctioncall:%d%8s%3c%4d\n",emp.emID,,emp.sex,emp.age); emp=Fun(emp); printf("Afterfunctioncall:%d%8s%3c%4d\n",emp.emID,,emp.sex,emp.age); return0;}【例11.6结构体变量作函数返回值】结构体作函数参数向函数传递结构体的完整结构复制整个结构体成员的内容,多个值函数内对结构内容的修改不影响原结构内容传递更直观,但开销大向函数传递结构体的首地址用结构体数组/结构体指针作函数参数仅复制结构体的首地址,一个值修改结构体指针所指向的结构体的内容指针传递效率高【例11.7】

编写程序,使用结构体数组作为函数参数,从键盘输入5个学生4门课的成绩,计算并输出每个学生4门课的平均分。typedefstructdate{ intmonth; intday; intyear;}DATE;typedefstructstudent{ longid; charname[20]; charsex; intage; DATEbirthday; charaddr[30]; floatscore[4];}STUDENT;#include<stdio.h>#defineM5#defineN4voidInputScore(STUDENTstu[],intm,intn);voidGetAverage(STUDENTstu[],floatav[],intm,intn);voidPrintScore(STUDENTstu[],floatav[],intm,intn);intmain(){ STUDENTstu[M]; intm,n; floataver[M]; printf("Enterthenumberofstudents:"); scanf("%d",&m); printf("Enterthenumberofsubjects:"); scanf("%d",&n); InputScore(stu,m,n); GetAverage(stu,aver,m,n); PrintScore(stu,aver,m,n); return0;}结构体数组作函数参数voidInputScore(STUDENTstu[],intm,intn){ inti,j; for(i=0;i<M;i++) { printf("EntertherecordofNo.%dstudent:\n",i+1); scanf("%ld%s%c%d%d%d%d%s",&stu[i].id,stu[i].name,&stu[i].sex,&stu[i].age, &stu[i].birthday.month,&stu[i].birthday.day,&stu[i].birthday.year,stu[i].addr); for(j=0;j<N;j++) { scanf("%f",&stu[i].score[j]); } } }voidGetAverage(STUDENTstu[],floatav[],intm,intn){ inti,j,sum[M]; for(i=0;i<M;i++) { sum[i]=0.0; for(j=0;j<N;j++) { sum[i]=sum[i]+stu[i].score[j]; } av[i]=sum[i]/4; }}结构体数组作函数参数voidPrintScore(STUDENTstu[],floatav[],intm,intn){ inti,j; printf("Finalresults:\n"); for(i=0;i<m;i++) { printf("%10ld%6s%3c%4d%02d/%02d/%4d%6s%6.1f%6.1f%6.1f%6.1f%6.1f\n", stu[i].id,stu[i].name,stu[i].sex,stu[i].age,stu[i].birthday.month,stu[i].birthday.day, stu[i].birthday.year,stu[i].addr,stu[i].score[0],stu[i].score[1],stu[i].score[2], stu[i].score[3],av[i]); }}共用体结构体(Struct)把关系紧密且逻辑相关的多种不同类型的变量,组织到统一的名字之下占用相邻的一段内存单元共用体,也称联合(Union)把情形互斥但逻辑相关的多种不同类型的变量,组织到统一的名字之下占用同一段内存单元,每一时刻只有一个数据起作用共用体sizeof(uniondata)取决于占空间最多的那个成员变量同一内存单元在每一瞬时只能存放其中一种类型的成员起作用的成员是最后一次存放的成员,不能作为函数参数不能进行比较操作,只能对第一个成员初始化共用体【例11.8】

有一批教师和学生的数据,教师的数据包括:姓名、编号、性别、职业、职务。学生的数据包括:姓名、编号、性别、职业、班级。编写程序,使用同一个表格来处理这批数据。#include<stdio.h>#defineN10typedefunioncategory{ intclas; charposition[10];}CATEGORY;typedefstructpersonel{ intnum; charname[20]; charsex; charjob; CATEGORYca;}PERSONEL;intmain(){PERSONELperson[N];inti,n;printf("Inputthenumberofpersons:");scanf("%d",&n);for(i=0;i<n;i++){printf("PleaseinputNo.%dperson'sdata:\n",i+1);scanf("%d%s%c%c",&person[i].num,person[i].name,&person[i].sex,&person[i].job);if(person[i].job=='s') scanf("%d",&person[i].ca.clas);elseif(person[i].job=='t') scanf("%s",&person[i].ca.position);else printf("Inputdataerror!");}printf("\n");printf("No.\tname\tsex\tjob\tclass/position\n");for(i=0;i<n;i++){if(person[i].job=='s')printf("%-6d%-10s%-4c%-4c%-10d\n",person[i].num,person[i].name,person[i].sex,person[i].job,person[i].ca.clas);else printf("%-6d%-10s%-4c%-4c%-10s\n",person[i].num,person[i].name,person[i].sex,person[i].job,person[i].ca.position);}return0; }枚举类型枚举(Enumeration)数据类型描述的是一组整型值的集合用于当某些量仅由有限个数据值组成时

enumweeks{SUN,MON,TUE,WED,THU,FRI,SAT};

enumweekstoday;enumresponse{no,yes,none};enumresponseanswer;

today=TUE;

answer=yes;

enumresponse{no=-1,yes=1,none=0};枚举类型【例11.10】

球袋里装有红、黄、蓝、白、黑5种颜色的乒乓球若干,每次从球袋里先后取出3个球,计算得到3个不同颜色的球的可能取法,并显示每种排列的情况。枚举类型问题的提出数组可能存在越界、浪费内存现象数组插入和删除操作时,需要移动大量的数组元素是否存在一种合理使用内存的方法呢?这些动态数据结构使用结构体和指针来实现。例如:structnode{ intdata; structnode*next;};动态数据结构---单向链表链表:线性表的链式存储结构特点:用一组任意的存储单元存储线性表的数据;存储单元可以是连续的,也可是不连续的为表示每个元素与后继元素的逻辑关系,除存储元素本身信息外,还要存储其直接后继信息datanextheaddatanextdatanextdataNULL数据域:存储数据元素信息指针域:存储直接后继的节点信息structLink{

int data;

structLink*next;};n个节点链接成一个链表(因为只包含一个指针域,故又称线性链表或单向链表)链表的建立向链表中添加一个新节点data=Anodedata=Bnodedata=C∧nodehead空指针NULL表示链表结尾链表的头指针:访问链表的关键structnode{ intdata; structnode*next;};链表的建立若原链表为空表(head==NULL),则将新建节点p置为头节点,让head指向新节点。

head=NULL;p->next=head;head=p;链表建立原链表不是空链表,则按节点值的大小(假定节点值已按升序排序)确定插入新节点的位置。如果在头节点前插入新节点,则将新节点的指针域指向原链表的头节点,且让head指向新节点。

p=malloc(sizeof(structnode));p->data=2;p->next=head;head=p;链表建立在链表中间插入新节点,则用语句p->next=prev->next;将新节点的指针域指向下一个节点,然后用语句prev->next=p;让前一个节点的指针域指向新节点链表建立在表尾插入新节点,则直接用语句prev->next=p;将尾节点的指针域指向新节点即可。链表建立-链表插入函数structnode*InsertNode(structnode*list,intn){ structnode*p; p=malloc(sizeof(structnode)); if(p=NULL) { printf("Error:mallocfailedinInsertNode\n"); exit(EXIT_FAILURE); } p->data=n; p->next=list; returnp;}链表建立-从键盘向链表输入数据structnode*ReadNumbers(void){ structnode*head; printf("Inputaseriesofintegers(0toterminate):"); for(;;) { scanf("%d",&n); if(n==0) { returnhead; } InsertNode(head,n); }}链表的搜索structnode*SearchNode(structnode*list,intn){ structnode*p; for(p=list;p!=NULL;p=p->next) if(p->data==n) returnp; returnNULL;}structnode*SearchNode(structnode*list,intn){ for(;list!=NULL;list=list->next) if(list->data==n) returnlist; returnNULL;}structnode*SearchNode(structnode*list,intn){for(;list!=NULL&&list->data!=n;list=list->next);returnlist;}structnode*SearchNode(structnode*list,intn){while(;list!=NULL&&list->data!=n;

温馨提示

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

评论

0/150

提交评论