第10章 结构体(最终讲稿)_第1页
第10章 结构体(最终讲稿)_第2页
第10章 结构体(最终讲稿)_第3页
第10章 结构体(最终讲稿)_第4页
第10章 结构体(最终讲稿)_第5页
已阅读5页,还剩36页未读 继续免费阅读

下载本文档

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

文档简介

结构体、共用体及枚举类型第

10

章10.1结构体类型和结构体变量10.2结构体数组10.3结构体指针10.4用指针处理链表

10.5共用体类型

10.6枚举类型

10.7用typedef命名类型本章小结结构体类型和结构体变量10.1教学进程10.1.1结构体类型的定义有时需要将不同类型的数据组合成一个有机的整体,以便于引用。如:一个学生有学号、姓名、性别、年龄、成绩、地址等属性

intnum;charname[20];charsex;

intage;floatscore;

intcharaddr[30];问题定义:100101

LiFun

M1887.5Beijing

Numnamesexagescoreaddr应当把它们组织成一个组合项,在一个组合项中包含若干个类型不同(当然也可以相同)的数据项。教学进程结构体类型struct

结构体名{类型标识符成员名表1;类型标识符成员名表2;

…;类型标识符成员名表n;};定义一个结构体类型的一般形式为:其中struct是用于定义具体结构体类型的关键字,与结构体名共同组成结构体类型名。在“成员表列”中可以定义该类型中有哪些成员,各成员属于什么数据类型,由它们组成结构体。教学进程结构体类型structstudent{intnum;charname[20];charsex;

intage;floatscore;charaddr[30];};结构体类型名成员类型名成员名例如:structstudent{intnum;charname[20];charsex;

intage;floatscore;charaddr[30];};structdate{intmonth;

intday;

intyear;}structstudent{intnum;charneme[20],sex;

intage;

structdatebirthday;charaddr[30];}student1,student2;已定义的结构体类型可以像基类型一样使用。教学进程结构体类型的定义可以嵌套在这个定义中,结构体“日期”类型date中又嵌套定义了结构体“时间”类型time。这就是结构体的嵌套定义。定义一个结构体“日期”类型date:

structdate{intyear; /*年*/

intmonth; /*月*/

intday; /*日*/

structtime/*结构体“时间”类型*/{inthour; /*小时*/

intminute; /*分*/

intsecond; /*秒*/}t;

};结构体类型(2)当一个结构体类型定义在函数之外时,它具有全局作用域;若定义在任一对花括号之内,则具有局部作用域,其作用范围是所在花括号构成的块。(3)结构体是一种复杂的数据类型,是数目固定、类型不同的若干成员的集合,结构体类型的定义只是列出了该结构的组成情况,编译系统并未因此而分配存储空间,当定义了结构体类型的变量或数组后,编译系统才会分配存储空间。(4)成员名可以与程序中的变量名相同,二者不代表同一个对象。例如,程序中可以定义一个变量num,它与struct

stu中的num是两回事,互不干扰。(5)如果两个结构体的成员类型、名称、个数相同,但结构体名不同,也是两个不同的结构类型。结构体类型教学进程要强调的是,结构体类型名(如上例中的date)是定义的类型名,而不是变量名,就好像整型的类型名为int,双精度实型的类型名为double,字符型的类型名为char一样,只不过整型、双精度实型、字符型等基本数据类型是C编译系统已经定义的,用户可以直接用它们来定义相应类型的变量,而结构体类型是用户根据数据处理的需要临时定义的一种类型,一经定义就可以像系统定义的类型一样使用了。但系统并不为类型分配存储空间,为了能在程序中使用结构体类型的数据,必须定义结构体类型的变量。定义结构体类型的变量教学进程结构体类型和结构体变量结构体变量的定义可以采取以下3种方法定义结构体变量:(1)先定义结构体类型,再定义结构体变量例如:structstudent

student1,student2;↑↑↑

结构体类型名结构体变量名定义了student1和student2为structstudent类型(应事先已定义)的变量,即它们具有structstudent类型的结构。student1100101ZhangXinM1990.5Shanghai100102WangLiF2098Beijingstudent2在TC中占字节数2201243059定义结构体类型变量教学进程●一般形式为:

struct结构体名{成员表列}变量名表列;(2)在定义结构体类型的同时定义结构体变量例如:structstudent{intnum;

charname[20];

charsex;

intage;

floatscore;

charaddr[30];}student1,student2;它的作用与第一种方法相同,即定义了两个structstudent类型的变量student1,student2。如果需要,在程序中还可以定义该种结构体类型的其它变量。结构体类型变量的定义教学进程(3)不指定类型名而直接定义结构体变量●

struct

{成员表}变量表;例如:

struct

{intnum;

charname[10];

charsex;

intage;

floatscore;

}studernt1,

student2;指定了一个无名的结构体类型,它没有名字,显然不能再以此结构体类型去定义其它变量了。未出现结构体名结构体类型变量的定义教学进程注意(1)结构体类型与结构体变量是不同的概念,不能混同。(2)结构体类型中的成员名可以与程序中的变量名相同,但二者不代表同一对象。(3)对结构体变量中的成员,可以单独使用,它的作用与地位相当于普通变量。教学进程结构体变量中的每个成员与普通变量一样,可进行各种运算。

st.num=115;

[0]=‘z';

[1]='a';

[2]='\0';

st.sex='M';

st.age=19;

st.score=95.0;

scanf("%d",&st.num);

printf("%s",);方式●结构体变量名.成员名其中“.”为结构体成员运算符,它的优先级最高。结构体变量的引用和初始化结构体变量的引用在定义结构体变量后,就可以引用其成员。引用结构体类型变量教学进程(1)同类的结构体变量可以互相赋值如:student1=student2;

但不能将一个结构体变量作为一个整体进行输入和输出。如:已定义student1和student2为结构体变量并已有值,

printf(″%d,%s,%c,%d,%f,%\n″,student1);(2)如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低一级的成员,进行赋值或存取及运算。

如:访问上面定义的结构体变量student1的各成员

student1.numstudent1.birthday.month定义了结构体变量后,便可以引用这个变量。但应遵守以下规则:引用结构体类型变量教学进程(3)对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。

如:student2.score=student1.score;sum=student1.score+student2.score;student1.age++;++student2.age;(4)可引用结构体变量成员的地址,也可引用结构体变量的地址。

如:scanf(″%d″,&student1.num);//为成员student1.num赋值

printf(″%o″,&student1);//输出变量student1的首地址

但不能用以下语句整体读入结构体变量如:

scanf(″%d,%s,%c,%d,%f,%s″,&student1);

结构体变量的地址主要用作函数参数,传递结构体变量的地址。教学进程与普通变量一样,在定义结构体类型变量的同时也可以对结构体类型变量赋初值。结构体变量的引用和初始化结构体变量的初始化例10-1对结构变量初始化。#include<stdio.h>main(){struct

stu

{intnum;charname[20];charsex;

intage;floatscore;}boy2,boy1={102,"Zhangping",'M',20,78.5};boy2=boy1;printf("Number:%d\nName:%s\n",boy2.num,);printf("Sex:%c\nage:%dScore:%4.1f\n",boy2.sex,boy2.age,boy2.score);}

本例中,对结构体变量boy1作了初始化赋值,然后把boy1的值整体赋予boy2,最后用printf函数输出boy2各成员的值。程序运行结果如下:Number:102Name:ZhangpingSex:MAge:20Score:78.5结构体数组10.310.3.1定义结构体数组教学进程与整型数组、实型数组、字符型数组一样,在程序中也可以定义结构体类型的数组,并且同一个结构体数组中的元素应为同一种结构体类型。与定义结构体变量的方法相似,只需说明其为数组即可。如:structstudent{intnum;charname[20];charsex;intage;floatscore;charaddr[30];

};structstudentstu[3];}stu[3];/*直接定义结构体数组*/定义了一个数组stu,数组有3个元素,均为structstudent类型数据。结构体数组10.310.3.2结构体数组的初始化教学进程与其它类型的数组一样,对结构体数组可以初始化。如:

structstudent{int

num;charname[20];charsex;

intage;floatscore;charaddr[30];

}stu[3]={{10101,″LiLin″,′M′,18,87.5,″103BeijingRoad″},{10102,″ZhangFun″,′M′,19,99,″130ShanghaiRoad″},{10104,″WangMin″,′F′,20,78.5,″1010ZhongshanRoad″}};图9-4定义结构体数组教学进程数组各元素在内存中连续存放,如图所示。一个结构体数组的元素相当于一个结构体变量,引用结构体数组元素的一般形式为:数组名[下标].成员名10.3.3结构体数组的引用教学进程【例10.2】计算学生的平均成绩和不及格的人数。#include<stdio.h>struct

