第十一章 结构体与共同体

60
第第 第第 第第第第 体体

description

第十一章 结构体与共同体. 本章要点:. 1. 掌握结构和联合类型数据的定义方法和引用方法; 2. 了解枚举类型数据的定义方法和引用方法。. 11.1 概述. 有时,需将不同类型的数据组合成一个有机的整体,以便于引用。这些数据是相互联系的。如一个学生的有关信息:. 可采用结构体数据结构描述上述信息。. 结构体是 一种 构造 数据类型 用途:把 不同类型 的数据组合成一个整体------- 自定义 数据类型 结构体类型定义. struct [ 结构体名] { 类型标识符 成员名; 类型标识符 成员名; ……………. - PowerPoint PPT Presentation

Transcript of 第十一章 结构体与共同体

Page 1: 第十一章    结构体与共同体

第十一章 结构体与共同体

Page 2: 第十一章    结构体与共同体

本章要点: 1. 掌握结构和联合类型数据的定

义方法和引用方法; 2. 了解枚举类型数据的定义方法

和引用方法。

Page 3: 第十一章    结构体与共同体

11.1 概述 有时,需将不同类型的数据组合成一个有机的整体,以便于引用。这些数据是相互联系的。如一个学生的有关信息:

num name sex age addr10010 Li min M 18 Dalian

可采用结构体数据结构描述上述信息。

Page 4: 第十一章    结构体与共同体

结构体是一种构造数据类型 用途:把不同类型的数据组合成一个整体 ------- 自定义数据类型– 结构体类型定义

struct [ 结构体名 ]{ 类型标识符 成员名; 类型标识符 成员名; …………….} ;成员类型可以是基本型或构造型

struct 是关键字 ,不能省略

合法标识符可省 : 无名结构体对各成员都要进行类型说明;成员名定名规则与变量名同。

Page 5: 第十一章    结构体与共同体

例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; };

结构体类型定义描述结构的组织形式 , 不分配内存结构体类型定义的作用域

是类型,不是变量名

Page 6: 第十一章    结构体与共同体

11.2 定义结构体类型变量的方法方法一:先定义结构体类型再定义变量名struct student{int num; char name[20]; char sex; int age; char addr[30];} ;struct student student1, student2;

定义 studet1 和sudent2 为

struct student类型变量

不能只指定一个变量为“ struct 型”而不指定结构体名

Page 7: 第十一章    结构体与共同体

•有时,可用符号常量代表一个结构体类型,如:#define STUDENT struct studentSTUDENT{int num; char name[20]; char sex; int age; char addr[30];};

这样,可直接用 STUDENT定义变量,如:STUDENT student1, student2;此时,不必再写关键字 struct

Page 8: 第十一章    结构体与共同体

方法二:在定义类型的同时定义变量,如:struct student{int num; char name[20]; char sex; int age; char addr[30];}student1, student2;

一般形式是:struct 结构体名 { 成员表列 } 变量名表列;

Page 9: 第十一章    结构体与共同体

方法三:直接定义结构类型变量。其一般形式是:struct { 成员表列 } 变量名表列;

此时,不出现结构体名

用无名结构体直接定义变量只能一次

Page 10: 第十一章    结构体与共同体

几点说明:1. 类型与变量是不同概念,不要混淆;

– 类型 : 不分配内存; 变量 : 分配内存– 类型 : 不能赋值、存取、运算 ; 变量 : 可以

2. 结构体中的成员,可以单独使用,其作用与地位相当于普通变量;3. 结构体可嵌套,成员也可以是一个结构体变量;例如:

struct date {int month; int day; int year; };

Struct student{int num;char name[20];int age;struct date birthday;}student1,student2;

4. 成员名可以与程序中的变量名相同,二者不代表同一对象。

Page 11: 第十一章    结构体与共同体

11.3 结构体类型变量的引用规则:1. 不能将一个结构体变量作为一个整体进行赋值和输出;只能对其各个成员分别输出(引用形式为:结构体变量名 . 成员名 ) 。 错! 正确!2 . 若成员本身又属一个结构体类型,只能对最低级的成员进行赋值或存取以及运算。 如: student1.birthday.year

成员 ( 分量 ) 运算符优先级 : 1结合性 : 从左向右printf(“………..”,student1);printf(“ %d”, student1.num); 输出 10010

Page 12: 第十一章    结构体与共同体

