




已阅读5页,还剩49页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第11章结构体与共用体,1、结构体类型的定义 2、结构体变量的定义及引用 3、结构体数组 4、结构体类型的指针 5、链表的基本操作 6、共用体和枚举类型(了解),问题:为了描述一个事物的不同属性,需要用到各种不同类型的数据,这些数据彼此相关,形成一个有机的整体。例如:一个教师的基本信息由姓名、性别、年龄、职称、工资等几项组合而成。如何描述一个教师的情况呢? 前面我们已学习过各种基本类型的变量和数组,而且我们知道,各个变量之间是相互独立的,无任何联系;而数组只能用来表示一批相同类型的数据。因此,若用单个变量分别表示教师的姓名、性别、年龄等属性,则难以反映他们之间的内在联系;若用数组,则根本无法表示,因为姓名、性别、年龄等不属同一种数据类型。 C语言中用“结构体”来描述由多个不同类型的数据组成的数据集合。相当于其他高级语言中的“记录”.,11.1结构体类型的定义,与基本数据类型不同的是,结构体是又一种构造类型,是由多个类型的数据成员组合而来的。因此该类型的具体内容应根据需要先定义,后使用。 可以定义如下结构体类型来描述教师的基本情况: struct teacher /*struct 是关键字*/ char name30; /*内是该类型的各成员*/ char sex; int age; char position10; float salary; ; /*语句末尾是“;” */ 该结构体类型名为struct teacher,teacher 是该结构体的标识符;该类型包含有6个成员的数据项:name、 sex、 age、 position 和salary,其中每个成员项都有自己的类型。,可见,定义一种新的结构体类型的一般形式是: struct 结构体类型名 成员类型 成员名; 成员类型 成员名; ; 其中,struct 是 关键字,结构体类型名、结构体成员名的命名规则同变量的命名规则一样。 特别提示:struct teacher只是一种具体的结构体类型,根据需要,程序员可以定义多个不同内容的结构体类型。其中的成员项是该类型的组成部分,而不是变量。 结构体类型的成员可以是基本类型的变量或数组,也可以是结构体类型的数据。即结构体类型的嵌套定义。 例如,若将教师的年龄改为出生日期,则可以将出生日期定义为一个结构体类型,然后嵌入 struct teacher中。,将出生日期单独定义为一个结构体类型后再嵌入。 Struct date_type int year; int month; int day; ; Struct teacher_2 char name30; char sex; struct date_type birthday; char position10; float salary; (常用),直接嵌入。 Struct teacher_3 char name30; char sex; struct date_type int year; int month; int day; birthday; char position10; float salary; /*成员birthday又是一个结构体类型的数据。*/,11.2结构体变量的定义及引用,经以上定义后,结构体类型struct teacher与系统定义的类型int、long、float 等一样,可以用它来定义该类型的变量、数组、函数等。 不同的是:结构体类型的作用范围是有限制的。在函数体内定义的结构体类型的作用域为本函数内,在函数体外定义的结构体类型的作用域为本程序文件内,若要引用不在本文件内的结构体类型,通常用#include命令将定义该类型的文件包含进来。 例11.1定义一个结构体变量,用于存放一个教师的信息,然后将其输出。,#include “stdio.h“ main() struct teacher /*该类型的作用范围在本函数内*/ char name30; char sex; int age; char position10; float salary; ; struct teacher person; /*定义结构体变量person*/ strcpy(,“wang li“); person.sex=f; /*给各成员赋值*/ person.age=30; strcpy(person.position,“middle“); person.salary=1600;,printf(“n name sex age position salary“); printf(“n%-10s %3c %5d %10s %8.2f“,, person.sex,person.age,person.position,person.salary); 分析: *本例中结构体类型在函数体内定义,其作用范围在本函数体内。 * 先定义结构体类型,后定义结构体变量。 * 对结构体变量输入输出操作、或将基本类型的数据赋给结构体变量时,需分别访问各个基本类型的成员,不能整体赋值或输入输出。 如:printf(“%s%c%d%s%f”,person); 错! person=“li li”,f, 24, “primary”,1000; 错!,例11.2 定义一个结构体类型,包含通讯录中的如下信息:姓名、年龄、电话、通讯地址;并定义该类型的变量,输入数据并输出。 程序l11_2.c #include “stdio.h“ struct address_list /*在函数体外定义结构体类型*/ char name10; /*该类型的作用域为本程序内*/ int age; char tel10; char address40; ; main() struct address_list s; /*定义变量s,占空间62个字节*/ printf(“n input name:“); gets();,printf(“ input age:“); scanf(“%d“, 分析: *结构体类型address_list 放在函数体外定义,其作用范围为本程序文件内。 * 结构体变量的输入输出需逐个访问基本类型的成员,引用方法与同类型的变量、数组相同。,例11.3 定义一结构体类型,包含工人的工资信息:编号、姓名、工资。并定义变量存放两人的数据,然后交换,输出交换前后的信息。 程序l11_3.c #include “stdio.h“ main() struct salary_list char no10; char name30; float salary; ; struct salary_list z,x=“10“,“li ming“,2000, y=“12“,“wang yan“,2500; /*结构体变量的初始化,给出各成员的数据并用括起来,各成员之间用逗号分开*/,printf(“n no name salary“); printf(“nx:%-5s%-6s%10.2f“,x.no,,x.salary); printf(“ny:%-5s%-6s%10.2f“,y.no,,y.salary); z=x; x=y; y=z; /*交换两个结构体变量*/ printf(“nafter exchange:“); printf(“nx:%-5s%-6s%10.2f“,x.no,,x.salary); printf(“ny:%-5s%-6s%10.2f“,y.no,,y.salary); 特别提示:同类型的结构体变量可以整体赋值,即可以将一个结构体变量整体赋给相同类型的另一个结构体变量。,说明一、定义结构体变量,定义结构体变量的方法有三种,(经常用第一种): 方法一:先定义结构体类型,再定义结构体变量。 如:struct teacher t1,t2; (例11.1) 方法二:定义结构体类型的同时定义结构体变量(例11.2) 。 又如:struct course math long no; 4B char name30; math,english; 30B 若以后还需用到此结构体类型,定义方法同1: struct course chemic; 方法三:格式同方法(二),其中类型名course 省略,缺点是该类型无法再次引用。 *结构体变量的存储:系统按结构体类型中各成员的类型给变量分配存储空间。如上图:,no name,说明二、结构体变量的引用,结构体变量定义后,可以分两个层次引用: *访问结构体变量的成员。 *引用整个结构体变量。 1、使用成员运算符“.”引用结构体变量的成员, “.”的优先级仅次于括号。 如例11.1、11.2、11.3中的, person.age x.no ,s,salary等成员的赋值、 输入、输出。 person.age+等价于(person.age)+ 对结构体变量中的成员的操作与基本类型的变量完全相同。 注意:当结构体类型嵌套定义时,应逐级访问。 如struct teacher_2 pp; pp.birthday.year=1999; 2、相同类型的结构体变量之间可以整体赋值。如例11.3中交换两个结构体变量的值。,11.2结构体数组,结构体数组用于保存一批同类型的结构体数据。每个数组元素相当于一个结构体变量。 例:11.4输入三门课的信息(课程编号、课程名),并输出。 分析: * 每门课的信息包含2项,用结构体类型表示,其成员有两项,即课程编号和课程名。 *三门课的信息,用一维数组保存。 输入:可以赋初值,也可由用户输入,本例中采用赋初值的方式。 程序l11_2_1.c 说明:结构体数组的初始化同基本类型的一维数组,只不过每个数组元素是用括起的一个结构体常量。 数组元素中每个成员的访问,同变量的成员的访问。,例11.5输入N个学生的学号、姓名、三门课的成绩,计算每人的平均成绩,并按平均成绩由高到低排序,输出排序后的成绩表。 分析: * 每个学生的信息包括多项,用结构体类型表示,其成员有学号、姓名、三门课的成绩、平均成绩。N个学生的信息用一维数组保存。 * 算法: 输入并计算平均成绩、排序、输出三步。 可将后面两项功能分别用函数实现,在主函数中调用。设排序函数为sort(),输出函数为output(). 分析每个函数的具体组成: 函数类型 参数 函数体 程序l11_2_2.c,/*例11.5程序*/ struct stu char no8; char name10; float score3; float aver; ; #include “stdio.h“ #include “stdlib.h“ #define N 3 #define STU_SC struct stu,main() void sort(STU_SC sc1 ),output(STU_SC sc2 ); STU_SC sc_listN; int i,j; char temp10; float sum; printf(“n input no,name,score(13):“); for(i=0;iN;i+) printf(“nstudent %d: n“,i+1); sum=0; printf(“no:“); gets(sc_listi.no); printf(“name:“); gets(sc_); for(j=0;j3;j+) printf(“score %d: “,j+1); gets(temp); sc_listi.scorej=atof(temp); sum+=sc_listi.scorej; ,sc_listi.aver=sum/3; sort(sc_list); output(sc_list); void sort(STU_SC sc1 ) int i,j,k; STU_SC t; for(i=0;isc1k.aver) k=j; if(k!=i) t=sc1k;sc1k=sc1i;sc1i=t; ,void output(STU_SC sc2 ) int i; printf(“n no name score1 score2 score3 aver“); for(i=0;iN;i+) printf(“n %-8s %-10s“, sc2i.no, ); printf(“%8.2f %8.2f %8.2f %8.2f“, sc2i.score0, sc2i.score1, sc2i.score2,sc2i.aver); ,通过本例说明: 1、结构体数组中的每一个数组元素相当于一个同类型的结构体变量。 2、对数组元素的输入输出及运算均需对元素的基本类型的成员进行,只有同类型的数组元素才可以作为整体相互赋值。 3、结构体数据的成员通常类型各不相同,输入各成员数据时应注意:,4、关于成员数据的输入技巧: *为了正确读入任意字符串,通常用gets()输入字符串,而不用scanf()。 *为了避免多余的回车符影响数据的正常输入,整型、实型的数据也用gets()但作字符串读入,然后再用相应的函数转换成所需类型。 如:char t20; gets(t); sc_listi.scorej=atof(t); 同理, atoi(t)则转换成整型。 *但输入单个字符时,通常用:ch=getchar(); getchar(); 5、本例中,用结构体数组名作函数参数,传递的是数组的首地址,实现主、被调函数共用同一个结构体数组。,11.3指向结构体类型的指针,结构体变量在内存中占据一内存段,该内存段的首地址就是该结构体变量的指针。 通过指向结构体类型数据的指针变量可以间接的访问结构体变量,也可以使用指向结构体数据的指针变量访问结构体数组中的元素。 例11.3.1定义一结构体类型,表示复数。定义该类型的变量和指针变量,用指针变量访问结构体变量。 分析:复数由实部和虚部组成,因此该结构体类型有两个成员:real, image。,L11.3.1程序: main() struct complex /*表示复数的结构体类型*/ float real; float image; ; struct complex x=2,3, *p; p= /*通过p访问x*/ 运行结果:2+3i 2+3i /*两个输出结果相同*/,2 3,使用指向结构体数据的指针变量引用结构体成员的一般格式: 指针变量名-成员名 -为指向运算符,即取指针变量指向的结构体数据的成员。如:p-real 等价于 (*p).real 其含义为:取指针变量p指向的结构体数据的成员real。 例11.3.2使用指向结构体数组元素的指针引用数组元素:输入输出N个复数。 分析:复数用结构体类型表示,输入时用下标法引用数组元素,输出实用指针引用各元素。 注意:p+的含义是p指向下一个数组元素。 为了引用已定义的结构体类型,通常将结构体类型名定义为更简单的宏名。,struct complex int real; int image; ; #define COMPLEX struct complex #define N 5 main() COMPLEX ssN,*p; int i; printf(“n input %d complex:n“,N); for(i=0;i”引用成员*/ printf(“n %d+%di“,p-real,p-image); ,11.4动态内存分配与链表,动态内存分配的引入 问题:如果要在内存中保存一个班学生的数据,按照现有的手段,首先要知道该班的人数,然后据此定义数组,可是,每一个班的人数并不完全相同,并且是浮动的,用确定长度的数组无法保存任意班级学生的数据,如果定义的数组太大,造成内存浪费,太小将导致程序无法实现原功能要求。这显然不够理想和灵活。 解决以上问题的方法是使用动态内存分配:在程序运行中实时申请内存分配,申请到的内存在不用时还可以随时释放。这样就可以根据每次运行程序时要处理的数据的多少随时申请内存,因此可以处理任意人数的数据。,用于动态内存分配的和释放的函数: (1)malloc() 函数原型:void *malloc(unsigned int size) 功能:申请分配size字节的连续内存空间。若分配成功,函数返回所分配内存的首地址;否则返回空指针(NULL)。 (2)calloc() 函数原型:void *calloc(unsigned int n,unsigned int size) 功能:申请分配n各连续的内存空间、每个空间为size字节。若成功,返回所分配内存的首地址;否则返回空指针(NULL)。 (3)free() 函数原型:void free( void *p) 功能:释放以前分配到的、指针p指向的内存空间。无返回值。,例11.4.1编程实现:输入一批实验数据(整型),计算其平均值。(个数由用户输入) #include #include main() int n,i, *p; float sum=0; printf(“n input datas num:“); scanf(“%d“,printf(“n input %d integer:“,n); for(i=0;in;i+,p+) scanf(“%d“,p); sum+=*p; printf(“n aver :%f“,sum/n); free(p); 程序分析: 特别提示: (1)使用分配失败是返回的空指针会造成程序的流产或系统的破坏,因此,程序中应先判断分配是否成功,然后再分别做出处理。 (2)所分配的首地址应先强制转换为所需的类型,然后使用。 (3)动态内存使用后应及时释放,否则,会导致内存资源的枯竭。,链表:是一种重要的数据结构,用来保存一批相同类型的结构体数据。与数组不同的是,链表中的各元素不要求连续存放,而且链表的长度事先不必确定。当要输入数据时,先向系统申请分配一个结构体数据的空间,因此实现链表时要用到动态内存分配技术。由于链表的组成元素-结点,在C语言中是用结构体来实现的,所以链表和链表操作是结构体应用的重要实例。 本节讨论最简单的链表:单向链表。 单向链表: 头指针 头结点 尾结点 链表结点: 结点是一结构体数据,其成员包括两部分:结点有效数据和结点指针(如图)。结点指针指向下一个结点,由此将所有结点“链”在一起、形成一根数据的“链条”。尾结点的指针为0,即空指针NULL,表示链表的结束。,单向链表的基本操作:建立链表、插入/删除结点、释放结点或整个链表。 例11.4 使用链表建立工人的工资单档案:编号、姓名、工资。并能及时添加记录、删除记录、插入记录、输出工资表。 分析: 首先定义每个记录的结构体类型: struct work long no; char name10; /*有效数据:3项*/ float salary; struct work *next; /*指向下一个结点的指针*/ ;,一、建立单向链表: 功能:输入一个或多个结点数据(工人编号输入0时结束),按输入的先后顺序生成链表。返回链表的头指针。 函数:struct work *create() 结点指针head为头指针,指向第一个结点;指针p1指向新输入的结点,p2指向链表的尾节点。n表示结点的个数。 算法:首先输入一个结点数据,若该数据有效(即编号不等于0),n加1;然后将该结点加入链表:若n等于1,则该结点应是头结点,即head=p1; 否则,连接在尾结点后面:p2-next=p1; 然后p2后移:p2=p1;使得p2始终指向结点。重复以上过程。,申请一个结点空间并输入数据,struct work *input() struct work *q; float x; q=(struct work *)malloc(LEN); if(!q)printf(“n failure.“);exit(0); printf(“n input a workers information(no=0 for end):n“); printf(“ no:“); scanf(“%ld“, /*返回该结点的首地址*/ ,建立链表,返回头指针,struct work *create(void) struct work *head,*p1,*p2; int n=0; p1=p2=input(); head=NULL; while(p1-no!=0) n+; if(n=1) head=p1; else p2-next=p1; p2=p1; p1=input(); /*输入下一个人的信息*/ p2-next=NULL; return(head); ,二、添加结点,功能:在链表的末尾追加多个结点,直至输入的结点编号等于0为止。 函数:struct work *append(struct work *head) 算法:指针p指向链表的尾结点,q指向新输入的结点。 重复执行:若链表为空,则q指向的结点尾头结点;否则,将q链在p之后。,添加结点之链表尾,struct work *append(struct work *head2) struct work *q, *p=head2; q=input(); q-next=NULL; while(q-no!=0) if(head2!=NULL) while(p-next!=NULL) p=p-next; p-next=q; else head2=p=q; q=input();q-next=NULL; return(head2); ,三、输出链表各结点,算法: 指针p指向链表的头结点,然后重复:若p指向的结点不为空,即链表未结束,则输出链表的结点成员;p指向下一个结点。,输出链表各结点,void out_list(struct work *head) struct work *p; printf(“n no name salaryn“); p=head; if(head=NULL) printf(“n no data.“); else while(p!=NULL) printf(“n %4ld %10s %7.2f“,p-no,p-name,p-salary); p=p-next; ,四、按编号删除结点,函数: struct work *delete(struct work *head3, long no) 算法: 先判断链表是否为空, 若是,则结束; 否则,从头结点开始查找要删除的结点。若找到,则删除,即将其从链表中去掉,并释放该结点;否则,若到了链表的为结点仍未找到,则输出“not found”。,按编号删除结点,struct work *delete(struct work *head3,int no) struct work *p,*q=head3; if(head3=NULL) printf(“n list null.“); return(head3); while(no!=q-no ,在第n个结点前插入一个结点,分析: 变量p指向第n个结点,q指向第n-1个结点,即新结点插在p和q指向的结点之间。 分三种情况:1)插在头结点之前。 2)插在中间:t-next=p;q-next=t; 3)链表中无第n个结点。,在第n个结点前插入一个结点,struct work *insert(struct work *head,int n) int i; struct work *p=head,*q,*t; t=input(); if(n=1) t-next=head; head=t;return(head);/*插在表头*/ for(i=1;inext!=NULL) q=p;p=p-next; else break; if(ino!=0) q-next=t;t-next=p; return(head); ,主函数,#include #include #define LEN sizeof(struct work) main() struct work *head; long num; int n1; head=create(); printf(“n append :“); head=append(head); printf(“n insert:“); scanf(“%d“, ,11. 5 共用体,所谓共用体数据类型是指将不同的数据项组织为一个整体,它们在内存中占用首地址相同的一段存储单元。共用体也称为联合。例如: union exam int a; float b; char c; x;,共用体类型说明的一般形式为: union 共用体标识名 类型名1 共用体成员名表1; 类型名2 共用体成员名表2; 类型名n 共用体成员名表n; ; 其中union是关键字,是共用体类型的标志。共用体中的成员可以是简单变量,也可以是数组、指针、结构体和共用体。,11. 5. 2共用体变量的定义及引用,定义共用体变量的方式与结构体变量相似。 1定义类型的同时定义变量。 union data int i;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 高承台桩施工方案
- 浙江网络营销策划方案
- 建筑领域施工方案设计
- 2024-2025学年度教师公开招聘测试卷及答案详解(典优)
- 保安员考试高频难、易错点题附答案详解(典型题)
- 2025年自考专业(人力资源管理)练习题【考试直接用】附答案详解
- 2024安全员考试高频难、易错点题及答案详解(必刷)
- 2025年应聘监控员面试题及答案
- 数据存储及分析解决方案合同
- 2024-2025学年主管护师(中级)真题附参考答案详解(基础题)
- 《节水型高校评价标准》
- GB/T 31771-2024家政服务母婴护理服务质量规范
- 哮喘治疗原理及方法
- 《植物的组织培养》课件
- 临床护理带教老师培训
- 初中体育与健康八年级 第十一章 民族民间体育-三人板鞋 教案
- 大疆80分钟在线测评题
- 财政投资项目评审服务投标方案(技术方案)
- 《新媒体营销》课件-2 直播商品卖点提炼
- 中国冠心病康复循证实践指南(2024版)第一部分
- AQ 1083-2011 煤矿建设安全规范 (正式版)
评论
0/150
提交评论