第 7 章 结构体和共用体

57
7 7 第 第第 第第第第 体体 第 第第 第第第第 体体

Upload: buck

Post on 14-Jan-2016

97 views

Category:

Documents


8 download

DESCRIPTION

第 7 章 结构体和共用体. 7.1.1 结构体类型和结构体变量. 数据类型 : 基本类型 : 整型、字符型、浮点型 构造数据类型 : 数组 结构体 共用体 数组实质上是同一类型变量的集合 在实际应用中,一组数据往往具有 不同 的数据类型 , 在 C 语言引入 结构体 来处理这种应用. 以我们常用的通讯录为例,通讯录中的联系人一般要设置序号、姓名、年龄、性别、通信地址等数据,这些数据组合到一起共同来描述和表达联系人这个整体信息。在数据类型说明上,序号为整型;姓名应为字符型;年龄应为整型;性别应为字符型;通信地址应为字符型. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 7 章 结构体和共用体

第第 77 章 结构体和共用章 结构体和共用体体

Page 2: 第 7 章 结构体和共用体

7.1.1 7.1.1 结构体类型和结构体变量结构体类型和结构体变量 数据类型 :

基本类型 : 整型、字符型、浮点型 构造数据类型 : 数组 结构体 共用体数组实质上是同一类型变量的集合 在实际应用中,一组数据往往具有不同的

数据类型 , 在 C 语言引入 结构体 来处理这种应用 .

Page 3: 第 7 章 结构体和共用体

以我们常用的通讯录为例,通讯录中的联系人一般要设置序号、姓名、年龄、性别、通信地址等数据,这些数据组合到一起共同来描述和表达联系人这个整体信息。在数据类型说明上,序号为整型;姓名应为字符型;年龄应为整型;性别应为字符型;通信地址应为字符型

Page 4: 第 7 章 结构体和共用体

C语言中给出了另一种构造数据类型——“结构( structure )”或叫“结构体”,“结构”是一种构造类型,它是由若干相互关联的“成员”组成的。每一个成员可以是一个基本数据类型,也可以是数组、指针,或者又是一个构造类型。结构既然是一种“构造”而成的数据类型,那么在使用之前必须先定义它的组成成分,我们叫做结构的类型。因为客观世界管理对象的多样性,构造了某个结构类型后就可以用它来说明该结构类型的变量,以便在程序设计中来引用和操纵该结构变量

Page 5: 第 7 章 结构体和共用体

7.1.2 7.1.2 结构类型的定义结构类型的定义结构类型定义的一般形式为:struct 结构类型名{ 成员列表 };

成员列表由若干个成员组成,每个成员都是该结构的一个组成部分。对每个成员也必须作类型说明,其形式为:

类型说明符 成员名 ;

成员名的命名应符合标识符的书写规定。

Page 6: 第 7 章 结构体和共用体

例如定义一个通讯录的联系人结构类型:struct person { long num; char name[30]; int age; char sex; char address[200]; };

Page 7: 第 7 章 结构体和共用体

结构类型说明里包含指针变量结构类型说明里包含指针变量如果将联系人的姓名用字符指针来说明的结构如下:  struct person

    {        long num;        char *name;

int age;        char sex;

char address[200]; };

Page 8: 第 7 章 结构体和共用体

7.1.3 7.1.3 结构变量的定义 结构变量的定义 1 )先定义结构类型,再说明结构变量。

如:struct person{        long num;        char name[30];

int age;        char sex;        char address[200];};

 struct person ab1,ab2;定义两个结构类型为 person 的结构变量 ab1,ab2 。

Page 9: 第 7 章 结构体和共用体

2 )在定义结构类型的同时说明结构变量。例如:struct person    {        long num;        char name[30];

int age;        char sex;        char address[200];}ab1,ab2;

Page 10: 第 7 章 结构体和共用体

3 )直接说明结构变量。例如:struct    {        long num;        char name[30];

int age;        char sex;        char address[200];}ab1,ab2;

Page 11: 第 7 章 结构体和共用体

结构体内存布局结构体内存布局

Page 12: 第 7 章 结构体和共用体

结构体长度结构体长度结构变量的总长度为各个成员长度的总