3. 对成员变量可以象普通变量一样进行各种运算,如: sumage=student1.age+student2.age;4. 可以引用成员的地址,也可以引用结构体变量的地址 , 如 scanf(“%d”,& student1.num); printf(“%o”,&student1); scanf(“%d,%s,%c,%d,%s”,&student1); 错!

输入 student1.num 的值输出 student1 的首地址

5. 可以将一个结构体变量赋值给另一个结构体变量例 struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }stu1,stu2;

stu2=stu1; ( )

Page 13: 第十一章    结构体与共同体

11.4 结构体变量的初始化– 形式一:struct 结构体名

{ 类型标识符 成员名; 类型标识符 成员名; …………….} ;struct 结构体名 结构体变量 ={ 初始数据 } ;例 struct student

{ int num; char name[20]; char sex; int age; char addr[30]; }; struct student stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};

Page 14: 第十一章    结构体与共同体

– 形式二:struct 结构体名{ 类型标识符 成员名; 类型标识符 成员名; …………….} 结构体变量 ={ 初始数据 } ;

例 struct student { int num; char name[20]; char sex; int age; char addr[30]; }stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};

Page 15: 第十一章    结构体与共同体

– 形式三:struct{ 类型标识符 成员名; 类型标识符 成员名; …………….} 结构体变量 ={ 初始数据 } ;

例 struct { int num; char name[20]; char sex; int age; char addr[30]; }stu1={112,“Wang Lin”,‘M’,19, “200 Beijing Road”};

Page 16: 第十一章    结构体与共同体

struct student{long int num; char name[20]; char sex; char addr[20];} a={9801,”Wang hong”,’W’,”2 Linggong Road”};

main( ){printf(“No.:%ld\nname:%s\nsex:%c\naddress:%s\n”,

a.num,a.name,a.sex,a.addr);}

运行结果为:No.:9801name:Wang hongsex:Waddress:2 Linggong Road

(一)对外部存储类型的结构体变量初始化:

Page 17: 第十一章    结构体与共同体

(二)对静态存储类型的结构体变量初始化,如:main( )

{static struct student

{long int num;

char name[20];

char sex;

char addr[20];

}a={9801,”Wang hong”,’W’,”2 Linggong Road”};

printf(“No.:%ld\nname:%s\nsex:%c\naddress:%s\n” , a.num,a.name,a.sex,a.addr);

}

Page 18: 第十一章    结构体与共同体

11.5 结构体数组(每个数组元素都是一个结构体类型的数据)( 一)结构体数组的定义,如struct student{int num; char name[20]; char sex; int age; char addr[30];}; struct student stu[3];

也可直接定义,如struct student {int num; … } stu[3];或 struct {int num; … }stu[3];

Page 19: 第十一章    结构体与共同体

(二)结构体数组的初始化struct student{int num; char name[20]; char sex; int age; char addr[30];} stu[3]={{111,”Li”,’M’,18,”Dalian”},{…},{…}};

也可采用: struct student {int num; … }; struct student stu[]={{…},{…},{…}};

结构体数组的初始化的一般形式是在定义数组后面加上:={ 初值表列 } ;

Page 20: 第十一章    结构体与共同体

例题:设有三个候选人,每次输入一个得票的候选人的名字,要求最后输出各人得票结果。struct person { char name[20]; int count; }leader[3]={“Li”,0,”zhang”,0,”Liu”,0};

main( ){ int i, j; char leader_name[20]; for( i=1;i<=10;i++) { scanf(“%s”,leader_name); for(j=0;j<3;j++) if(strcmp(leader_name,leader[j].name)= =0)leader[j].count++); } for(i=0;i<3;i++) printf(“%5s:%d\n”,leader[i].name,leader[i].count); }

应用方式:结构体数组名 [ 下标 ]. 成员名

name count

Li

Zhang

Wang

0

0

0

Page 21: 第十一章    结构体与共同体

11.6 指向结构体类型数据的指针结构体变量的指针:是该结构体变量所占居的内存段的起始地址。例如:main( ){struct student {long int num; char name[20]; char sex; };struct student stu_1;struct student *p;p=&stu_1 ;

stu.num=9901;strcpy(stu_1.name,”Li Min”);stu_1.sex=‘W’;printf(“No.:%ld\nname%s\nsex:%c\n”,stu_1.num,stu_1.name,stu_1.sex);printf(“\nNo.:%ld\nname%s\nsex:%c\n”,(*p).num,(*p).name,(*p).sex);}

