C语言程序设计(第7章)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第七章结构体与共用体
计算机基础教研室
本章主要内容
本章介绍:如何自己构造数据类型(构造型数据)
●结构体
●内存分配函数
●共用体
●枚举类型
●类型定义
●教学目的与要求
⏹掌握结构体和共同体类型的说明
⏹结构体和共用体变量的定义及初始化方法
⏹掌握结构体与共用体变量成员的引用
⏹领会存储动态分配和释放
⏹领会链表的基本概念和基本操作
⏹领会枚举类型变量的定义
⏹了解T y p e d e f的作用
●重点与难点
⏹结构体的基本概念
⏹结构体类型及变量的定义
⏹结构数组
⏹用指针处理链表
⏹共用体及枚举类型的基本概念
⏹T y p e d e f的基本概念
C(C++)数据类型
一、结构体
1.概述
●数组是构造类数据,其数组元素必须是同一数据类型的。

●结构体也是构造类数据,但其成员可以是任何类型的。

构造类型使用户可以象处理单个变量一样来处理复杂的数据结构。

使用结构体的一般步骤
●根据问题的要求定义一个结构体类型
●用自己定义的结构体类型定义结构体变量
●在程序中使用结构体变量处理问题
比较普通变量的情况:
●用系统给定的数据类型定义变量
●在程序中使用变量处理问题
如何定义结构体类型?
一个示例
小结:什么是“结构体类型”?
●用户自己定义的构造型数据类型
●由若干数据项(成员)组成
●同一结构体中的成员可以具有不同的数据类型
●注意成员定义与普通变量定义的区别:
成员定义时¡ª¡ª不为其分配内存
变量定义时¡ª¡ª为其分配内存
结构体类型的特点:
●组成结构体的成员本身必须是一种已有定义的数据:
⏹基本类型成员(整型/字符型/实型)
⏹指针类型成员
⏹数组类成员
⏹其他构造类成员(包括已定义的另一种结构体)
⏹注意:成员≠变量,故成员名可与变量名同名
⏹结构体类型可以有千千万万种,表示由若干不同数据项组成的复合类型。

●定义结构体类型时,系统不会为该结构体分配内存(只是定义类型,而非变量声明)
2、结构体类型变量的定义
定义了以上结构体类型后,s t r u c t s t u d e n t相当于标准数据类型关键字c h a r,
i n t,f l o a t¡-我们可以用它来定义“结构体变量”。

①在结构体类型定义后,用s t r u c t结构体名复合词定义
s t r u c t结构体名
{¡-};
s t r u c t结构体名变量名1,变量名2,…变量名n;
如:s t r u c t s t u d e n t a,b[30],*p;
a为s t r u c t s t u d e n t类型的变量
b为s t r u c t s t u d e n t类型的数组(每个元素都是一个结构
体变量,都有众成员)
p为指向s t r u c t s t u d e n t类型的指针变量
还有两种合二为一方法¡-¡-
【例二】定义结构体类型的同时定义结构体类型变量。

main()
{
struct student
{
int number;
char name[6];
char sex;
int age;
char address[20];
} a,b[30],*p;
¡­¡­
}
其他有关知识¡-
●实际使用中,还可以使用以下形式:
#d e f i n e S T U s t r u c t s t u d e n t
S T U s t u1,s t u2;
●比较一下两种变量定义方式的异同:
●i n t a,b,c;
定义三个整型变量,每个变量占二个字节,可单独赋值。

●s t r u c t s t u d e n t a,b,c;
定义三个结构体类型变量,每个变量下有若干“成员”。

其占用的内存长度等于各成员项长度之和。

示例
示例
【例五】若有以下定义,则正确的赋值语句为。

