第9章结构体共用体.doc_第1页
第9章结构体共用体.doc_第2页
第9章结构体共用体.doc_第3页
第9章结构体共用体.doc_第4页
第9章结构体共用体.doc_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

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

文档简介

第11章结构体与共用体 14/14第11章 结构体与共同体11.1 概 述结构体(structure)是一种数据类型,它把互相联系的数据组合成一个整体。例、一个学生的学号、姓名、性别、年龄、成绩、地址,是互相联系的数据,在C语言中用“结构体(structure)”来定义。struct studentintnum; /* 学号 */char name20;/* 姓名 */char sex; /* 性别 */int age; /* 年龄 */floatscore; /* 成绩 */char addr30;/* 地址 */; struct 是关键字,不能省略。student是定义的结构体类型名。结构体中的每一项数据,称为结构体“成员”(member)或“分量”。“结构体”在大多数资料中被称为“结构”。112 结构体类型的定义结构体是一种数据类型(像int、char、flaot是数据类型一样),可以用它定义变量。用结构体类型定义变量的方式有三种:1、先定义结构体类型,再定义变量例、struct student intnum; /* 学号 */char name20;/* 姓名 */char sex; /* 性别 */int age; /* 年龄 */floatscore; /* 成绩 */char addr30;/* 地址 */; struct student student1, student2; 结构体变量中的各成员,在内存中顺序存放。结构体变量所占内存大小用运算符sizeof计算。它是各各成员所占字节数总和。 例、printf( %d %d n,sizeof(struct student), sizeof(student1); 为了方便,可以这样定义结构体变量:#define STUDENT struct studentSTUDENT intnum; char name20;char sex; int age; floatscore; char addr30;; STUDENT student1, student2;2、在定义类型的同时定义变量struct student intnum; /* 学号 */char name20;/* 姓名 */char sex; /* 性别 */int age; /* 年龄 */floatscore; /* 成绩 */char addr30;/* 地址 */student1, student2; 3、直接定义变量struct intnum; /* 学号 */char name20;/* 姓名 */char sex; /* 性别 */int age; /* 年龄 */floatscore; /* 成绩 */char addr30;/* 地址 */student1, student2; 4、成员是另一个结构体变量struct date /*日期结构 */int month; /* 月 */int day;/* 日 */int year; /* 年 */; struct student intnum; /* 学号 */char name20;/* 姓名 */char sex; /* 性别 */int age; /* 年龄 */struct date birthday; /* 成员是另一个结构体变量 */char addr30;/* 地址 */ student1, student2; 11.3 结构体变量的引用1、一般情况下,不能将一个结构体变量作为整体来引用,只能引用其中的成员(分量)。引用结构体成员的方式:结构体变量名.成员名.是“成员运算符”(分量运算符)例1、printf(%d,%s,%c,%d,%f,%s, student1.num, , student1.sex, student1.age, student1.score, sutdent1.addr);例2、student2.score = student1.score;sum = student1.score + student2.score;student1.age+;+student1.age;例3、scanf(%d, &student1.num);2、当成员是另一个结构体变量时,应一级一级地引用成员。例4、student1.num;;student1.birthday.month;student1.birthday.day;student1.birthday.year;3、仅在以下两种情况下,可以把结构体变量作为一个整体来访问。(1) 结构体变量整体赋值,例、student2 = student1;(2)取结构体变量地址,例、printf(%x, &student1); /*输出student1的地址 */11.4 结构体变量的初始化struct student long int num; /* 学号 */char name20;/* 姓名 */char sex; /* 性别 */char addr20;/* 地址 */a = 89031, Li Lin, M, 123 Beijing Road; 注意:不能在结构体内赋初值。例、struct student long int num = 89031;char name20 = Li Lin;char sex = M;char addr30 = 123 Bejing Road;a;11.5 结构体数组1、结构体数组的定义struct studentint num;char name20;char sex;int age;float score;char addr30;struct student stu3; /*3个元素的结构体数组 */2、结构体数组的初始化struct studentint num;char name20;char sex;int age;float score;char addr30; stu3 = 10101,Li Lin, M, 18, 87.5, 103 Bejing Road,10102,Zhang Fun,M, 19, 99, 130 Shanghai Roaad,10104,Wang Min, F, 20, 78.5, 1010 Zhongshan Road ;3、举例例11.1对候选人得票的统计程序。设有三个候选人,每次输入一个得票的候选人的名字,要求最后输出各候选人得票结果。#include stdio.h#include string.hstruct person/*候选人信息结构体 */ char name20; /* 姓名*/int count; /* 得票数 */leader3 = Li, 0, Zhang,0,Fun, 0 ;void main() int i,j;char leader_name20; /*输入得票人姓名 */for(i=1; i=10; i+) /* 设有10个人参加投票 */scanf(%s, leader_name);for (j=0; j3; j+) /* 得票人姓名与3个候选人姓名比较 */if (strcmp(leader_name, ) = 0) stui.count+; printf(n); for(i=0; i引用结构体中的成员。例、p-nump-namep-sexp-score注:也可以这样引用(*p).num,但很少用。2、指向结构体数组的指针struct student stu3;struct student *p = stu; /* 指向stu0 */p+; /* 指向stu1 */p+; /* 指向stu2 */p = &stu;p-num; /* 引用stu0.num */p+;p-num; /* 引用stu1.num */p+;p-num; /* 引用stu2.num */3、用结构指针作函数的参数例11.2有一个结构体变量stu,内含学生学号、姓名和三门课程的成绩。要求在main中赋值,在函数print中打印输出。#include stdio.h#include string.h#define format %dn %sn %fn %fn %fnstruct student int num; /*学号 */char name20; /* 姓名*/float score3; /* 三门课程的成绩 */; void print(struct student *p); /*print函数原型声明 */void main()struct student stu;stu.num = 12345;strcpy(, Li Li); stu.score0 = 67.5;stu.score1 = 89;stu.score2 = 78.6; print(&stu); void print(struct student *p) /*print函数定义 */printf(format, p-num, p-name, p-score0, p-score1, p-score2); printf(n); (1)结构体的成员作函数的参数。与普通变量作函数参数的用法相同。值传送,不能修改实参的值。(2)结构体指针作函数的参数。将结构体的地址传送给函数,效率高,可以修改实参的值。(3)结构体作函数的参数。将结构体的全部成员值传送给函数,效率低,不能修改实参的值。4、举例例11.3 有4个学生,每个学生包括学号、姓名和成绩。要求找出成绩最高者的姓名和成绩。#include stdio.hvoid main() struct student int num; /* 学号 */char name20; /* 姓名*/float score; /* 成绩 */;struct student stu4; /* 4个学生 */struct student *p;int i;int temp = 0; /*成绩最高学生在数组中的序号,03 */ float max; /* 最高成绩 */for(i=0; i4; i+) /* 输入4个学生的学号、姓名、成绩 */scanf(%d %s %f, &stui.num, , &stui.score); for(max=stu0.score, i=1; i max)max = stui.score;temp = i; p = stu + temp; /* p指向成绩最高的学生结构 */printf(nThe maximum score:n);printf(No.: %dn name: %sn score: %4.1fn,p-num, p-name, p-score); 动态存储分配函数malloc和free11.7 用结构体指针处理链表一、链表概述链表是一种最常见的数据结构,它动态地进行存储分配。数组:必须事先定义固定的长度(元素个数),不能适应数据动态地增减的情况。当数据增加时,可能超出原先定义的元素个数;当数据减少时,造成内存浪费。链表动态地进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。(数组中插入、删除数据项时,需要移动其它数据项)。链表有单向链表、双向链表、环形链表等形式。以单向链表为例、链表有一个“头指针”head,它指向链表的第一个元素。链表的一个元素称为一个“结点”(node)。结点中包含两部分内容,第一部分是结点数据本身,如图中的、所示。结点的第二部分是一个指针,它指向下一个结点。最后一个结点称为“表尾”,表尾结点的指针为空(NULL)。在链表中插入一个结点,比如,在结点后插入结点P,只需使指向,使指向。在链表中删除一个结点,比如删除结点C,只需使指向,并删除结点C所占内存。因此,用链表作插入、删除操作非常方便。链表结点数据可以用结构体来描述,例如、struct studentint num;float score;struct student *next; /* 指向下一结点 */ ;链表需要动态地进行存储分配,在语言中,使用以下函数进行动态存储分配和释放。1、void * malloc(size_t size)在动态存储区分配长度为size的连续空间,并返回指向该空间起始地址的指针。若分配失败(系统不能提供所需内存),则返回NULL。2、void * calloc(size_t n, size_t size)在动态存储区分配n个长度为size的连续空间,并返回指向该空间起始地址的指针。若分配失败(系统不能提供所需内存),则返回NULL。3、void free(void * ptr)释放ptr指向的内存空间。ptr是malloc()或calloc()函数返回的值。注意、()上述函数的原型在alloc.h和stdlib.h中定义。在程序中必须包含这两个头文件。()size_t是专用于描述内存大小和计数值的数据类型, 等于unsigned int。二、建立链表例11.4写一个函数creat(),建立一个有5个学生的单向链表。分析建立过程:设:链表结构为:struct studentlongnum;float score;struct student *next;当输入的num等于零时,表示建立过程结束。定义以下变量:struct student *head; /* 表头 */struct student *p1; /* 新建结点 */struct student *p2; /* 表尾结点 */通过以上分析,可以得到创建链表的算法。程序:#include stdio.h#include alloc.h#include stdlib.hstruct studentlongnum;float score;struct student *next;#define LEN sizeof(struct student)/* 注意,#define NULL 0不需要,因为,NULL已在stdio.h中定义 */int n;struct student * creat() /* 创建链表,并返回表头指针 */struct student *head; /* 表头 */struct student *p1; /* 新建结点 */struct student *p2; /* 表尾结点 */n = 0; /* 结点数为0 */head = NULL; /* 还没有任何结点,表头为指向空 */p1 = (struct student *)malloc(LEN); /* 创建一个新结点p1 */p2 = p1; /* 表尾p2也指向p1 */ scanf(%ld,%f, &p1-num, &p1-score); /* 读入第一个结点的学生数据 */while(p1-num != 0) /* 假设num=0表示输入结束 */n = n + 1;if (n = 1) head = p1; /* 第一个新建结点是表头 */elsep2-next = p1; /* 原表尾的下一个结点是新建结点 */p2 = p1; /* 新建结点成为表尾 */p1 = (struct student *)malloc(LEN); /* 新建一个结点 */scanf(%ld,%f, &p1-num, &p1-score); /* 读入新建结点的学生数据 */ free(p1); /* 对于num=0的结点,未加入链表,应删除其空间 */p2-next = NULL; /* 输入结束,表尾结点的下一个结点为空 */return (head);/* 返回表头指针 */ 三、输出链表只要已知表头结点,通过p-next可以找到下一个结点,从而可以输出链表的全部结点数据。void print(struct student *head)struct student *p;printf(nNow, These %d records are:n, n); p = head;if (p = NULL) return;do printf(%ld %5.1fn, p-num, p-score); p = p-next;while(p != NULL); 四、删除一个结点删除一个结点的算法: 应考虑以下情况:、找到需要删除的结点,用p1指向它。并用p2指向p1的前一个结点。、要删除的结点是头结点。、要删除的结点不是头结点根据以上情况分析,得到删除一个结点的算法:程序:在链表head中删除学号为num的结点。以表头指针head和需要删除的结点的num(学号)为参数,返回删除操作后的链表表头。struct student * del(struct student *head, long num)struct student *p1; /* 指向要删除的结点 */struct student *p2; /* 指向p1的前一个结点 */ if (head = NULL) /* 空表 */ printf(n List is NULLn);return (head); p1 = head;while(num != p1-num & p1-next != NULL) /* 查找要删除的结点 */p2 = p1;p1 = p1-next;if (num = p1-num) /* 找到了 */if (p1 = head) /* 要删除的是头结点 */head = p1-next;else/* 要删除的不是头结点 */p2-next = p1-next;free(p1); /* 释放被删除结点所占的内存空间 */* 教材p235称:删除一个结点,并不是真正从内存把它抹掉 ? */printf(delete: %ldn, num);n = n - 1; else /* 在表中未找到要删除的结点 */printf(%ld not foundn);return (head); /* 返回新的表头 */ 五、对链表的插入操作设在链表中,各结点按成员num(学号)由小到大顺序存放,把结点p0插入链表。用指针p0指向待插入结点,设把p0插在p1结点之前,插入算法:1、在p1之前、p2之后插入p02、将p0插入第一个结点之前3、将p0插入表尾结点之后4、找到应插入的位置应插入的位置:p1之前、p2之后。在链表中,各结点按成员num(学号)由小到大顺序存放,从第一个结点开始,把待插入结点p0-num与每一个结点p1-num比较,若(p0-num) (p1-num),则p1移到下一个结点。同时,p2也移到下一个位置。根据以上分析,得出插入算法:程序:在链表head中,插入stud结点,并返回新链表的表头。struct student * insert(struct student *head, struct student *stud) struct student *p0; /* 待插入结点 */struct student *p1; /* p0插入p1之前、p2之后 */struct student *p2; p1 = head;p0 = stud;if(head = NULL) /* 原链表是空表 */head = p0;p0-next = NULL;elsewhile (p0-num p1-num) & (p1-next != NULL) /*查找待插入位置 */ p2 = p1;p1 = p1-next; if(p0-num num) /* num从小到大排列,p0应插入表内(不是表尾) */ if (p1 = head) /* p1是表头结点 */ head = p0;p0-next = p1; else p2-next = p0;p0-next = p1; else /* p0插入表尾结点之后 */p1-next = p0;p0-next = NULL; n = n + 1; /* 结点数加1 */return (head); 六、主程序主程序(一)(有错)void main()struct student * head;struct student stu;long del_num;printf(input records:n); head = creat(); /* 建立链表,并返回表头 */print(head);/* 输出链表 */printf(nInput the deleted number:);scanf(%ld, &del_num);head = del(head, del_num); /* 从链表中删除del_num结点 */print(head); /* 输出链表 */printf(nInput the inserted record:);scanf(%ld,%f, &stu.num, &stu.score);head = insert(head, &stu); /* 在链表中插入一个结点stu */print(head);/* 输出链表 */ 该程序插入多个结点时要出错。因为,使用一个普通变量stu不能代表多个结点。正确的做法是:每一个插入的结点都应有自己的内存空间,因此,应在插入时为需要插入的结点分配内存。主程序(二)(正确的程序)void main()struct student * head;struct student * stu;long del_num;printf(input records:n); head = creat(); /* 建立链表,并返回表头 */print(head);/* 输出链表 */printf(nInput the deleted number:);scanf(%ld, &del_num);while(del_num != 0) head = del(head, del_num); /* 从链表中删除del_num结点 */print(head); /* 输出链表 */printf(nInput the deleted number:);scanf(%ld, &del_num); printf(nInput the inserted record:);stu = (struct student *)malloc(LEN);scanf(%ld,%f, &stu-num, &stu-score);while(stu-num != 0) head = insert(head, stu); /* 在链表中插入一个结点stu */print(head);/* 输出链表 */ printf(nInput the inserted record:);stu = (struct student *)malloc(LEN);scanf(%ld,%f, &stu-num, &stu-score); free(stu); /*对于num=0的结点,未插入,应删除其空间 */ 118 联合(共用体)一、共用体的概念当需要把不同类型的变量存放到同一段内存单元,或对同一段内存单元的数据按不同类型处理,则需要使用“共用体”数据结构。例、把一个整型变量、一个字符型变量、一个实型变量放在同一个地址开始的内存单元中。共用体的定义形式:union 共用体名成员列表; 变量列表;例、 union dataint i;char ch;float f; 注意区分:“共用体”:各成员占相同的起始地址,所占内存长度等于最长的成员所占内存。“结构体”:各成员占不同的地址,所占内存长度等于全部成员所占内存之和。二、共用体变量的引用只能引用共用体变量的成员,如、union data a;a.i;a.ch;a.f; 三、共用体类型数据的特点、共用体变量中的值是最后一次存放的成员的值,如、a.i = 1;a.ch = a;a.f = 1.5;完成以上三个赋值语句后,共用体变量的值是1.5,而a.i=1和a.ch=a已无意义。、共用体变量不能初始化,例、union dataint i;char ch;float f;a=1,a, 1.5; 例11.12 设有若干个人员的数据,其中有学生和教师。学生数据包括:姓名、号码、性别、职业、班级。教师数据包括:姓名、号码、性别、职业、职务。如上图、要求输入人员数据,然后输出。分析:学生数据的class(班级)和教师数据的position(职务)类型不同,但在同一表格中,使用“共用体”数据结构。struct int num;char name10;char sex;char job;unionint class; /* 班级 */char position10; /* 职务 */category;person2; /* 2个人员数据 */void main()int i;for(i=0;i2;i+) /* 输入2个人员的数据 */scanf(%d %s %c %c, &personi.num, &, &personi.sex, &personi.job); if(personi.job = S) /*学生 */scanf(%d, &personi.category.class); /* 输入班级 */else if(personi.job = T) /* 教师 */scanf(%s, personi.category.position); /* 输入职务 */else printf(Input error!); printf(n);printf(No. name sex job class/positionn); for(i=0;i sun).4、整型与枚举类型是不同的数据类型,不能直接赋值,如、workday = 2; /* workday是枚举类型 */但可以通过强制类型转换赋值,如、workday = (enum weekday)2;例11.13口袋里有红、黄、蓝、白、黑五种颜色的球若干个。每次从口袋中取出三个球,打印出三种不同颜色球的可能取法。分析:球的颜色只可能取五种值,用枚举类型变量处理。#include stdio.hvoid main()enum color red, yellow, blue, white, black; /*枚举类型 */enum color i,j,k,pri;int n,loop;n = 0; /* 不同颜色的组合序号 */for(i=red; i=black; i+) for(j=red; j=black; j+) if (i != j)for(k=red; k=black; k+) if (k != i) & (k != j)n = n + 1;printf(%-4d,n); /* 组合序号 */for(loop = 1;loop=3; loop+) /* 循环输出三个球的颜色 */switch(loop)case 1: pri = i; break; /* 第1个球 */case 2: pri = j; break; /* 第2个球 */case 3: pri = k; break; /* 第3个球 */ defa

温馨提示

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

评论

0/150

提交评论