Page 22: 第十一章    结构体与共同体

引用结构体成员的三种形式: 结构体变量名 . 成员名 (*p). 成员名 p- > 成员名 : 直观,表示 *p 所指向的结构变量中的成员 printf(“\nNo.:%ld\nname%s\nsex:%c\n”,p->num, p-> name, p->sex);

指向运算符。其优先级高于自增、自减运算符

试分析以下运算:p->n 得到 p 指向的结构体变量中的成员 n 的值p->n++ 得到 p 指向的结构体变量中的成员 n 的值, 用完后使它加 1 ;++p->n 得到 p 指向的结构体变量中的成员 n 的值 使其先加 1

Page 23: 第十一章    结构体与共同体

– 指向结构体数组的指针例 指向结构体数组的指针struct student{ int num; char name[20]; char sex; int age;}stu[3]={{10101,"Li Lin",'M',18}, {10102,"Zhang Fun",'M',19},

{10104,"Wang Min",'F',20}};main(){ struct student *p; for(p=stu;p<stu+3;p++) printf("%d%s%c%d\n",p->num,p->name,p->sex,p->age);}

numnamesexage

stu[0]

p

stu[1]

stu[2]

p+1

Page 24: 第十一章    结构体与共同体

– 用指向结构体的指针作函数参数» 用结构体变量的成员作参数 ---- 值传递» 用指向结构体变量或数组的指针作参数 ---- 地

址传递» 用结构体变量作参数 ---- 多值传递,效率低

Page 25: 第十一章    结构体与共同体

struct data{ int a, b, c; };main(){ void func(struct data); struct data arg; arg.a=27; arg.b=3; arg.c=arg.a+arg.b; printf("arg.a=%d arg.b=%d arg.c=%d\n",arg.a,arg.b,arg.c); printf("Call Func()....\n"); func(arg); printf("arg.a=%d arg.b=%d arg.c=%d\n",arg.a,arg.b,arg.c);}void func(struct data parm){ printf("parm.a=%d parm.b=%d parm.c=%d\n",parm.a,parm.b,parm.c); printf("Process...\n"); parm.a=18; parm.b=5; parm.c=parm.a*parm.b; printf("parm.a=%d parm.b=%d parm.c=%d\n",parm.a,parm.b,parm.c); printf("Return...\n");}

arga :27b: 3c :30

(main)

(func)

parma :27b: 3c :30

copy

arga :27b: 3c :30

(main)

(func)

parma :18b: 5c :90

arga :27b: 3c :30

(main)

arga :27b: 3c :30

(main)例 用结构体变量作函数参数

Page 26: 第十一章    结构体与共同体

struct data{ int a, b, c; };main(){ void func(struct data *parm); struct data arg; arg.a=27; arg.b=3; arg.c=arg.a+arg.b; printf("arg.a=%d arg.b=%d arg.c=%d\n",arg.a,arg.b,arg.c); printf("Call Func()....\n"); func(&arg); printf("arg.a=%d arg.b=%d arg.c=%d\n",arg.a,arg.b,arg.c);}void func(struct data *parm){ printf("parm->a=%d parm->b=%d parm->c=%d\n",parm->a,parm->b,parm->c); printf("Process...\n"); parm->a=18; parm->b=5; parm->c=parm->a*parm->b; printf("parm->a=%d parm->b=%d parm->c=%d\n",parm->a,parm->b,parm->c); printf("Return...\n");}

arga :18b: 5c :90

(main)

arga :27b: 3c :30

(main)例 用结构体指针变量作函数参数

arga :27b: 3c :30

(main)

(func)parm****

arga :18b: 5c :90

(main)

(func)parm****

Page 27: 第十一章    结构体与共同体

11.7 用指针处理链表 链表概述

– 一种数据结构:相互之间存在一种或者多种特定关系的数据元素的集合。» 顺序存储结构:数据元素在存储单元中顺序存储,数组» 非顺序存储结构——链式结构:借助指示数据元素存储地址的指针来表示数据元素的逻辑关系,在内存单元随机存储,链表

1356A

1475B

1021C

NUllD

1249

head 1249 1356 1475 1021

Page 28: 第十一章    结构体与共同体

1356A

1475B

1021C

NUllD

1249

