
第十一章结构类型数据描述.ppt
45页第11章 构造类型数据描绘11.1结构体11.2共用体11.3枚举类型11.4用 typedef 定义类型名11.5位段结构第11章 构造类型数据描绘 这种多项组合又有内在联络的的数据称为构造体(structure)它是可以由用户自己定义的11.1 构造体 在实际应用中,有时需要将一些有互相联络而类型不同的数据组合成一个有机的整体,以便于引用如学生学籍档案中的学号、姓名、性别、年龄、成绩、地址等数据,对每个学生来说,除了其各项的值不同外,但表示形式是一样的numnamesexagescoreAddr10010Li FunF1887.5Beijing1. 概述2. 构造体类型变量的定义两者缺一不可1) 构造体类型的定义形式struct 构造体名 分量表 ;其中“分量表中的分量也应进展类型说明,例如:struct student int num; char name20; char sex; int age; float score; char addr30; ;即:类型标识符 分量名;分量描绘 由用户定义的“构造体类型,可以同标准类型一样作为定义变量的类型相当于PASCAL语言中的记录(record)。
2) 定义构造体类型变量的方法 先定义构造体类型再定义变量 定义了构造体类型 struct student 后,可以用它定义变量注:不能写成 struct st1,st2; 必须同时指定构造体名 为了方便起见,可以在程序开头定义符号常量进展简化如:如:struct student st1, st2;那么在程序中可以直接写成:STUDENT int num; char name20; char sex; int age; float score; char addr30;#define STUDENT struct studentSTUDENT st1, st2; 在定义类型的同时定义变量如:struct student int num; char name20; char sex; int age; float score; char addr30;st1,st2;struct 构造体名 分量表; 变量表;那么一般定义形式为: 直接定义构造类型变量定义形式为:struct 分量表; 变量表; 在 struct 后不出现构造体名,因此也不能再以此定义一样的构造体变量3关于构造体类型的几点说明 类型与变量是两个不同的概念。
一般先定义构造体类 型,再定义变量为该类型变量可以赋值、存取或运 算,而类型没有这些操作在编译时,对变量分配空 间,对类型来说不存在分配空间 对构造体中的分量可以单独使用 分量也可以是一个构造体变量如 student 中要增加 birthday,那么可按如下方式进展定义:struct date int month; int day; int year; ;struct student struct date birthday; st1, st2;先定义一个日期构造该分量也是一个构造体 分量名可以与程序中的变量名一样,两者之间不会产生混淆4. 构造体类型变量的引用引用构造体变量应遵守如下规那么:1) 构造体变量中分量的引用方式构造体变量名 分量名 二级分量名 其中:“为分量运算符, 在所有的运算符中优先级最高2) 构造体变量的分量本身又属于构造体类型时只能对最 低级分量进展操作如:st1.num;st1.name;st1.birthday.day;写成 st1.birthday 并不会访问st1中的birthday,只会引起警告错误3) 不能将一个构造体变量直接进展输入输出,只能对结 构体变量的各分量进展输入输出。
如:scanf(“%d,%s,%c,%d,%f,%s,&st1);错误printf(“%d,%s,%c,%d,%f,%s,st1);错误printf(“%s,%d,st1.name,st1.birthday.day);正确4) 分量和构造体变量的地址均可以被引用如:scanf(“%d,&st1.num);输入st1.num的值printf(“%x,&st1);以十六进制输出st1的首地址5. 构造体变量的初始化1) 外部存储类的构造体变量初始化例11.1struct studentlong int num; char name20; char sex; char addr30;a=89031,“Li Lin,M,“123 Beijing Road;main( ) printf(“%ld,%s,%c,%sn,a.num,a.name,a.sex,a.addr);输出结果:89031,Li Lin,M,123 Beijing Road定义结构体的同时定义变量 a 并进行初始化2) 静态存储类的构造体变量初始化main( )struct student long int num; char name20; char sex; char addr30; a=89031,“Li Lin,M,“123 Beijing Road; printf(“%ld,%s,%c,%sn,a.num,a.name,a.sex,a.addr);可以将定义部分放在main函数中6. 构造体数组 构造体数组与普通数组的不同之处在于每个数组元素都是一个构造体类型的数据,且这些数据又分别包括各个分量。
构造体数组的定义、初始化等操作和内存中的存放方式与普通数组相类似7 指向构造体类型数据的指针 同普通变量一样,也可以定义一个指针变量指向一个构造体变量,那么此时该指针变量的值是构造体变量的起始地址指针变量也可以用来指向构造体数组中的元素,同样也可以用指向构造体的指针作函数参数例11.11 用指向构造体的指针作函数参数#include “string.hmain( ) struct student long int num; char name20; char sex; float score; ; struct student stu; struct student *p; p=&stu; stu.num=89101; strcpy(stu.name,“Li Lin ); stu.sex=M; stu.score=89.5; printf(“No.:%dnname:%snsex:%cnscore:%f n, stu.num,stu.name,stu.sex,sru.score); printf(“nNo.:%dnname:%snsex:%cnscore:%f n, (*p).num,(*p).name,(*p).sex,(*p).score);注意这里的引用格式,也可写成pnum, 。
若写成p.num, 或 *p.num, 则是错误的注意: (*p) 表示 p 指向的构造体变量,不得省去括号而 *p.num 等价于 *(p.num) 称为指向运算符 (*p).num可写成 pnum,使之直观,余类推 构造体变量 分量名、(*p) 分量名、p分量名,三 者是等价的 pn 得到 p 指向的构造体变量中的分量 n 的值 pn+ 得到 p 指向的构造体变量中的分量 n 的值, 用完该值后加1 +pn 得到 p 指向的构造体变量中的分量 n 的值, 并在用该值前先加18 动态数据构造 静态数据构造 (例如数组) 占据内存空间的位置和大小是在它们被说明的同时由系统分配的, 在程序运行期间是不变的, 因此可以有效地访问它们的任何一个元素但要删除和插入一个元素那么比较困难, 往往要引起大量的数据挪动而且数据量的扩大更受到它们所占用的有限内存空间的限制C 中的动态数据构造有效地解决了这一问题 动态数据构造中最根本的形式是链表和二叉树, 它们在数据处理中起着非常重要的作用动态数据构造中的每个组成数据在逻辑上是连续排列的,但在物理上即在内存中存储时并不占用连续的内存空间,它们可以根据需要随机地增加或减少其元素, 相应地占用或释放内存空间。
1. 动态存储分配C语言实现动态存储分配的函数: malloc(size) 在内存的动态存储区中分配一个结点长度为size的连续存储空间,并返回一个指向其起始地址的指针,假设分配不成功,那么返回值为0size为整型 calloc(n, size) 在内存的动态存储区中分配 n个结点长度为size的连续存储空间,并返回一个指向其起始地址的指针,假设分配不成功,那么返回值为0n、size为整型 free(ptr) 释放由指针ptr所指向的存储空间ptr是最近一次调用malloc 或calloc函数或链表指针返回的值ptr 为字符型指针2. 链表1) 链表概念 单向链表是按照输入数据的顺序建立的它有一个 “头指针 (图中为 head ),指向第一个元素;每一个元素称为“结点,每个结点包括两个域:数据域和指向下一个结点的指针域;最后一个元素的指针域为“NULL(“空地址),表示链表的完毕,称为“表尾headABBCENULL 链表是一种常见的动态地进展存储分配的数据结构链表有 “单向链表、“双向链表、“循环链表、“双向循环链表之分以下图是一个“单向链表的例如2) 建立链表例11.12 链表的建立和遍历(队列)#define NULL 0#define LEN sizeof(struct node)struct node int data; struct node *next; main( ) struct node *head, *rear, *p; int n=0; p=(struct node *)malloc(LEN); pdata=n+1; head=rear=p; for (n=1; ndata=n+1; rearnext=p; rear=p; rearnext=NULL; p=head; while (p != NULL) printf(“%3d,pdata); p=pnext; 恢复指针head12345678910ppppppppp0rearprear rearrearrearrear rear rear rearrear例11.13 链表的建立和遍历(栈)#define NULL 0#define LEN sizeof(struct node)struct node int data; struct node *next; main( )struct node *base, *p; int n; base = NULL ; for (n = 0; ndata = n +1; pnext = base ; base = p; p = base; while ( p ! = NULL ) printf(“%3d,pdata); p = pnext; 102345678910pbase输出结果:10 9 8 7 6 5 4 3 2 1恢复指针3) 删除链表元素例11.14 删除链表中指定的结点。
struct node *delete(head, data)struct node *head;int data; struct node *p1, *p2; if (head != NULL) p1 = head ; while (p1data != data & p1next != NULL) p2 = p1; p1 = p1next; if (p1data = = data) if (p1= = head) head = p1next; else p2next = p1next; printf(“deleted: %dn,data); n = n 1; else printf(“%d not been found!n, data); return(head);p1p2p1p2p1p2p1p2p1123456789100prearhead4) 链表的插入操作例11.15 在链表中插入一个新结点struct node *inse。