stu{intnum;charname[20];charsex;floatscore;}boy[5]={{101,"Liping",'M',45},{102,"Zhangping",'M',62.5},{103,"Hefang",'F',92.5},{104,"Chengling",'F',87},{105,"Wangming",'M',58}};main(){int

i,c=0;floatave,s=0;

for(i=0;i<5;i++){s+=boy[i].score;

if(boy[i].score<60)c+=1;}

ave=s/5;

printf("average=%f\ncount=%d\n",ave,c);}

本例程序中定义了一个结构体数组boy,共5个元素,并作了初始化赋值。在main函数中用for语句逐个累加各元素的score成员值存于s之中,如果score的值小于60(不及格),那么计数器c加1,循环完毕后输出全班平均分及不及格人数。程序运行结果如下:average=69.000000count=2结构体指针10.410.4.1指向结构体变量的指针变量教学进程结构体类型的指针变量指向结构体变量或数组(或数组元素)的起始地址。

structstudent{intnum;

charname[10];

charsex;

intage;

floatscore;

};

structstudentst1,st2,

st[10],*p;例如令p=&st1,st1.num(*p).nump->num令p=st,

st[0].num(*p).nump->num指向结构体变量的指针变量教学进程当结构体类型的指针变量p指向一个结构体类型变量后,下列三种表示是等价的:结构体变量名.成员

(*p).成员

p->成员必须注意,当p定义为指向结构体类型的变量后,它不能指向某一成员。例如,p=&st1.num;是错误的,因为它企图让结构体指针变量指向结构体变量st1中的成员num。10.4.2指向结构体数组的指针教学进程

#include<stdio.h>structstudent{intnum;charname[20];charsex;

intage;};【例10.4】

指向结构体数组元素的指针的应用。structstudentstu[3]={{10101,"LiLin",'M',18},{10102,"ZhangFun",'M',19},{10104,"WangMin",'F',20}};voidmain(){structstudent*p;

printf("No.Namesexage\n");

for(p=stu;p<stu+3;p++)printf("%5d%-20s%2c%4d\n",p->num,p->name,p->sex,p->age);}结构体指针10.4指向结构体数组的指针教学进程程序分析:p是指向structstudent结构体类型数据的指针变量。在for语句中先使p的初值为stu,也就是数组stu第一个元素的起始地址。在第一次循环中输出stu[0]的各个成员值。然后执行p++,使p自加1。p加1意味着p所增加的值为结构体数组stu的一个元素所占的字节数。执行p++后p的值等于stu

+1,p指向stu[1]。在第二次循环中输出stu[1]的各成员值。在执行p++后,p的值等于stu+2,再输出stu[2]的各成员值。在执行p++后,p的值变为stu+3,已不再小于stu+3了,不再执行循环。图9-8教学进程注意:(1)

如果p的初值为stu,即指向第一个元素,则p加1后p就指向下一个元素。例如:

(++p)->num先使p自加1,然后得到它指向的元素中的num成员值(即10102)。

(p++)->num先得到p->num的值(即10101),然后使p自加1,指向stu[1]。(2)

程序已定义了p是一个指向structstudent类型数据的指针变量,它用来指向一个structstudent类型的数据,不应用来指向stu数组元素中的某一成员。指向结构体数组的指针用指针处理链表10.710.7.1链表概述1.链表的一般结构存储节点数据域 存放数据元素指针域 存放下一个结点元素的地址链表是一种常见的重要的数据结构,是动态地进行存储分配的一种结构。链表的组成:头指针:存放一个地址,该地址指向一个元素

结点:用户需要的实际数据和链接节点的指针链表是一种常见的重要的数据结构,是动态地进行存储分配的一种结构。链表的组成:头指针:存放一个地址,该地址指向一个元素

结点:用户需要的实际数据和链接节点的指针链表是一种常见的重要的数据结构,是动态地进行存储分配的一种结构。链表的组成:头指针:存放一个地址,该地址指向一个元素

结点:用户需要的实际数据和链接节点的指针教学进程教学进程链表的概述2.结点结构体类型的定义