head 1249 1356 1475 1021

简单链表介绍:头指针: head 表示,存放地址,该地址指向链表的第一个元素结点: 链表中的每个元素,每个结点包括用户的实际数据和 指向下一个结点的指针表尾: 最后一个结点,地址部分放一个“ NULL” 指针。几点说明:1 、链表中的各元素在内存中不是连续存放的,必须先找到上一个元素,根据其提供的地址才能找到下一个元素。2 、利用结构体变量最为链表中的结点。

Page 29: 第十一章    结构体与共同体

建立和输出一个简单链表do {printf("%ld %5.1f\n",p->num,p->score); p=p->next; }while(p!=NULL);}

#define NULL 0struct student{long num; float score; struct student *next;};main(){struct student a,b,c,*head,*p; a.num=99101;a.score=89.5; b.num=99103;b.score=90; c.num=99107;c.score=85; head=&a; a.next=&b; b.next=&c; c.next=NULL; p=head;

本例式比较简单的,所有结点在程序中定义了,不是临时开辟的,用完也不能释放,这种链表成为“静态链表”。还有一种是动态链表——动态分配内存

Page 30: 第十一章    结构体与共同体

动态存储分配 在数组一章中,曾介绍过数组的长度是预先定义好的, 在整个程序中固定不变。C语言中不允许动态数组类型。例如: int n; scanf("%d",&n); int a[n]; 用变量表示长度,想对数组的大小作动态说明,这是错误的。但是在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定。对于这种问题,用数组的办法很难解决。 为了解决上述问题,利用动态链表解决这个问题。C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态地分配内存空间给结点,也可把不再使用的结点空间回收待用,为有效地利用内存资源提供了手段。

Page 31: 第十一章    结构体与共同体

1. 分配内存空间函数malloc 调用形式: (类型说明符 *) malloc (size) 功能:在内存的动态存储区中分配一块长度为“ size” 字节的连续区域。函数的返回值为该区域的首地址。“类型说明符”表示把该区域用于存储何种数据类型。 (类型说明符 *)表示把返回值强制转换为该类型指针。“ size” 是一个无符号数。 例如: pc=(char *) malloc (100); 表示分配 100个字节的内存空间,并强制转换为字符数组类型,函数的返回值为指向该字符数组的指针,把该指针赋予指针变量 pc。

Page 32: 第十一章    结构体与共同体

2.分配内存空间函数 calloc calloc 也用于分配内存空间。 调用形式: (类型说明符 *)calloc(n,size) 功能:在内存动态存储区中分配 n 块长度为“ size” 字节的连续区域。函数的返回值为该区域的首地址。 (类型说明符 *)用于强制类型转换。 calloc 函数与malloc 函数的区别仅在于一次可以分配 n块区域。 例: ps=(struet stu*) calloc(2,sizeof (struct stu)); 其中的 sizeof(struct stu)是求 stu的结构长度。因此该语句的意思是:按 stu的长度分配 2块连续区域,强制转换为 stu类型,并把其首地址赋予指针变量 ps。

Page 33: 第十一章    结构体与共同体

3. 释放内存空间函数 free 调用形式: free(void*ptr); 功能:释放 ptr所指向的一块内存空间, ptr 是一个任意类型的指针变量,它指向被释放区域的首地址。被释放区应是由malloc或 calloc函数所分配的区域:

main(){ struct stu { int num; char *name; char sex; float score; } *ps; ps=(struct stu*)malloc(sizeof(struct stu)); ps->num=102; ps->name="Zhang ping"; ps->sex='M'; ps->score=62.5;

printf("Number=%d\nName=%s\n",ps->num,ps->name);printf("Sex=%c\nScore=%f\n",ps->sex,ps->score); free(ps); }

Page 34: 第十一章    结构体与共同体

动态链表的作用: 如在学籍管理,有多少个学生就应该申请分配多少块内存空间,也就是说要建立多少个结点。当然用结构数组也可以完成上述工作,但如果预先不能准确把握学生人数,也就无法确定数组大小。而且当学生留级、退学之后也不能把该元素占用的空间从数组中释放出来。用动态链表的方法可以很好地解决这些问题。有一个学生就分配一个结点,无须预先确定学生的准确人数,某学生退学可删去该结点,并释放该结点占用的存储空间。从而节约了宝贵的内存资源。另一方面,用数组的方法必须占用一块连续的内存区域。 而使用动态链表时,每个结点之间可以是不连续的 (结点内是连续的 )。

