《结构体与共同体》PPT课件.ppt_第1页
《结构体与共同体》PPT课件.ppt_第2页
《结构体与共同体》PPT课件.ppt_第3页
《结构体与共同体》PPT课件.ppt_第4页
《结构体与共同体》PPT课件.ppt_第5页
已阅读5页,还剩32页未读 继续免费阅读

下载本文档

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

文档简介

第11章 结构体与共同体,11.1 概述 迄今为止,已介绍了基本类型的变量(如整型、实型、字符型变量等),也介绍了一种构造类型数据数组,数组中的各元素是属于同一个类型的。但是只有这些数据类型是不够的。有时需要将不同类型的数据组合成一个有机的整体,以便于引用。这些组合在一个整体中的数据是互相联系的。 例如,一个学生的学号、姓名、性别、年龄、成绩、家庭地址等项。这些项都与某一学生相联系。,11.1 概述,对于上述的数据,应当把它们组织成一个组合项,在一个组合项中包含若干个类型不同的数据项。C语言允许用户自己指定这样一种数据结构,它称为结构体。 由于C语言没有提供这种现成的数据类型,因此用户必须要在程序中建立所需的结构体类型。例如: struct student /* 定义了一个名为student的结构体 */ int num; char name20; char sex; 规定了数据项的个数以及各数据项 int age; 的数据类型 float score; char addr30; ; 注:以上是定义了一个结构体类型,还没有定义变量,系统不分配内存。,关于定义结构体的说明:,(1) 声明一个结构体类型的一般形式为: struct 结构体名 成员表列; “结构体名” 用作结构体类型的标志,它又称“结构体标记”。 (2) 大括弧内是该结构体中的各个成员,由它们组成一个结构体。对各成员都应进行类型声明,即: 类型名 成员名; (3) 也可以把“成员表列”称为“域表”。每一个成员也称为结构体中的一个域。成员名命名规则与变量名同。,11.2 定义结构体类型变量的方法,前面只是指定了一个结构体类型,它相当于一个模型,但其中并无具体数据,系统也不分配实际内存单元。为了能在程序中使用结构体类型的数据,应当定义结构体类型的变量,并在其中存放具体的数据。可以采取以下三种方法定义结构体类型变量。 1. 先声明结构体类型再定义变量名 对于已定义了一个结构体类型struct student,可以用它来定义变量。如: struct student student1, student2 结构体类型名 结构体变量名 上面语句定义了student1和student2为struct student类型的变量,即它们具有struct student类型的结构。,11.2 定义结构体类型变量的方法,结构体变量存放数据形式如图所示: student1 student2 在定义了结构体变量后,系统会为之分配内存单元。例如student1和student2在内存中各占59个字节(2+20+1+2+4+30=59)。 应当注意,将一个变量定义为标准类型(基本数据类型)与定义为结构体类型不同之处在于后者不仅要求指定变量为结构体类型,而且要求指定为某一特定的结构体类型(例如struct student类型)。因为可以定义出许许多多种具体的结构体类型。而在定义变量为整型时,只需指定为int型即可。,11.2 定义结构体类型变量的方法,2. 在声明类型的同时定义变量 例如: struct student int num; char name20; char sex; int age; float score; char addr30; student1,student2; 它的作用与第一种方法相同,即定义了两个struct student类型的变量student1、student2。,11.2 定义结构体类型变量的方法,这种形式的定义的一般形式为: struct 结构体名 成员表列 变量名表列; 3. 直接定义结构类型变量 其一般形式为: struct 成员表列 变量名表列; /* 即不出现结构体名 */,关于结构体类型的说明:,(1) 类型与变量是不同的概念,不要混同。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。 (2) 对结构体中的成员(即“域”),可以单独使用,它的作用与地位相当于普通变量。 (3) 成员也可以是一个结构体变量。(见例题) (4) 成员名可以与程序中的变量名相同,二者不代表同一对象。例如,程序中可以另定义一个变量num,它与struct student中的num是两回事,互不干扰。,成员也可以是一个结构体变量。例如:,struct date /*声明一个结构体类型*/ int month; int day; int year; ; struct student int num; char name20; char sex; int age; struct date birthday; /*birthday是struct date类型*/ char addr30; student1,student2; 先声明一个struct date类型,它代表“日期”,包括3个成员:month(月)、day(日)、year(年)。然后在声明struct student类型时,将成员birthday指定为struct date类型。,11.3 结构体变量的引用,在定义了结构体变量以后,当然可以引用这个变量。但应遵守以下规则: (1) 不能将一个结构体变量作为一个整体进行输入和输出。例如: printf (“%d,%s,%c,%d,%f,%sn“,student1); 只能对结构体变量中的各个成员分别进行输入和输出。引用结构体变量中成员的方式为: 结构体变量名.成员名 例如: student1.num=10010; (2) 如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低的一级的成员。 例如:student1.birthday.month=5;,11.3 结构体变量的引用,(3) 对结构体变量的成员可以像普通变量一样进行各种运算。例如: student2.score=student1.score; sum=student1.score+student2.score; student1.age+; +student1.age; (4) 可以引用结构体变量成员的地址,也可以引用结构体变量的地址。例如: scanf(“%d”, /* 输入student1.num的值 */ printf(“%o”,&student1); /* 输出student1的首地址 */ 但不能用以下语句整体读入结构体变量,如: scanf(“%d,%s,%c,%d,%f,%s”,&student1); 结构体变量的地址主要用于作函数参数,传递结构体的地址。,11.4 结构体变量的初始化,和其他类型变量一样,对结构体变量可以在定义时指定初始值。 例11.1 对结构体变量初始化。 #include void main() struct student long int num; char name20; char sex; char addr20; a=89031,“Li Lin”,M,“123 Beijing Road”; printf(“NO.:%ldnname:%snsex:%cnaddress:%sn”,a.num, ,a.sex,a.addr); 运行结果如下: No.:89031 name:Li Lin sex:M address:123 Beijing Road,11.5 结构体数组,一个结构体变量中可以存放一组数据(如一个学生的学号、姓名、成绩等数据)。如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。 11.5.1 定义结构体数组 和定义结构体变量的方法相仿,只需说明其为数组即可。如: struct student int num; char name20; char sex; int age; float score; char addr30; ; /* 也可表示为: stu3; */ struct student stu3;,11.5.2 结构体数组的初始化,与其他类型的数组一样,对结构体数组可以初始化。如: struct student int num; char name20; char sex; int age; float score; char add30; stu3=10101,“Li Lin”,M,18,87.5,“103 Beijing Road”, 10102,“Zhang Fun”,M,19,99,“130 Shanghai Road”, 10104,“ang Min”,F,20,78.5,“1010 Zhongshan Road”; 定义数组stu时,元素个数可以不指定,即写成以下形式: stu =, ; 编译时,系统会根据给出初值的结构体常量的个数来确定数组元素的个数。,11.5.3 结构体数组应用举例 例11.2对候选人得票的统计程序。设有3个候选人,每次输入一个得票的候选人的名字,要求最后输出各人得票结果。,#include #include struct person char name20; int count; leader3=“Li”,0, “Zhang”,0, “Wang”,0; void main() int i,j; char leader_name20; for(i=1;i=10;i+) scanf(“%s”,leader_name); for(j=0;j3;j+) if(strcmp(leader_name,)=0) leaderj.count+: printf(“n“); for(i=0;i3;i+) printf(“%5s:%dn”,,leaderi.count); ,11.6 指向结构体类型数据的指针,一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组中的元素。 11.6.1 指向结构体变量的指针 下面通过一个简单例子来说明指向结构体变量的指针变量的应用。,例11.3 指向结构体变量的指针的应用。,#include #include 程序运行结果: void main() No.:89101 struct student name:Li Lin long num; sex:M char name20; score:89.5 char sex; No.:89101 float score; name:Li Lin ; sex:M struct student stu_1; score:89.5 struct student *p; p= ,11.6 指向结构体类型数据的指针,在C语言中,为了使用方便和使之直观,可以把(*p).num改用 p-num来代替,它表示*p所指向的结构体变量中的num成员。 以下三种形式等价: 结构体变量.成员名 (*p).成员名 p-成员名 上面程序中最后一个printf函数中的输出项表列可以改写为: p-num,p-name,p-sex,p-score,11.6.2 指向结构体数组的指针,前面可以使用指针变量指向数组或数组元素。同样,对结构体数组及其元素也可以用指针或指针变量来指向。 例11.4 指向结构体数组的指针的应用。 struct student int num; char name20; char sex; int age; ; struct student stu3=10101,“Li Lin”,M,18,10102,“Zhang Fen”, M,19,10104,“ang Min”,F,20; void main() struct student *p; printf(“ No. Name sex agen“); for(p=stu;pnum, p-name, p-sex, p-age); ,使用指向结构体数组的指针有关说明:,(1) 如果p的初值为stu,即指向第一个元素,则p加1后p就指向下一个元素的起始地址。例如: (+p)-num 先使p自加1,然后得到它指向的元素中的num成员值(即10102)。 (p+)-num 先得到p-num的值(即10101),然后使p自加1,指向stu1。 (2) 程序已定义了p是一个指向struct student类型数据的指针变量,它用来指向一个struct student型的数据不应用来指向stu数组元素中的某一成员。例如,下面的用法是不对的: p= 编译时将给出警告信息,表示地址的类型不匹配。,11.6.3 用结构体变量和指向结构体的指针作函数参数,将一个结构体变量的值传递给另一个函数,有3种方法: (1) 用结构体变量的成员作参数。例如,用stu1.num或作函数实参,将实参值传给形参。用法和用普通变量作实参是一样的,属于“值传递”方式。应当注意实参与形参的类型保持一致。 (2) 用结构体变量作实参。由于用结构体变量作实参时,采取的是“值传递”的方式,即将结构体变量所占的内存单元的内容全部顺序传递给形参(形参也必须是同类型的结构体变量)。因此,如果在执行被调用函数期间改变了形参的值,该值不能返回主调函数。 (3) 用指向结构体变量(或数组)的指针作实参,表示将结构体变量(或数组)的地址传给形参。,例11.6 用指向结构体变量的指针作实参,输出学生成绩。,#include #define FORMAT “%dn%sn%fn%fn%fn“ struct student int num; char name20; float score3; stu=12345,“Li Li”,67.5,89,78.6; void main() void print(struct student *p); /* 形参类型是指向结构体的指针变量 */ print(&stu); /* 实参为stu的起始地址 */ void print(struct student *p) /*形参类型修改了*/ printf(FORMAT,p-num,p-name,p-score0,p-score1,p-score2); /*用指针变量调用各成员之值*/ printf(“n“); ,11.7 用指针处理链表,11.7.1链表概述 链表是一种常见的重要的数据结构。它是动态地进行存储分配的一种结构。用数组存放数据时,必须事先定义固定的长度(即元素个数)。对于不同的处理对象,需要的数据长度是不固定的,因此必须把数组定得足够大,以能存放对象数据。显然这将会浪费内存。链表则没有这种缺点,它根据需要开辟内存单元。下列图表示最简单的一种链表(单向链表)的结构。 Head 1249 1356 1475 0121 链表有一个“头指针”变量,head表示,它存放一个地址。该地址指向一个元素。链表中每一个元素称为“结点”,每个结点都应包括两个部分:一为用户需要用的实际数据,二为下一个结点的地址。最后结点地址部分放一个“NULL”(表示“空地址”),链表到此结束。,1249,11.7.1 链表概述,可以看到链表中各元素在内存中可以不是连续存放的。要找某一元素,必须先找到上一个元素,根据它提供的下一元素地址才能找到下一个元素。如果不提供“头指针”(head),则整个链表都无法访问。 这种链表的数据结构,必须利用指针变量才能实现。即:一个结点中应包含一个指针变量,用它存放下一结点的地址。 前面介绍了结构体变量,用它作链表中的结点是最合适的。一个结构体变量包含若干成员,这些成员可以是数值类型、字符类型、数组类型,也可以是指针类型。我们用这个指针类型成员来存放下一个结点的地址。例如,可以设计这样一个结构体类型: struct student int num; float score; struct student *next; ;,11.7.1 链表概述,其中成员num和score用来存放结点中的有用数据,next是指针类型的成员,它指向struct student类型数据。 一个指针类型的成员既可以指向其他类型的结构体数据,也可以指向自己所在的结构体类型的数据。 next是struct student类型中的一个成员,它又指向struct student类型的数据。用这种方法就可以建立链表。如图所示: num 10101 10103 10107 score 89.5 90 85 next Null 成员next存放下一结点的地址,程序设计人员可以不必具体知道各结点的地址,只要保证将下一个结点的地址放到前一结点的成员next中即可。,11.7.2 简单链表 例11.7 建立一个简单链表,它由3个学生数据的结点组成。输出各结点中的数据。 #include #define NULL 0 struct student long num; float score; struct student *next; ; viod main() struct student a,b,c,*head,*p; a.num=99101; a.core=89.5; b.num=99103; b.score=90; c.num=99107; c.score=85; /*对结点的num和score成员赋值*/ head= /*输出完c结点后p的值为NULL*/ ,11.8 共用体,11.8.1 共用体的概念 有时需要使几种不同类型的变量存放到同一段内存单元中。例如,可把一个整型变量、一个字符型变量、一个实型变量放在同一个地址开始的内存单元中。这些变量在内存中占的字节数不同,但都从同一地址开始存放。也就是使用覆盖技术,几个变量互相覆盖。这种使几个不同的变量共占同一段内存的结构,称为“共用体”类型的结构。 定义共用体类型变量的一般形式为: union 共用体名 例如:union data 成员表列 int i; 变量表列; char ch; float f; a,b,c;,11.8.1 共用体的概念,也可以将类型声明与变量定义分开: union data int i; char ch; float f; ; union data a,b,c; 即先声明一个union data类型,再将a、b、c定义为union data类型。 “共用体”与“结构体”的定义形式相似。但它们的含义是不同的。 结构体变量所占内存长度是各成员占的内存长度之和。每个成员分别占有其自己的内存单元。而共同体变量所占的内存长度等于最长的成员的长度。例如,上面定义的“共用体”变量a、b、c各占4个字节(因为一个实型变量占4个字节),而不是各占2+1+4=7个字节。,11.8.2 共用体变量的引用方式,只有先定义了共用体变量才能引用它。而且不能引用共用体变量,而只能引用共用体变量中的成员。例如,前面定义了a、b、c为共用体变量,下面的引用方式是正确的: a.i (引用共用体变量中的类型变量i) a.ch (引用共用体变量中的字符变量ch) a.f (引用共用体变量中的实型变量f) 不能只引用共用体变量,例如: printf(“%d“,a) 是错误的,a的存储区有好几种类型,分别占不同长度的存储区,仅写共用体变量名a,难以使系统确定究竟输出的是哪一个成员的值。应该写成printf(“%d“,a.i)或printf(“%c“,a.ch)等。,11.8.3 共用体类型数据的特点,在使用共用体类型数据时要注意以下一些特点: (1) 同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中一种。也就是说,每一瞬时只有一个成员起作用,其他的成员不起作用。 (2) 共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员就失去作用。如有以下赋值语句: a.i=1; a.c=a; a.f=1.5; 在完成以上3个赋值运算以后,只有a.f是有效的,a.i和a.c已经无意义了。 (3) 共用体变量的地址和它的各成员的地址都是同一地址。例如:&a、&a.i、&a.c、&a.f都是同一地址值。,11.8.3 共用体类型数据的特点,(4) 不能对共用体变量名赋值,也不能企图引用变量名来得到一个值,又不能在定义共用体变量时对它初始化。例如,下面这些都是不对的: union int i; char ch; float f; a=1,a,1.5;(不能初始化) a=1; (不能对共用体变量赋值) m=a; (不能引用共用体变量名以得到一个值) (5) 不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针(与结构体变量这种用法相仿)。 (6) 共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。,程序举例,例10.12 设有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、号码、性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。可以看出,学生和教师所包含的数据是不同的。现要求把它们放在同一表格中,如果“job”项为“s”(学生),则第5项为class(班)。即Li是501班的。如果“job”项是“t”(教师),则第5项为position(职务)。ang是prof(教授)。显然对第5项可以用共用体来处理(将class和position放在同一段内存中)。 要求输入人员的数据,然后再输出。为简化起见。只设两个人(一个学生、一个教师)。,#include struct int num;char name10;char sex;char job; union int class; char position10; category; person2; void main() int i; for(i=0,i2;i+) scanf(“%d %s %c %c”, ,运行情况如下:,101 Li f s 501 102 ang m t professor No Name sex job class/position 101 Li f s 501 102 ang m t professor,11.9 枚 举 类 型,如果一个变量只有几种可能的值,可以定义为枚举类型。所谓“枚举”是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。声明枚举类型用enum开头。例如: enum weekday sun,mon,tue,wed,thu,fri,sat; 声明了一个枚举类型enum weekday,可以用此类型来定义变量。 如:enum weekday workday,week_end; workday和week_end被定义为枚举变量,它们的值只能是sun到sat之一。例如: workday=mon;

温馨提示

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

评论

0/150

提交评论