和。我们一般用 sizeof ( 结构类型名 ) 这个库函数来获取结构变量在内存实际所占字节的总长度。如取通讯录联系人结构的长度的语句为 :

sizeof (struct person);

Page 13: 第 7 章 结构体和共用体

结构嵌套定义结构嵌套定义通讯录联系人结构的嵌套定义:

先定义一个联系方式结构 :struct contact

{        char telephone[20];        char fax[20];        char email[20];    };

Page 14: 第 7 章 结构体和共用体

 struct person    {        long num;        char name[30];

int age;        char sex;        char address[200];

struct contact lxfs;}ab1;

Page 15: 第 7 章 结构体和共用体

嵌套结构布局 嵌套结构布局

Page 16: 第 7 章 结构体和共用体

7.2   7.2    结构变量成员的引用方法结构变量成员的引用方法 7.2.1 结构变量的引用

引用结构变量成员的一般形式是: 结构变量名 . 成员名

例如上面定义的联系人结构变量 ab1,ab2 : ab1.name        即第一个联系人的姓名 ab2.age          即第二个联系人的年龄成员本身又是一个结构的引用方法,用 . 运算符逐级访问结构的成员 .

例如:ab1.lxfs.email

Page 17: 第 7 章 结构体和共用体

【例 7.1 】给结构变量赋值并输出其值。 #include <string.h>