Page 35: 第十一章    结构体与共同体

链表的基本操作,对链表的主要操作有以下几种: 1. 建立链表;2.结构的查找与输出;3.插入一个结点;4.删除一个结点; 下面通过例题来说明这些操作。建立一个三个结点的链表,存放学生数据。为简单起见,我们假定学生数据结构中只有学号和年龄两项。可编写一个建立链表的函数 creat。程序如下: #define NULL 0 #define TYPE struct stu #define LEN sizeof (struct stu) struct stu { int num; int age; struct stu *next; };

Page 36: 第十一章    结构体与共同体

1249i=0

1. 建立链表TYPE *creat(int n)/* 定义函数,该函数返回指向链表头的指针 */ { struct stu *head,*pf,*pb; /* 定义三个指向结构体指针 */ int i; for(i=0;i<n;i++) { pb=(TYPE*) malloc(LEN); /*开辟内存单元并将首地址赋给指针 pb*/ printf("input Number and Age\n"); scanf("%d%d",&pb->num,&pb->age); if (i==0) pf=head=pb; else pf->next=pb; pb->next=NULL; pf=pb; } return(head); }

001

19

pb

head

pf null

i=11356002

20null

pb

i=21021003

19null1021

pb

pf pf1021

Page 37: 第十一章    结构体与共同体

在函数外首先用宏定义对三个符号常量作了定义。这里用 TYPE表示 struct stu ,用 LEN 表示 sizeof(struct stu) 主要的目的是为了在以下程序内减少书写并使阅读更加方便。结构 stu 定义为外部类型,程序中的各个函数均可使用该定义。creat 函数用于建立一个有 n个结点的链表,它是一个指针函数,它返回的指针指向 stu 结构。在 creat 函数内定义了三个 stu 结构的指针变量。 head 为头指针, pf 为指向两相邻结点的前一结点的指针变量。 pb 为后一结点的指针变量。在 for 语句内,用 malloc 函数申请 LEN 长度(与 stu 长度相等)的空间作为一结点,首地址赋予 pb。然后输入结点数据。如果当前结点为第一结点 (i==0) ,则把 pb 值 ( 该结点指针 ) 赋予 head 和 pf 。如非第一结点,则把 pb 值赋予 pf 所指结点的指针域成员 next 。而 pb 所指结点为当前的最后结点,其指针域赋 NULL 。 再把 pb值赋予 pf以作下一次循环准备。creat 函数的形参 n ,表示所建链表的结点数,作为 for 语句的循环次数。

Page 38: 第十一章    结构体与共同体

2. 结构的查找TYPE * search (TYPE *head,int n){ TYPE *p; int i; p=head; while (p->num!=n && p->next!=NULL) p=p->next; /* 不是要找的结点后移一步 */ if (p->num==n) return (p); if (p->num!=n&& p->next==NULL) { printf ("Node %d has not been found!\n",n); return NULL; }} 本函数中使用的符号常量 TYPE等于 struct stu 。函数有两个形参, head 是指向链表的指针变量, n 为要查找的学号。进入 while语句,逐个检查结点的 num 成员是否等于 n ,如果不等于 n且指针域不等于 NULL( 不是最后结点 ) 则后移一个结点,继续循环。如找到该结点则返回结点指针。 如循环结束仍未找到该结点则输出“未找到”的提示信息。

20001

1249

135619002

1356

147520003

1475

1021

18004

1021

null

head

p p p p

Page 39: 第十一章    结构体与共同体

3. 删除链表中的指定结点 删除一个结点有两种情况:1). 被删除结点是第一个结点。这种情况只需使 head 指向第二个结点 即可。即 head=pb->next 。2). 被删结点不是第一个结点,这种情况使被删结点的前一结点指向 被删结点的后一结点即可。即 pf->next=pb->next 。编程如下:TYPE * delete(TYPE * head,int num){ TYPE *pf,*pb; if(head==NULL) /* 如为空表, 输出提示信息 */ { printf("\n Empty list!\n"); goto end;} pb=head; while (pb->num!=num && pb->next!=NULL) /* 当不是要删除的结点,而且也不是最后一个结点时,继续循环 */

Page 40: 第十一章    结构体与共同体

{pf=pb;pb=pb->next;} /*pf 指向当前结点, pb 指向下一结点 */if(pb->num==num) {if(pb==head) head=pb->next; /* 如找到被删结点,且为第一结点,则使 head 指向第二个结点,否则使 pf 所指结点的指针指向下一结点 */ else pf->next=pb->next; free(pb); printf("The node is deleted\n");} else printf("The node not been foud!\n");end: return head;}