s t r u c t c o m p l e x{
f l o a t r e a l;
f l o a t i m a
g e;
};
s t r u c t v a l u e{
i n t n o;
s t r u c t c o m p l e x c o m;
}v a l1;
A)c o m.r e a l=1;B)v a l1.c o m p l e x.r e a l=1;
C)v a l1.c o m.r e a l=1;D)v a l1.r e a l=1;
3、结构体变量的初始化和赋值
●使一个结构体变量获得数据¡°值¡〒(实际上是给其各个成员赋值)有三种方法:
⏹①定义时初始化之
⏹②用赋值语句对各成员分别赋值
⏹③同类型的结构体变量间相互赋值
如s t u d e n t1=s t u d e n t2
示例:①定义时初始化之
【例六】
m a i n()
{
s t r u c t
{
c h a r n a m e[15];
c h a r c l a s s[12];
l o n g n u m;
}s t u={"W e n l i","C o m p u t e r",200113};
p r i n t f("%s\n%s\n%l d\n",s t u.n a m e,s t u.c l a s s,s t u.n u m);
}
示例:②用赋值语句对各成员分别赋值
【例七】
m a i n(){
s t r u c t
{c h a r n a m e[15];
c h a r c l a s s[12];
l o n g n u m;
}s t u={"W e n l i","C o m p u t e r",200113};
s t u.n a m e[0]='1';
s t u.c l a s s[2]='A';
s t u.n u m=1111;
p r i n t f("%s,%s,%d\n",s t u.n a m e,s t u.c l a s s,s t u.n u m);
}
示例:②用赋值语句对各成员分别赋值
【例七】
m a i n(){
s t r u c t
{c h a r n a m e[15];
c h a r c l a s s[12];
l o n g n u m;
}s t u={"W e n l i","C o m p u t e r1",200113};
s t u.n a m e[0]='1';
s t u.c l a s s[2]='A';
s t u.n u m=1111;
p r i n t f("%s,%s,%d\n",s t u.n a m e,s t u.c l a s s,s t u.n u m);
}
进行所谓“结构体变量赋值”只能逐个成员进行,不能将结构体变量作为一个整体进行输入和输出。

如对结构体变量s t u,以下语句是错误的:
s c a n f(“%s,%s,%l d”,s t u);
p r i n t f(“%s,%s,%l d”,s t u);
4、结构体变量的引用
●只能引用其成员变量
用圆点(成员运算符)——优先级最高
如v a l1.n o++
s u m=v a l1.c o m.r e a l+v a l1.c o m.i m a g e
●可以将成员变量按普通变量运算方式处理,包括取地址:
&v a l1(函数间传递用)&v a l1.n o
●对多级结构体,只能对最低级的成员进行赋值、存取及运算处理。

示例
●以下函数g e t d a y s()计算某年某月某日是该年的第几天。

如2001年2月5日是该年的第36天。

闰年的二月有29天,表达式“(y e a r%4==0&&y e a r%100!=0)||(y e a r%400)==0”值为真,即
为闰年,其中y e a r表示年号。

示例
5、结构体数组
●定义P265
⏹定义结构体后定义
⏹定义结构体时同时定义
5、结构体数组
●初始化P266
⏹一般初始化
⏹省略维数[]
⏹定义后初始化
一般初始化示例
6、指向结构体类型的指针
●一个结构体变量的指针就是该变量所占据的内存段的起始地址。


s t r u c t s t u d e n t s t u;
s t r u c t s t u d e n t*p;
p=&s t u;
如果s t r u c t s t u d e n t s t u;
s t r u c t s t u d e n t*p;
p=&s t u;
则以下三种形式等价:
s t u.a g e(结构体变量名.成员名)
(*p).a g e(*指针变量名.成员名)
p->a g e(指针变量名.成员名)
此时:p->a g e++等效于(p->a g e)++先得
到成员值,再使它加1;
++p->a g e等效于++(p->a g e)先使成员
值加1,再使用之。

