




已阅读5页,还剩76页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
结构体与共用体,课程:程序设计语言 教材:谭浩强C程序设计第三版 教师:陈小荷,本章重点,结构体的各分量是顺序存放的,共用体的各分量是重叠存放的。共用体的使用有一些特殊限制。 可以定义结构体(或共用体)数组。 可以定义指向结构体(或共用体)变量或数组元素的指针。 成员运算符(.),指向成员运算符(-)。 枚举类型是一种受限的整数类型。 可以用typedef语句给已有的数据类型一个别名。,C语言的数据类型,整型 字符型 枚举类型(受限整型) 单精度型 双精度型 数组类型 结构体类型 共用体类型 指针类型 空类型,浮点型,基本类型,构造类型,数据类型,枚举类型,有时变量的取值是有限的、可枚举的几个整数,为了清楚地表示这些整数的意义,同时也为了防止变量取非法值,可将这些变量定义为枚举类型,而这些可枚举的整数叫做枚举常量。 例如,一个星期有七天,这七天的名字可以表示为枚举常量。 又如,分数可划分为优秀、良好、及格和不及格四个等级,这是四个枚举常量。词频可划分为高频、中频、低频三个等级,这是三个枚举常量。,枚举类型的声明,格式:enum 枚举标记 枚举常量列表; enum Days Sun,Mon,Tue,Wed,Thu,Fri,Sat ; enum Score excellent, good, pass, fail ; enum Frequency high-freq, mid_freq, low_freq ; 枚举常量都是表示整型常量的标识符,上述三个枚举类型中的枚举常量分别是06, 03, 02. 若无特别指定,枚举常量值总是从0开始,并且依次增1. 注意:“enum 枚举标记”合起来才是枚举类型名。,枚举类型的声明,可以在枚举常量列表中用“=”来特别指明枚举常量值,例如: enum Days Mon=1, Tue, Wed, Thu, Fri, Sat, Sun ; enum Days Sun=7, Mon=1, Tue, Wed, Thu, Fri, Sat ; 不要求每个枚举常量是唯一的值,例如可以声明为: enum Days Sat, Sun=0, Mon, Tue, Wed, Thu, Fri, Sat ;,枚举变量的定义,方式之一:枚举类型名 变量名; enum Days today, yestoday; 方式之二:在声明类型的同时定义变量 enum Score excellent, good, pass, fail score; 方式之三:直接定义枚举变量 enum excellent, good, pass, fail your_score;,枚举变量的赋值和初始化,枚举变量只能赋值或初始化为枚举常量: enum Days today=Thu; enum Score score; score=excellent; enum Frequency freq; freq=high-freq; 或者将整形表达式强制转换为枚举类型后赋给枚举变量: today=(enum Days) (6-2);,枚举类型的输入和输出,无法直接输入枚举变量的值,只能先输入整数,然后强制转换为枚举类型。 无法直接输出枚举变量的值,但可用switch语句来输出: switch(this_day) case Sun: printf(“这天是星期日n“); break; case Mon: printf(“这天是星期一n“); break; case Tue: printf(“这天是星期二n“); break; case Wed: printf(“这天是星期三n“); break; case Thu: printf(“这天是星期四n“); break; case Fri: printf(“这天是星期五n“); break; case Sat: printf(“这天是星期六n“); break; ,补充例题:求某日期是星期几,已知该年元旦是星期几,并且已定义函数int order_of_year(int y, int m, int d); 求某日期是星期几: enum Days this_day; int order=order_of_year(y, m, d); this_day=(enum Days) (weekday+order-1)%7); 用switch语句输出枚举变量this_day。,typedef语句,typedef 语句的作用是将已有的类型名定义为另一个类型名(别名)。例如: typedef int Count; typedef enum Days Days; typedef char *String; typedef int Array100 ; typedef int(*PF) (int,int);,允许新的类型名与原有类型名中的一个标记相同。 然后就可以用新的类型名来定义变量: Count i; Days this_day; String p; Array a; PF pf;,typedef 的定义方式,按变量定义方式写出定义语句,例如: int i; int array10; 将变量名替换为新类型名,例如: int Count; int Array10; 在前面加上 typedef,例如: typedef int Count; typedef int Array10; 然后可用新类型名来定义变量,例如: Count i; Array a, b, c;,结构体类型的声明,格式:struct 结构体标记 成员列表; 成员又叫分量,各成员的数据类型可以不同。(如果要求相同,那就应该用数组。) 简单例子:表示词条的结构体 struct Item char word12; int freq; ; 类型名 分量1 分量2 注意分号的用法。,结构体类型的声明,表示学生信息的结构体: struct Student int num; / 学号 char name20; / 姓名 char sex; / 性别 int age; / 年龄 float score; / 分数 char addr30; / 住址 ;,结构体类型的声明,可以把相同类型的成员写在一起: struct Student int num, age; char name20, sex, addr30; float score; ; 不管写法如何,struct Student的理论宽度都是4+4+20+1+30+4=63字节 但是,结构体变量中各成员是根据类型声明中的顺序来依次存储的。,结构体变量的定义,方式之一:结构体类型名 变量名; struct Item w; struct Student st1, st2; Student st3; 方式之二:在声明类型的同时定义变量 struct Item char word12; int freq; w; 方式之三:直接定义结构体变量 struct char word12; int freq; w;,结构体类型的嵌套,struct Date int year, month, day; ; struct Student int num; char name20, sex, addr30; float score; struct Date birthday; ;,用typedef定义结构体类型名,typedef struct int year, month, day; Date; typedef struct int num; char name20, sex, addr30; float score; Date birthday; Student; Student st1, st2;,这时定义结构体变量就不要写struct了。,成员运算符,C语言没有提供对结构体变量进行整体操作的方法,但提供了访问其成员的方法: 结构体变量名.成员名 例如:,st2.birthday 其中的圆点叫做成员运算符,优先级为1,自左至右结合。 对于嵌套的结构体类型,可用多个圆点来表示其中最基层的成员: 例如:st2.birthday.year,结构体变量的初始化,格式:结构体变量名=初始化列表; 常量形式要跟声明中的成员类型和顺序一致。例如: st1=10101, “李明”, M, “宁海路122号”, 85, 1986,7,10; 打印其中前3项数据: printf(“学号:%d,姓名:%s,性别: %cn”, st1.num, , st1.sex);,结构体数组的定义,与结构体变量的定义方式类似,也有三种方式,只需指明是数组即可。例如: struct Item ws3; struct Item char word12; int freq; ws3; struct char word12; int freq; ws3; Student students10;,结构体数组的初始化,一般方式是初始化列表中每个元素用花括号括起来,此时元素中可以只初始化某些成员,例如下面中间元素缺词频数据: struct Item ws3 =“man”,3,”good”,“cook”,5; 内层的花括号也可以省略,但这个时候必须对元素的每个成员都初始化,例如: struct Item ws3=“man”,3,”good”,2,“cook”,5;,结构体数组应用举例,struct person char name20; int count; leaders3=“Li”,0, “Zhang”,0, ”Feng”,0; void main( ) int i, j; char name20; for(i=1;i=10;i+) scanf(“%s”,name); for(j=0;j3;j+) if(!strcmp(name, ) leadersj.count+; for(j=0;j3;j+) print_vote(leadersj); / 打印选票,待实现,此name非彼name,指向结构体变量的指针,格式:struct 结构体名 * 指针名; struct Item w=“friend”, 7; struct Item *p; 上例可合并为: struct Item w=“friend”, 7, *p;,指向成员运算符,可用指向结构体变量的指针来访问其成员,这时要用到”指向成员运算符“,例如: struct Item w=“friend”, 7, *p= / 此时等价于: w.word, w.freq 指向成员运算符与成员运算符的优先级都是1,都是自左至右结合。,成员运算符与指向成员运算符,struct Date int year, month, day; ; struct Student int num; float score; char name20, sex, addr30; struct Date birthday; st, *p= 此时若通过指针p来访问 st.birthday.year,应如何表达?,指向结构体数组元素的指针,struct person char name20; int count; leaders3=“Li”,0, “Zhang”,0, ”Feng”,0; void main( ) int i; char name20; struct person *p; for(i=1;iname) p-count+; for(j=0;j3;j+) print_vote(leadersj); ,选票统计程序 的指针版本,用结构体变量做函数参数,main中的函数调用: for(j=0;j3;j+) print_vote(leadersj); print_vote函数的实现: void print_vote(struct person x) printf(“%s: %dn”, , x.count); ,用结构体指针做函数参数,print_vote函数的另一个版本: void print_vote(struct person *p) printf(“%s: %dn”,p-name,p-count); 用指针做参数,传递的数据仅有4字节。 main函数中应该怎样调用这个版本的print_vote呢?,简单链表,A - 1356,B - 1475,C - 1021,D - NULL,1249,1249,1356,1475,1021,head,每个结点都有数据域和指针域。 A, B, C, D是要存储的数据,1249等是指向下一 结点的指针,是为了访问链表所加的成员。 各元素的地址可以是不连续的,这与数组不同。 术语:头指针、首元结点、尾元结点,用结构体表示链表结点,typedef struct Student int num; float score; struct Student *next; Student;,A - 1356,B - 1475,C - 1021,D - NULL,1249,1249,1356,1475,1021,head,Student *head=NULL; head是一个指针,起初无所指,以后用它分配首元结点。首元结点的next又可用来分配次元结点,,内存的动态分配和释放,动态分配可用malloc或calloc函数,例如: char *p1=(char *)malloc(1024); Student *p2=(Student*)malloc(sizeof(Student); long *p3=(long *)calloc(3, sizeof(long); Student *p4=(Student*)calloc(4,sizeof(Student); 内存释放用free函数,例如:free(p); 调用这三个函数需包含stdlib.h,建立动态链表,NULL,head,NULL,p,NULL,tail,Student *head=NULL, *tail=NULL, *p=NULL;,建立动态链表,NULL,head,1249,p,NULL,tail,1 80.5 - NULL,p=(Student*)malloc(sizeof(Student); p-num=num; p-score=score; p-next=NULL;,建立动态链表,1249,head,1249,p,1249,tail,1 80.5 - NULL,if(!head) head=tail=p;,建立动态链表,1249,head,1249,tail,1356,p,1 80.5 - NULL,2 75.2 - NULL,p=(Student*) malloc(sizeof(Student); p-num=num; p-score=score; p-next=NULL;,建立动态链表,1249,head,1356,tail,1356,p,1 80.5 - 1356,2 75.2 - NULL,if(!head) head=tail=p; else tail-next=p; tail=tail-next; ,建立动态链表,1249,head,1356,tail,1475,p,1 80.5 - 1356,2 75.2 - NULL,3 91.45 - NULL,p=(Student*) malloc(sizeof(Student); p-num=num; p-score=score; p-next=NULL;,建立动态链表,1249,head,1475,tail,1475,p,1 80.5 - 1356,2 75.2 - 1475,3 91.45 - NULL,if(!head) head=tail=p; else tail-next=p; tail=tail-next; ,建立动态链表,1249,head,1475,tail,1021,p,1 80.5 - 1356,2 75.2 - 1475,3 91.45 - NULL,p=(Student*) malloc(sizeof(Student); p-num=num; p-score=score; p-next=NULL;,4 63.8 - NULL,建立动态链表,1249,head,1021,tail,1021,p,1 80.5 - 1356,2 75.2 - 1475,3 91.45 - 1021,4 63.8 - NULL,if(!head) head=tail=p; else tail-next=p; tail=tail-next; ,建立动态链表,Student *create( ) Student *head=NULL, *tail=NULL, *p=NULL; int num; float score; for(;) scanf(“%d%f“, ,建立动态链表的步骤,因为新结点总是附加在链表尾部,所以设一指针tail指向尾元。设head是指向链表首元的指针,学号为x,成绩为s,说出以下各个步骤所对应的C语句: 用指针p分配一个结点; 对结点中各个成员赋值; 将p链接到链表尾部,注意当链表为空的特殊情况。 有n项数据时,以上步骤重复n次。,输出动态链表,1249,head,1 80.5 - 1356,2 75.2 - 1475,3 91.45 - 1021,4 63.8 - NULL,while(head!=NULL) printf(); head=head-next; ,输出动态链表,1356,head,1 80.5 - 1356,2 75.2 - 1475,3 91.45 - 1021,4 63.8 - NULL,while(head!=NULL) printf(); head=head-next; ,输出动态链表,1475,head,1 80.5 - 1356,2 75.2 - 1475,3 91.45 - 1021,4 63.8 - NULL,while(head!=NULL) printf(); head=head-next; ,输出动态链表,1021,head,1 80.5 - 1356,2 75.2 - 1475,3 91.45 - 1021,4 63.8 - NULL,while(head!=NULL) printf(); head=head-next; ,输出动态链表,NULL,head,1 80.5 - 1356,2 75.2 - 1475,3 91.45 - 1021,4 63.8 - NULL,while(head!=NULL) printf(); head=head-next; ,链表的输出,void print(Student *head) while(head!=NULL) printf(“%d %5.1fn“, head-num, head-score); head=head-next; ,这个head只是形参,它的移动不会导致实参的改变。,输出链表的步骤,设head是指向链表首元的指针,且head的值不容改变,说出以下各个步骤所对应的C语句: 用指针p指向链表的首元; 当p不是空指针时 输出p所指结点中的各项数据; p指向下一个结点。,删除链表中一个结点(学号为2),1249,head,1249,q,NULL,p,1 80.5 - 1356,2 75.2 - 1475,3 91.45 - 1021,4 63.8 - NULL,for(q=head; q!=NULL; p=q, q=q-next) if(q-num=num) break;,删除链表中一个结点(学号为2),1249,head,1356,q,1249,p,1 80.5 - 1356,2 75.2 - 1475,3 91.45 - 1021,4 63.8 - NULL,for(q=head; q!=NULL; p=q, q=q-next) if(q-num=num) break;,删除链表中一个结点(学号为2),1249,head,1356,q,1249,p,1 80.5 - 1475,2 75.2 - 1475,3 91.45 - 1021,4 63.8 - NULL,if(p=NULL) head=q-next; else p-next=q-next;,删除链表中一个结点(学号为2),1249,head,1249,p,1 80.5 - 1475,3 91.45 - 1021,4 63.8 - NULL,free(q); return head; / 这个head没变,删除链表中一个结点(学号为1),1249,head,1 80.5 - 1475,3 91.45 - 1021,4 63.8 - NULL,1249,q,NULL,p,for(q=head; q!=NULL; p=q, q=q-next) if(q-num=num) break;,删除链表中一个结点(学号为1),1249,head,1 80.5 - 1475,3 91.45 - 1021,4 63.8 - NULL,1249,q,NULL,p,for(q=head; q!=NULL; p=q, q=q-next) if(q-num=num) break;,删除链表中一个结点(学号为1),1021,head,1 80.5 - 1475,3 91.45 - 1021,4 63.8 - NULL,1249,q,NULL,p,if(p=NULL) head=q-next; else p-next=q-next;,删除链表中一个结点(学号为1),1021,head,3 91.45 - 1021,4 63.8 - NULL,NULL,p,free(q); return head; /这个head变了,从链表中删除一个结点,Student *del(Student *head, int num) Student *p=NULL, *q=NULL; for(q=head; q!=NULL; p=q, q=q-next) if(q-num=num) break; if(!q) return head; if(p=NULL) head=q-next; else p-next=q-next; free(q); return head; ,删除结点的步骤,用指针p和q指向链表中逻辑上相邻的两个结点(*p是* q的直接前驱)。设head是指向链表首元的指针,x是要删除的结点中的学号,当q所指的学号恰为x时,说出以下步骤所对应的C语句: 将*p与*q的下一结点链接起来; 释放*q。,向链表中插入一个结点,head领头的链表是按学号升序排列,插入结点时应保持有序性。 共有四种情况: 该学号已有,不必插入(如有必要,第一种情况的处理办法可改为:不插入结点,但修改其分数); 插在开头,此时需修改head; 插在中间,这是典型情况; 插在尾部,这是遇到学号最大的情况。,向有序链表插入一个结点(学号为4),1249,head,NULL,q,NULL,p,2 80.5 - 1021,4 75.2 - NULL,7 63.8 - NULL,Student *p=NULL, *q=NULL;,ins,1356,向有序链表插入一个结点(学号为4),1249,head,1249,q,2 80.5 - 1021,4 75.2 - NULL,7 63.8 - NULL,for(q=head; q!=NULL; p=q, q=q-next) ,NULL,p,ins,1356,向有序链表插入一个结点(学号为4),1249,head,1021,q,2 80.5 - 1021,4 75.2 - NULL,7 63.8 - NULL,for(q=head; q!=NULL; p=q, q=q-next) ,1249,p,ins,1356,向有序链表插入一个结点(学号为4),1249,head,1021,q,2 80.5 - 1021,4 75.2 - NULL,7 63.8 - NULL,for(q=head; q!=NULL; p=q, q=q-next) if(ins-numnum) break; ,1249,p,ins,1356,向有序链表插入一个结点(学号为4),1249,head,1021,q,2 80.5 - 1356,4 75.2 - 1021,7 63.8 - NULL,1249,p,ins,1356,ins-next=q; if(p=NULL) head=ins; else p-next=ins;,向有序链表插入一个结点(学号为1),1249,head,NULL,q,2 80.5 - 1356,4 75.2 - 1021,7 63.8 - NULL,NULL,p,ins,1475,Student *p=NULL, *q=NULL;,1 75.5 - NULL,向有序链表插入一个结点(学号为1),1249,head,1249,q,2 80.5 - 1356,4 75.2 - 1021,7 63.8 - NULL,NULL,p,ins,1475,1 75.5 - NULL,for(q=head; q!=NULL; p=q, q=q-next) ,向有序链表插入一个结点(学号为1),1249,head,1249,q,2 80.5 - 1356,4 75.2 - 1021,7 63.8 - NULL,NULL,p,ins,1475,1 75.5 - NULL,for(q=head; q!=NULL; p=q, q=q-next) if(ins-numnum) break; ,向有序链表插入一个结点(学号为1),1475,head,1249,q,2 80.5 - 1356,4 75.2 - 1021,7 63.8 - NULL,NULL,p,ins,1475,1 75.5 - 1249,ins-next=q; if(p=NULL) head=ins; else p-next=ins;,向有序链表插入一个结点(学号为1),1475,head,2 80.5 - 1356,4 75.2 - 1021,7 63.8 - NULL,1 75.5 - 1249,向链表中插入一个结点,Student *insert(Student *head, Student *ins) Student *p=NULL, *q=NULL; for(q=head; q!=NULL; p=q, q=q-next) if(ins-num = q-num) free(ins); return head; if(ins-num num) break; if(p=NULL) head=ins; else p-next=ins; ins-next=q; return head; ,插入结点的步骤,用
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 宿迁市中石化2025秋招笔试模拟题含答案油品分析质检岗
- 中国移动成都市2025秋招企业文化50题速记
- 开封市中石油2025秋招面试半结构化模拟题及答案炼油设备技术岗
- 白银市中石化2025秋招面试半结构化模拟题及答案油田勘探开发岗
- 儋州市中储粮2025秋招笔试粮食政策与企业文化50题速记
- 国家能源怀化市2025秋招采矿工程类面试追问及参考回答
- 国家能源深圳市2025秋招笔试题库含答案
- 鹰潭市中石油2025秋招笔试模拟题含答案市场营销与国际贸易岗
- 山南市中储粮2025秋招购销统计岗高频笔试题库含答案
- 黑河市中石油2025秋招笔试模拟题含答案安全环保与HSE岗
- 农产品电商知识培训课件
- 认识数字123幼儿园课件
- 2024海湾消防智慧消防物联网系统用户手册
- 诗经王风黍离课件
- 2025年湖北恩施州鹤峰县国有资本投资运营有限公司招聘笔试参考题库附带答案详解
- 应知应会设备安全操作培训
- 智能监控系统技术方案
- 《企业安全生产费用提取和使用管理办法》专题培训
- 德育故事分享
- 2023-2024学年天津九十二中七年级(上)第一次段考语文试卷
- 实验室人员准入制度范文(2篇)
评论
0/150
提交评论