20001

1249

135619002

1356

147520003

1475

1021

18004

1021

null

head

pb pbpf pbpf

1021

Page 41: 第十一章    结构体与共同体

4. 在链表中指定位置插入一个结点 在一个链表的指定位置插入结点,要求链表本身必须是已按某

种规律排好序的。例如,在学生数据链表中,要求学号顺序插入一个结点。设被插结点的指针为 pi, 在三种不同情况下插入。

1).原表是空表,只需使 head 指向被插结点即可。2). 被插结点值最小,应插入第一结点之前。这种情况下使 head 指

向被插结点,被插结点的指针域指向原来的第一结点则可。即: pi->next=pb; head=pi;

3). 在其它位置插入。这种情况下使插入位置的前一结点的指针域指向被插结点 , 使被插结点的指针域指向插入位置的后一结点。即为: pi->next=pb; pf->next=pi ;

4). 在表末插入。这种情况下使原表末结点指针域指向被插结点,被插结点指针域置为 NULL 。即: pb->next=pi;pi->next=NULL ;

Page 42: 第十一章    结构体与共同体

TYPE * insert(TYPE * head,TYPE *pi) { TYPE *pf,*pb; pb=head; if(head==NULL) /*空表插入 */ {head=pi; pi->next=NULL;} else { while((pi->num > pb->num) && (pb->next!=NULL)) /*大于某一结点,且该结点不是最后一个结点,即循环在此末结点 */ {pf=pb; pb=pb->next; } /* 找插入位置,指针 pf 、 pb 后移 */ if(pi->num <= pb->num) {if(head==pb) head=pi; /* 在第一结点之前插入 */ else pf->next=pi; /* 在其它位置插入 */ pi->next=pb; } else {pb->next=pi; pi->next=NULL;} /* 在表末插入 */ } return head;}

Page 43: 第十一章    结构体与共同体

将以上建立链表,删除结点,插入结点的函数组织在一起,再建一个输出全部结点的函数,然后用 main函数调用它们。void print(TYPE * head){ printf("Number\t\tAge\n"); while(head!=NULL) { printf("%d\t\t%d\n",head->num,head->age); head=head->next; }}

Page 44: 第十一章    结构体与共同体

main(){ TYPE * head,*pnum; int n,num; printf("input number of node: "); scanf("%d",&n); head=creat(n); print(head); printf("Input the deleted number: "); scanf("%d",&num); head=delete(head,num); print(head); printf("Input the inserted number and age: "); pnum=(TYPE *)malloc(LEN); scanf("%d%d",&pnum->num,&pnum->age); head=insert(head,pnum); print(head);}

Page 45: 第十一章    结构体与共同体

11.8 共用体11.8.1 共用体的概念共用体:使几个不同的变量共占同一段内存的结构,称为“共用体”类型的结构。“ 共用体”类型变量的定义形式为:

union 共用体名{ 类型标识符 成员名; 类型标识符 成员名; …………….} ;

例 union data { int i; char ch; float f; }; f

ch

i

类型定义不分配内存

Page 46: 第十一章    结构体与共同体

形式一 : union data { int i; char ch; float f; }a,b;

形式二 : union data { int i; char ch; float f; }; union data a,b,c,*p,d[3];

形式三 : union { int i; char ch; float f; }a,b,c;

– 共用体变量的定义

fch

i

fch

i

a b

共用体变量定义分配内存 ,长度 =最长成员所占字节数共用体变量任何时刻只有一个成员存在

Page 47: 第十一章    结构体与共同体

– 共用体变量引用» 引用方式:

例 a.i=1; a.ch=‘a’; a.f=1.5; printf(“%d”,a.i); ( 编译通过,运行结果不对 )

» 引用规则 不能引用共用体变量,只能引用其成员

共用体指针名 -> 成员名共用体变量名 . 成员名 (* 共用体指针名 ). 成员名union data { int i; char ch; float f; }; union data a,b,c,*p,d[3];

a.i a.ch a.f

p->i p->ch p->f