7、链表
链表结点定义形式
●定义形式:
s t r u c t s t u d e n t
{
i n t n u m b e r;
c h a r n a m e[6];
s t r u c t s t u d e n t*n e x t;
};
链表操作常用技术语句
●p=p->n e x t在链表结点间顺序移动指针
将p原来所指结点中n e x t的值赋给p,而p->n e x t值即下一结点起始地址,故p=p->n e x t的作用是使p指向下一结点起始地址。

●p2->n e x t=p1将新结点添加到现在链表中
如果p2是链表中的末结点,p1指新建结点,此句的功能是使p1所指新结点变成链表中的新的末结点。

●p2->n e x t=N U L L让p2所在结点成为链表中最后结点
示例
若已建立下面的链表结构,指针p指向某单向链表的首结点,如下图所示。

s t r u c t n o d e
{
i n t d a t a;
s t r u c t n o d e*n e x t;
}*p;
以下语句能正确输出该链表所有结点的数据成员d a t a的是
链表指针p++表示什么?
静态链表的建立
P274例11.7
二、内存分配函数
2、动态内存分配函数P275/P387
以下函数在m a l l o c.h或s t d l i b.h中定义(n,x为无符号整数,p为指针变量):●v o i d*m a l l o c(x)
分配一个长度为x字节的连续空间,分配成功返回起始地址指针,分配失败(内存不足)返回N U L L
●v o i d*c a l l o c(n,x)
分配n个长度为x字节的连续空间(成败结果同上)
●v o i d*r e a l l o c(p,x)
将p所指的已分配空间大小调整为x个字节
●v o i d f r e e(p)
将由以上各函数申请的以p为首地址的内存空间全部释放
动态内存分配函数使用示例
#i n c l u d e"s t d l i b.h"
m a i n()
{c h a r*p;
p=(c h a r*)m a l l o c(17);
i f(!p)
{
p r i n t f("内存分配出错");
e x i t(1);
}
s t r c p y(p,"T h i s i s16c h a r s");
/*如果超过16个字符,可能破坏程序其他部分*/
p=(c h a r*)r e a l l o c(p,18);
i f(p==N U L L)
{
p r i n t f("内存分配出错");
e x i t(1);
}
s t r c a t(p,".");
p r i n t f(p);
f r e e(p);
}
动态链表的建立和遍历示例
(后进先出的数据结构,即所谓“栈”)
#d e f i n e N U L L0
s t r u c t i n f o
{
i n t d a t a;
s t r u c t i n f o*n e x t;
};
m a i n()
{
s t r u c t i n f o*b a s e,*p;
i n t n;
b a s e=N U L L;
动态链表的建立和遍历示例
(以建立P274链表为例)
#d e f i n e N U L L0
s t r u c t i n f o
{
l o n g n u m;
i n t s c o r e;
s t r u c t i n f o*n e x t;
};
m a i n()
{
s t r u c t i n f o*h e a d,*p1,*p2;
i n t n=1;
c l r s c r();
三、共用体(联合体)
●1、概述P287
与结构体相似,共用体也是一种用户自己定义的构造型数据,其成员也可以具有不同的数据类型,但共用体将几种不同的数据项存放在同一段内存单元中。

所以,每一时刻只能有一个成员存在¡ª¡ª占用分配给该共用体的内存空间(新进旧出)。

该共用体的数据长度等于最长的成员长度。

如何定义共用体类型?
3、共用体变量的声明
共用体变量的引用
●共用体变量的引用与结构体相似
♫只能引用其成员变量,不能引用共用体变量本身
正确:p r i n t f(“%d”,d a t a.i);
错误:p r i n t f(“%d”,d a t a);
♫不能对共用体变量赋值,不能初始化,不能作为函数参数!见P289示例
♫允许两个同类型共用体之间相互赋值。

♫可通过指针引用。

示例
m a i n()
{
u n i o n u_t y p e{
i n t i;
c h a r c h[6];
l o n g s;
};
s t r u c t s t_t y p e{
u n i o n u_t y p e u;
f l o a t s c o r e[3];
};
p r i n t f("%d\n",s i z e o f(s t r u c t s t_t y p e));
}
示例
m a i n()
{u n i o n e x a m p l e{
s t r u c t{
i n t x;
i n t y;
}i n;
i n t a[2];
}e={0,0};
e.a[0]=1;e.a[1]=2;
p r i n t f("%d,%d\n",e.i n.x,e.i n.y);
}
四、枚举类型
1、概述P291
所谓“枚举”,是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。

枚举类型也是用户自定义的数据类型,用此种类型声明的变量只能取指定的若干值之一。

2、定义枚举类型
一般形式
e n u m c n{r e d,y e l l o w,b l u e,w h i l e,b l a c k};
e n u m d a y{s u n,m o n,t u e,w e d,t h u,
f r i,s a t};
0,1,2,3,4,5(有值常量)
花括号中间的数据项称“枚举元素”或“枚举常量”,是用户定义的标识符。

3、枚举型变量的声明
e n u m c n a,b,c;
e n u m d a y x,y,z;
亦可在定义类型时同时声明枚举型变量:
e n u m c n{r e d,y e l l o w,b l u e,w h i t e,b l a c k}a,b,c;
【注意】枚举元素为有值常量,默认为0,1,2,3…
但定义时不能将
e n u m c n{r e d,y e l l o w,b l u e,w h i l e,b l a c k};
写成e n u m c n{0,1,2,3,4};
也不能对元素直接赋值,如r e d=3;
应先进行强制类型转换才能赋值。

见P292
但可在定义时改变其值。

示例
一、以下程序的运行结果是什么?
m a i n()
{
e n u m c o l o r{r e d,g r e e n=4,b l u e,w h i t e=b l u e+10};
p r i n t f("%d,%d,%d\n",r e d,b l u e,w h i t e);
}
二、以下正确的枚举类型定义是。

A)e n u m a={“s u n”,”m o n”,”t u e”};
B)e n u m b{s u n=7,m o n=-1,t u e};
C)e n u m c{7,1,2};
示例
m a i n()
{
e n u m c o l o r{r e d,g r e e n,b l u e,w h i t e};
e n u m c o l o r
f c;
c l r s c r();
p r i n t f("请输入色号:");
s c a n f("%d",&f c);
s w i t c h(f c)
{
c a s e r e d:p r i n t f("红色!");b r e a k;
c a s e g r e e n:p r i n t f("绿色!");b r e a k;
c a s e b l u e:p r i n t f("蓝色!");b r e a k;
c a s e w h i t e:p r i n t f("白色!");b r e a k;
d e f a u l t:p r i n t f("其他颜色!");
}
}
五、类型定义(t y p e d e f)
给已有的数据类型加一个新的别名——提高程序可读性(但未建立新的数据类型)。

一般形式:
t y p e d e f数据类型名新别名
(已有定义)(习惯用大写)例
t y p e d e f f l o a t R E A L;
R E A L a,b,c;
用法
1、简单数据类型
t y p e d e f f l o a t R E A L;
R E A L a,b;=f l o a t a,b;
2、数组
t y p e d e f c h a r S T R[80];
S T R s1;=c h a r s1[80];
3、指针
t y p e d e f f l o a t*P F;
P F p;=f l o a t*p;
4、函数
t y p e d e f c h a r F C H();
F C H a;=c h a r a();
用法
5、结构体/联合体等
t y p e d e f u n i o n{……}D A T E;
t y p e d e f s t r u c t{……}D A T E;
D A T
E b i r t h d a y,*p;
相当于
u n i o n{……}b i r t h d a y,*p;
s t r u c t{……}b i r t h d a y,*p;
本章编程练习
1、编写一个竞赛用的秒表程序,按S键开始计时,按E键停止计时。

2、编写一个通讯录程序,能动态存储不超过10个同学的个人信息(如姓名、性别、年龄等),并能进行查询。

相关文档
最新文档