struct

结构体名

{数据成员表;

struct

结构体名*指针变量名;

};链表结点结构的一般形式:其函数原型为void*malloc(unsigned

intsize);又如:float*pc;pc=(float*)malloc(5*sizeof(float));3.结点的动态分配

malloc(存储区字节数)

该函数返回存储区的首地址。形式是:释放存储区用如下函数:free(p);它表示释放由p指向的存储空间。教学进程教学进程结点的动态分配用结构体建立链表:

structstudent{intnum;

floatscore;

structstudent*next;};

其中成员num和score用来存放结点中的有用数据(用户需要用到的数据),next是指针类型的成员,它指向structstudent类型数据(这就是next所在的结构体类型)教学进程教学进程#include<stdio.h>structstudent{longnum;floatscore;

structstudent*next;};voidmain(){structstudenta,b,c,*head,*p;

a.num=99101;a.score=89.5;

b.num=99103;b.score=90;c.num=99107;c.score=85;用指针处理链表10.710.7.2建立简单的静态链表【例10.7】建立上图所示的简单链表,它由个学生数据的节点组成。输出个节点中的数据。head=&a;

a.next=&b;

b.next=&c;

c.next=NULL;p=head;do{printf("%ld%5.1f\n“,p->num,p->score);p=p->next; }while(p!=NULL);}教学进程教学进程建立链表指从无到有建立一个链表,即一个一个地开辟结点和输入各结点数据,并建立前后相链的关系,其算法如下:①读取数据;②生成新结点;③将数据存入新结点;④将新结点插入到链表中。重复上述步骤,直到输入结束。可以根据需要将新结点插入到链表不同位置,如链表头、链表中间、链表尾等,例10-10将新结点插入到链表尾部。10.7.3创建动态链表

【例10.7】从键盘读入学生的信息,包括学号、成绩,当输入的学号为0时,表示建立链表结束。#include<stdlib.h>#include<alloc.h>#defineLENsizeof(struct

stu)/*LEN为结构体类型struct

stu的长度*/struct

stu{intnum;floatscore;

struct

stu*next;};struct

stu*creat(){struct

stu*head;/*用于指向链表的第一个结点*/struct

stu*p;/*用于指向新生成的结点*/struct

stu*tail;/*用于指向链表的最后一个结点*/

intx;floaty;tail=head=NULL;

scanf("%d",&x);

while(x!=0){p=(struct

stu*)malloc(LEN);p->num=x;

if(head==NULL)head=p;

scanf("%f",&y);p->score=y;

if(tail!=NULL)tail->next=p;tail=p;

scanf("%d",&x);}

if(tail!=NULL)tail->next=NULL;

return(head);}所谓“访问”就是对各结点的数据域中的值进行修改、运算、输出等。例10-11编写函数,顺序输出链表中各结点数据域中的内容。顺序输出链表的算法比较简单,只需利用一个指针p从头到尾依次指向链表中的每个结点,即可以完成顺序访问。10.7.4顺序访问链表中的结点voidlist(struct

stu*head){struct

stu*p;

printf("Thelistrecordsare:\n");p=head;

if(head!=NULL)do{printf("%d\t%5.1f\n",p->num,p->score);p=p->next;}while(p!=NULL);else

printf("Thelistisnull");}main(){struct

stu*head;head=creat();

list(head);}程序运行结果如下:10190↙10289↙0↙Thelistrecordsare:1019010289共用体类型10.8教学进程使几个不同的变量共占同一段内存的结构。一般形式union共用体名

{成员表}变量表列;虽然共用体与结构体在定义形式上类似,但它们在存储空间的分配上是有本质区别的。按照定义中各个成员所需要的存储空间的总和来分配存储单元,其中各成员的存储位置是不同的。结构体按定义中需要存储空间最大的成员来分配存储单元,其他成员也使用该空间,它们的首地址是相同的。共用体10.8.1什么是共用体类型共用体教学进程例如:

uniondatauniondata

{inti;{inti;charch;或charch;floatf;floatf;}a,b,c;};uniondataa,b,c;上面定义的“共用体”变量a、b、c各占4个字节(因为一个实型变量占4个字节),而不是各占2+1+4=7个字节。

温馨提示

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

评论

0/150

提交评论