(*p).i (*p).ch (*p).f

d[0].i d[0].ch d[0].f

共用体变量中起作用的成员是最后一次存放的成员例 union { int i; char ch; float f; }a; a=1; ()

不能在定义共用体变量时初始化例 union { int i; char ch; float f; }a={1,’a’,1.5}; ()

可以用一个共用体变量为另一个变量赋值例 float x; union { int i; char ch; float f; }a,b; a.i=1; a.ch=‘a’; a.f=1.5; b=a; () x=a.f; ()

Page 48: 第十一章    结构体与共同体

例 将一个整数按字节输出

01100001 01000001低字节高字节

0100000101100001

ch[0]

ch[1]

运行结果:i=60501ch0=101,ch1=141ch0=A,ch1=a

main(){ union int_char { int i; char ch[2]; }x; x.i=24897; printf("i=%o\n",x.i); printf("ch0=%o,ch1=%o\n ch0=%c,ch1=%c\n",

x.ch[0],x.ch[1],x.ch[0],x.ch[1]);}

Page 49: 第十一章    结构体与共同体

– 结构体与共用体»区别: 存储方式不同

struct node{ char ch[2]; int k;}a;

union node{ char ch[2]; int k;}b;

achk

bch k

变量的各成员同时存在

任一时刻只有一个成员存在

»联系 : 两者可相互嵌套结构体类型变量所占内存长度是各成员内存长度之和。共用体类型变量所占内存长度等于最长的成员的长度。

Page 50: 第十一章    结构体与共同体

例 结构体中嵌套共用体 name num sex job classposition

Li

Wang

1011

2086

F

M

S

T

501

prof

循环 n 次读入姓名、号码、性别、职务

job==‘s’真真 假

假读入 class 读入

position输出“ 输入错”

循环 n 次job==‘s’真 假

输出 : 姓名 , 号码 ,性别 , 职业 , 班级输出 : 姓名 , 号码 ,性别 , 职业 , 职务

job==‘t’

struct{ int num; char name[10]; char sex; char job; union { int class; char position[10]; }category;}person[2];

Page 51: 第十一章    结构体与共同体

main(){int n,i; for(i=0;i<2;i++) {scanf("%d %s %c %c", &person[i].num, person[i].name, &person[i].sex,&person[i].job); if (person[i].job=='s') scanf("%d",&person[i].category.class); else if (person[i].job=='t') scanf("%s",person[i].category.position); else printf("Input error!"); } printf("\n"); printf("No. Name sex job class/position\n");

Page 52: 第十一章    结构体与共同体

for(i=0;i<2;i++) {if (person[i].job=='s') printf("%-6d %-10s %-3c %-3c %-6d\n", person[i].num, person[i].name, person[i].sex, person[i].job,person[i].category.class); else printf("%-6d %-10s %-3c %-3c %-6s\n", person[i].num, person[i].name, person[i].sex, person[i].job, person[i].category.position); }}

Page 53: 第十一章    结构体与共同体

例共用体中嵌套结构体,机器字数据与字节数据的处理 00010010 00110100

低字节高字节

0011010000010010

low

high

0x1234

00010010 11111111低字节高字节

1111111100010010

low

high

0x12ff

struct w_tag{ char low; char high;};union u_tag{ struct w_tag byte_acc; int word_acc;}u_acc;

word_accbyte_acc.lowbyte_acc.high

u_acc

Page 54: 第十一章    结构体与共同体

11.8.2 共用体类型数据的特点1. 每一瞬时只有一个成员起作用 ;2. 共用体变量中起作用的成员是最后一次存放的成员;3. 共用体变量的地址和它的各成员的地址都是同一地址;4. 不能对共用体变量名赋值,也不能企图引用变量名来

得到成员的值,又不能在定义共用体变量时对它初始化。5. 不能把共用体变量作为函数参数,也不能使函数带回

共用体变量,但可使用指向共用体变量的指针;6. 共用体类型可以出现在结构体类型定义中,也可以定义

共用体数组。而结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。

Page 55: 第十一章    结构体与共同体

11.9 枚举类型 若一个变量只有几种可能的值,可以定义为枚举类型。所谓“枚举”是指将变量的值一一列举出来,变量的值只限于列举出来的值的范围内。 定义方法:先定义枚举类型 enum weekday {sun, mon, tue, wed, thu, fri, sat};再用此类型定义变量,如:enum weekday workday, week_end;或直接定义枚举变量。如:enum weekday {sun, mon, tue, wed, thu, fri, sat} workday,week_end;