main(){   struct person    {        long num;        char name[30];

int age;        char sex;        char address[200];

7.2.2 7.2.2 结构变量的赋值结构变量的赋值

Page 18: 第 7 章 结构体和共用体

struct person ab1,ab2;    ab1.num=1;    strcpy(ab1.name,“Zhao Jun”);    printf(“input age and sex\n”);    scanf(“%d %c”,&ab1.age,&ab1.sex);    ab2=ab1;   printf("Number=%ld\nName=%s\n" ab2.num,ab2.name);   printf("age=%d\nsex=%c\n",ab2.age,ab2.sex);

Page 19: 第 7 章 结构体和共用体

7.3  7.3  结构变量的初始化结构变量的初始化【例 7.2 】对结构变量初始化。

main(){

struct person    {        long num;        char name[30];

int age;        char sex;        char address[200];}ab1={1,“Gao Hong",38,’M’, “Beijing Haidian”};

Page 20: 第 7 章 结构体和共用体

7.4   7.4    结构体数组 结构体数组 .4.1 结构数组的定义和初始化: 例如: struct person { long num; char name[30]; int age; char sex; char address[200]; } struct person abook[10];

Page 21: 第 7 章 结构体和共用体

【例 7.3 】输出通讯录中的联系人的平均年龄 . struct person

    {        long num;        char name[30];

int age;        char sex;        char address[200]; }abook[3]={             {1,"Xu Chong",25,"F",”Beijing Chaoyang Distinct ”},             {2,"Tao Ning",26,"F",”Shanghai Fudan University”},             {3,”Liu Qiang”,35,”M”,”Shenzhen Shitong CO.,LTD”}

} ;

Page 22: 第 7 章 结构体和共用体

void main()

{ int i;

int avg,sum=0;

for(i=0;i<3;i++)

{sum+=abook[i].age;}

avg=sum/3;

printf(“average=%d\n”,avg);

}

Page 23: 第 7 章 结构体和共用体

7.5  7.5  结构体指针 结构体指针 结构指针变量说明的一般形式为:

struct 结构名 * 结构指针变量名例如,在前面的例题中定义了 person 这个结构类型,如要说明一个指向 person 的指针变量pabook ,可写为: struct person *pabook; struct person ab1;

    pabook=&ab1是正确的,而: pabook=&person是错误的。

Page 24: 第 7 章 结构体和共用体

结构指针变量访问成员结构指针变量访问成员其访问的一般形式为:

(* 结构指针变量 ). 成员名或为: 结构指针变量 -> 成员名例如:(*pabook).name或者: pabook->name

Page 25: 第 7 章 结构体和共用体

7.5.2 7.5.2 指向结构体数组的指针指向结构体数组的指针结构体指针变量可以指向一个结构体数组,

这时结构体指针变量的值是整个结构数组的首地址。结构指针变量也可指向结构数组的一个元素,这时结构指针变量的值是该结构数组元素的首地址。如果 psa 为指向结构数组的指针变量,则 psa 也指向该结构数组的 0 号元素, psa+1 指向 1 号元素, psa+i 则指向 i 号元素。这与普通数组的情况是一致的。

Page 26: 第 7 章 结构体和共用体

【例 7.5 】用指向结构体数组的指针输出结构体数组中的元素。struct person

{ long num; char name[30]; int age; char sex; char address[200]; }abook[3]={ {1,"Xu Chong",25,'F',"Beijing Chaoy

ang Distinct"}, {2,"Tao Ning",26,'F',"Shanghai Fuda

n University"}, {3,"Liu Qiang",35,'M',"Shenzhen Don

gxing CO.,LTD"} };

Page 27: 第 7 章 结构体和共用体

void main() { int i; struct person *psa; printf("Num\t\tName\t\t\tage\t\tsex\t\t\n"); psa=abook; for(i=0;i<3;i++) { printf("%ld\t\t%s\t\t%d\t\t%c\t\t\n",psa->nu

m,psa->name,psa->age,psa->sex); psa++; } }

Page 28: 第 7 章 结构体和共用体

应该注意的语句是 psa++ ,每次 psa 自增后自动跳过一个结构类型的长度,指向下一个结构变量的首地址 , 这样才能正确输出结构变量的成员。

如: 当 psa+0 指向 abook[0] 即 {1,"Xu Chong",2

5,'F',"Beijing Chaoyang Distinct"} 的首地址; 当 psa+1 指向 abook[1] 即 {2,"Tao Ning",2

6,'F',"Shanghai Fudan University"} 的首地址;当 psa+2 指向 abook[2] 即 {3,"Liu Qiang",35,'M',"Shenzhen Dongxing CO.,LTD"} 的首地址;

Page 29: 第 7 章 结构体和共用体

7.5.3   7.5.3    结构体在函数传递中的应用结构体在函数传递中的应用 【例 7.6 】计算通讯录中联系人的平均年龄和统计年龄小

于 30 岁的人数。用结构指针变量作函数参数编程。struct person

{ long num; char name[30]; int age; char sex; char address[200]; }abook[3]={ {1,"Xu Chong",25,'F',"Beijing Chaoyang Distinc

t"}, {2,"Tao Ning",26,'F',"Shanghai Fudan Universi

ty"}, {3,"Liu Qiang",35,'M',"Shenzhen Dongxing C

O.,LTD"}};

Page 30: 第 7 章 结构体和共用体

void main() { struct person *psa; void average(struct person *inps); psa=abook; average(psa); } void average(struct person *inps) {struct person *tpsa; int c=0,i; int avg,sum=0; tpsa=inps;

Page 31: 第 7 章 结构体和共用体

for(i=0;i<3;i++) { sum+=tpsa->age; if(tpsa->age<30) c+=1; } avg=sum/3; printf("average=%d\n persons which a

ge less than thirty count=%d\n",avg,c);}

Page 32: 第 7 章 结构体和共用体

7 .6 7 .6 动态存储分配 动态存储分配 1) 分配内存空间malloc 函数

函数原型: void*malloc(unsigned int size); 函数功能:在内存的动态存储区中分配一块长

度为 "size" 字节的连续区域。函数的返回值为该区域的首地址。若分配失败(系统不能提供所需内存),则返回 NULL 。因 malloc 的返回类型是 void * ,需要把返回值强制转换为需要的数据类型指针,比如申请内存用来处理结构类型,那么就要强制转换为结构类型。例如: char *p;          p=(char *)malloc(200*sizeof(char));

Page 33: 第 7 章 结构体和共用体

如前我们定义的结构通讯录联系人结构体,如果动态分配结构变量的存储空间,可用以下语句实现:

struct person *pab;pab= (struct person*) malloc (sizeof(struc

t person));

Page 34: 第 7 章 结构体和共用体

分配内存空间 calloc 函数 calloc 是另一个用于分配内存空间的函数。 函数原型: void*calloc(unsigned int n , uns

igned int size); 函数功能:在内存动态存储区中分配 n块长

度为“ size” 字节的连续区域。函数的返回值为该区域的首地址。calloc 函数与 malloc 函数的区别仅在于一次可以分配 n块 size 大小的区域。例如:

struct person *pab; pab= (struct person*) calloc (2,sizeof(struct p

erson));

Page 35: 第 7 章 结构体和共用体

7.7 7.7 用结构和指针处理链表 用结构和指针处理链表

Page 36: 第 7 章 结构体和共用体

图中,第 0 个结点称为头结点,它存放有第一个结点的首地址,它没有数据,只是一个指针变量。以下的每个结点都分为两个域,一个是数据域,存放各种实际的数据,如序号 num ,姓名 name ,年龄 age, 性别 sex 等;另一个域为指针域,存放下一结点的首地址。链表中的每一个结点都属于同一种结构类型。头节点是链表的重要节点 ,链表的各种操作都是从头节点开始进行的。

Page 37: 第 7 章 结构体和共用体

结点定义结点定义 一个存放通讯录联系人结点应为以下结构:

struct person    {   long num;         char name[30];

int age;         char sex;         char address[200];

struct person * next; };

Page 38: 第 7 章 结构体和共用体

7.7.27.7.2 建立链表建立链表【例 7.8 】建立一个有三个结点的链表 , 存放通讯录数据 . struct person { long num; char name[30]; struct person * next; } struct person *createlist(int n) { struct person *head,*cur,*tail; /*head 为头结点; cur 为新建的结点; tail 为尾结点 *

/ int i; for(i=0;i<n;i++) { cur=(struct person *) malloc(sizeof(struct person));

/* 动态申请建立一个新结点 */

Page 39: 第 7 章 结构体和共用体

if (cur==NULL) { printf("memory malloc failure"); exit(0); } printf("please input number and name\n"); scanf("%d,%s",&cur->num,cur->name); if(i==0) tail=head=cur; /* 第一个节点 */ else tail->next=cur; /*建立中间结点 */ cur->next=NULL; tail=cur; } return(head); /* 函数返回新建链表的头结点 */

}

Page 40: 第 7 章 结构体和共用体

7.7.3 7.7.3 输出链表输出链表 【例 7.9 】输出链表数据的函数 void output_list (struct person *head) { struct person *h; h=head; while(h!=NULL) { printf("%d,%s\n",h->num,h->name); h=h->next; } }

Page 41: 第 7 章 结构体和共用体

7.7.4 7.7.4 插入操作插入操作设在通讯录链表中,各联系人结点按照 num

(序号)由小到大顺序存放,当新建一个联系人信息时,把结点 cur插入链表。用指针cur 指向待插入结点,设把 cur插在 m2 结点之前, m1 结点之后(如下页图)。

插入算法要点如下:找到应插入的位置。1. 在 m2 之前、 m1 之后插入 cur 。2. 将 cur插入第一个结点之前。3. 将 cur插入表尾结点之后。

Page 42: 第 7 章 结构体和共用体
Page 43: 第 7 章 结构体和共用体

7.7.5 7.7.5 删除结点删除结点删除一个结点的算法要点如下 :找到需要删除的结点 , 用 cur 指向它。并用 m1

指向 cur 的前一个结点。 1. 要删除的结点是头结点。 2. 要删除的结点不是头结点。 设在通讯录链表中删除序号为 num 的结点,

以表头指针 head 和需要删除的结点的 num(序号)为参数,返回删除后的链表表头

Page 44: 第 7 章 结构体和共用体
Page 45: 第 7 章 结构体和共用体

7.8 7.8 共用体共用体7.8.2 共用体类型的定义定义共用体类型的关键是 “ union” 。同

结构类型的定义方式相似,共用体类型的一般形式为:

union 共用体类型名{ 成员列表 };成员可以是基本数据类型,也可以是数组,指针,以及其他构造类型。

Page 46: 第 7 章 结构体和共用体

union data{char c;int i;float f;};

共用体与结构体不同的是:结构体类型是异址的,而共用体类型是同址的。也就是说,结构体长度是各个成员长度之和,而共用体所有成员共享内存的一个区域(首地址相同),共用体的长度是成员列表中最大长度的成员长度。

Page 47: 第 7 章 结构体和共用体

7.8.3 7.8.3 共用体变量的定义共用体变量的定义 定义类型后说明变量 union data {char c; int i; float f; }; union data u1,u2;

Page 48: 第 7 章 结构体和共用体

7.8.4 7.8.4 共用体变量成员的引用方法共用体变量成员的引用方法 1 ) . 运算符 在一般共用体变量中引用成员也是用 . 运算符 union data u1; u1.i=12; u1.f=3.4; 2 ) -> 运算符 如果共用体变量是指向共用体类型的指针,那

么用 -> 来访问成员。 union data *p; p->i=12; p->f=3.4;

Page 49: 第 7 章 结构体和共用体

【例【例 7.137.13 】演示共用体成员之间】演示共用体成员之间赋值的覆盖形式赋值的覆盖形式

union data {char c; int i; float f; }; void main() { union data u1; u1.c=‘a’; u1.i=65; printf(“%c”,u1.i); } /* 输出结果 :A*/ 程序运行结果可以看出,最后赋值的 f 将覆盖

点先前赋值的变量 i 。

Page 50: 第 7 章 结构体和共用体

7.9  7.9  枚举类型枚举类型 在实际编程中,有些变量的取值被限定在一个

有限的范围内,例如性别只有男、女,一个星期内只有七天,一年只有十二个月等。C语言提供了一种称为“枚举”的构造类型。“枚举”就是将变量可能的值一一列举出来。变量的值只能取列举出来的值之一。应该说明的是,实际上枚举类型的元素为固定的常量的集合。

Page 51: 第 7 章 结构体和共用体

7.9.1 7.9.1  枚举类型的定义 枚举类型的定义 枚举类型定义的一般形式为:

enum 枚举名 { 枚举值表 };

在枚举值表中应罗列出所有可用值,这些值也称为枚举元素。例如: enum COLOR{red,green,blue};

enum WEEKDAY { sun,mou,tue,wed,thu,fri,sat };

Page 52: 第 7 章 结构体和共用体

7.9.27.9.2 枚举变量的说明枚举变量的说明设有变量 a,b,c被说明为上述的 WEEKD

AY ,可采用下述任一种方式:enum WEEKDAY { sun,mou,tue,wed,thu,

fri,sat };在随后的程序中可以以下语句说明 :enum WEEKDAY a,b,c;

Page 53: 第 7 章 结构体和共用体

1.枚举元素不能赋值 . 2.枚举元素本身由系统定义了一个表示

序号的数值,从 0开始顺序定义为 0 , 1 ,2… 。如在 WEEKDAY 中, sun 值为 0 ,mon 值为 1 ,… ,sat 值为 6 。

3.枚举值可以作判断,例如:enum WEEKDAY day; if (day == mon)…. if (day > sun)…

Page 54: 第 7 章 结构体和共用体

7.10 7.10 类型定义符类型定义符 typedeftypedef

C语言不仅提供了丰富的数据类型,而且还允许由用户自己定义类型说明符,也就是说允许由用户为数据类型取别名。关键字 typedef用于为已有的数据类型定义别名(新名),而不是定义新的数据类型。例如:

typedef int INTEGER; typdef unsigned int UINT; 分别为 int 、 unsigned int 定义别名 INTEGE

R 和 UINT , INTEGER代表已有数据类型 int,UINT代表已有数据类型 unsigned int 。

Page 55: 第 7 章 结构体和共用体

典型用法典型用法简化数据类型的书写。   typedef struct person

{  long num;  char name[30];

int age;   char sex;   char address[200]; } TXL, * PTXL;

Page 56: 第 7 章 结构体和共用体

定义标识符 TXL 为 struct person 结构类型的别名, PTXL 为指向 struct person结构指针的别名。定义新的类型说明符后,可用 TXL , PTXL 来说明结构变量:

例如:TXL ab1,ab2;等价于 struct person ab1,ab2;PTXL pab1,pab2;等价于 struct person *pab1,*pab2;

Page 57: 第 7 章 结构体和共用体

考点提示:等级考试大纲要求掌握结构体和共用体类型数据的定义方法和引用方法,用指针和结构体构成链表,单向链表的建立、输出、删除和插入。