Page 56: 第十一章    结构体与共同体

说明: 枚举元素为常量,不是变量,故不能对它们赋值 枚举常量有值。如上面定义中, sun 、 mon 、 tu

e ······ sat 的值依次为 0 、 1 、 2······7 也可改变枚举元素的值,在定义时指出,如: enum weekday{sun=7,mon=1,tue,wed,thu,fri,sat}; 枚举值可用来作判断比较,如: if(workday==mon) if(workday>sun) 一个整数不能直接赋值给一个枚举变量,应先进行强制类型转换才能赋值,如: workday=(enum weekday)2; ( 相当于将序号为 2 的枚举元素值赋给 workday , 即: workday=tue;

Page 57: 第十一章    结构体与共同体

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; case 2:pri=j;break; case 3:pri=k;break; default:break; }

switch(pri)

{case red: printf("%-10s","red"); break;

case yellow:printf("%-10s","yellow"); break;

case blue: printf("%-10s","blue");break;

case white: printf("%-10s","white"); break;

case black: printf("%-10s","black"); break ;default: break;} }

printf("\n"); } }}

Page 58: 第十一章    结构体与共同体

功能:用自定义名字为已有数据类型命名– 类型定义简单形式: typedef type name;

例 typedef int INTEGER;类型定义语句关键字已有数据类型名用户定义的类型名例 typedef float REAL;

类型定义后 ,与已有类型一样使用

例 INTEGER a,b,c; REAL f1,f2;

int a,b,c; float f1,f2;

说明 :1.typedef 没有创造新数据类型2.typedef 是定义类型 ,不能定义变量3.typedef 与 define 不同 define typedef预编译时处理 编译时处理简单字符置换 为已有类型命名

11.10 用 typedef定义类型

Page 59: 第十一章    结构体与共同体

– typedef 定义类型步骤按定义变量方法先写出定义体 如 int i; 将变量名换成新类型名 如 int INTEGER; 最前面加 typedef 如 typedef int INTEGER; 用新类型名定义变量 如 INTEGER i,j;

例 定义数组类型 int a[100]; int ARRAY[100]; typedef int ARRAY[100]; ARRAY a,b,c;

int a[100],b[100],c[100];

例 定义指针类型 char *str; char *STRING; typedef char *STRING; STRING p,s[10];

char *p; char *s[10];

例 定义函数指针类型 int (*p)(); int (*POWER)(); typedef int (*POWER)(); POWER p1,p2;

int (*p1)(),(*p2)();

例 定义结构体类型 struct date { int month; int day; int year; }d;

例 定义结构体类型 struct date { int month; int day; int year; }DATE;

例 定义结构体类型typedef struct date { int month; int day; int year; }DATE;

例 定义结构体类型 DATE birthday, *p;

struct date { int month; int day; int year; }birthday, *p;

– 类型定义可嵌套例 typedef struct club { char name[20]; int size; int year; }GROUP; typedef GROUP *PG; PG pclub;

GROUP *pclub; struct club *pclub;

GROUP 为结构体类型PG为指向 GROUP 的指针类型

Page 60: 第十一章    结构体与共同体

本章小结 1. 结构和联合是两种构造类型数据,是用户定义新数据类型的重要手段。结构和联合有很多的相似之处,它们都由成员组成。成员可以具有不同的数据类型。成员的表示方法相同。都可用三种方式作变量说明。2. 在结构中,各成员都占有自己的内存空间,它们是同时存在的 一个结构变量的总长度等于所有成员长度之和。在联合中,所有 成员不能同时占用它的内存空间,它们不能同时存在。联合变量 的长度等于最长的成员的长度。3. “.” 是成员运算符,可用它表示成员项,成员还可用“ ->” 运 算符来表示。4. 结构变量可以作为函数参数,函数也可返回指向结构的指针变量。而联合变量不能作为函数参数,函数也不能返回指向联合的指针变量。但可以使用指向联合变量的指针,也可使用联合数组。5. 结构定义允许嵌套,结构中也可用联合作为成员,形成结构和联合的嵌套。6. 链表是一种重要的数据结构,它便于实现动态的存储分配。本章介绍是单向链表,还可组成双向链表,循环链表等。