第四章高级数据类型.ppt

上传人:本田雅阁 文档编号:3459282 上传时间:2019-08-28 格式:PPT 页数:54 大小:288.54KB
返回 下载 相关 举报
第四章高级数据类型.ppt_第1页
第1页 / 共54页
第四章高级数据类型.ppt_第2页
第2页 / 共54页
第四章高级数据类型.ppt_第3页
第3页 / 共54页
第四章高级数据类型.ppt_第4页
第4页 / 共54页
第四章高级数据类型.ppt_第5页
第5页 / 共54页
点击查看更多>>
资源描述

《第四章高级数据类型.ppt》由会员分享,可在线阅读,更多相关《第四章高级数据类型.ppt(54页珍藏版)》请在三一文库上搜索。

1、第四章 高级数据类型,类型定义语句,前面我们学习了Pascal语言的5种标准数据类型:整型、实型、字符型、字符串型以及布尔型,这些数据类型无需声明定义即可在程序中直接使用。而解决实际问题,还需要其他数据类型,这些都属于用户自定义的数据类型,属于高级数据类型。这些数据类型必须在使用之前用语句进行定义。 高级数据类型主要有:枚举类型、子界类型、集合类型、数组、记录类型、指针类型,类型定义语句,类型定义语句的语法格式为: type =; =; =; 其中保留字type表示类型定义段的开始。是用户为自定义类型取的名称,是用户定义的数据类型名,既可以是Object Pascal语言的标准数据类型,也可以

2、是Object Pascal语言的高级数据类型。,枚举类型,在处理诸如物体的颜色、人的职业、教师的职称等非数值数据时,可以用数值或字符串来表示,比如用1表示红色,2表示黄色;或用“red”表示红色,“yellow”表示黄色。但这样的表示都存在一些缺点:使用数值表示很不直观,特别当表示的种类较多时容易引起混乱和错误,使用字符串则需要占用较多的内存。 仔细分析这些数据,可知这些数据的个数总是有限的,而且可以一一列举。为此,Object Pascal提供的用户自定义数据类型枚举类型,可以很方便地处理这类数据。,枚举类型,type 枚举类型标识符(标识符1,标识符n); 例如: type daytyp

3、e=(sun,mon,tue,wed,thu,fri,sat); 注意: 1、括号内为枚举元素,是该类型数据的所有取值,又称枚举常量。但枚举元素只能是标识符(字母开头的字母数据串),而不能是数值常量或字符常量。 例如以下的定义是错误的: type daytype1=(sun,mon,tue,wed,thu,fri,sat); 2、不要把作为枚举元素的标识符视作变量名,它不能被赋值。例如以下的语句是错误的: sunday:=sun; monday:=mon;,枚举类型,3、枚举常量不允许在同一枚举类型定义中重复出现,同一个枚举常量也不能出现在不同的枚举类型定义中。 例如以下的定义是错误的: ty

4、pe daytype1=(monday,tuesday); daytype2=(monday,wednesday); 4、Pascal不允许直接读写枚举值(如 write(pred(mon)),所以枚举值的输出常用case语句间接的输出。 case succ(sun) of sun:write(sunday); mon:write(monday); . . sat:write(saturday); end;,枚举类型,枚举类型变量的声明 Var x,y:daytype; 注意:此时的daytype必须是已定义好的枚举类型。 也可以将枚举类型的定义和变量的定义结合在一起。 例如:var a:(s

5、un,mon,tue); 枚举类型的运算 顺序运算:枚举类型属于顺序类型。根据定义类型时各枚举元素的排列顺序确定它们的序列,序列号从0开始,如果类型说明中有N个元素,那么,每个元素对应的序号从左到右依次为0(N-1),如上面daytype中,sun的序号为0,sat的序号为6,即ord(sun)=0,succ(sun)=mon,pred(fri)=thu 注意:枚举类型中的第一个元素没有前趋,最后一个元素没有后继。,枚举类型,关系运算:例如,sunmon为真,thutue为假 例4-1:显示系统日期,并返回昨天、今天和明天的星期 分析: 法一:如教材 法二:利用日期型数据本质的特点,建立day

6、ofweek返回值与星期几文字的对应函数即可。,子界类型,有确定的数据类型(称为基类型),且其取值范围确定的数据可以定义为“子界类型”。其中的基类型,必须为顺序类型。子界类型具有便于查错、节省内存的优点。 type 子界类型标识符常量常量; 例如:type a=13; b=ad; 注意: 1、子界的两个常量必须是同一种顺序类型,如:ab,要求a=b。这里的“顺序”不是指大小,而是指子界中的每个元素都有后继元素或前趋元素。如type x0.20.8是错误的。,子界类型,2、子界的上、下界所属的数据类型即子界的基类型。若子界的基类型为标准数据类型(整型、布尔型、字符型),则子界的上、下界可以直接使

7、用该类型常量,若子界的基类型为枚举类型,则必须先定义基类型(枚举类型),再定义子界类型。例如:type week=(sun,mon,tue,wed,thu,fri,sat); subweek=monthu; 子界变量的声明 Var num1,num2:a; str1,str2:b; 可以将子界类型的定义和变量的定义结合在一起,例如: var a:19,子界类型,子界类型变量的运算 子界类型的运算与其基类型的运算一致。 例4-2:十进制到其他进制的转换 例:按月、日、年顺序读入一日期,输出该日期是这一年中的第几天。,集合类型,集合是指具有相同性质且可以相互区分的对象的全体。构成集合的各个对象,称

8、为集合的元素。例如一组学生的姓名,小于10的自然数等。 集合表示方法 (1)穷举法:把集合中所有元素列举出来。例如 小于20的素数2,3,5,7,11,17,19 (2)描述法:列出集合元素的共同特征。例如 1100之间的自然数=n | 1n100,且n属于n,集合类型,在理解集合的概念时,要注意以下几点: 1、集合中的元素是互异的,即相同的元素视为是同一个元素。 2、集合中的元素是无序的,即1,2,3,4与2,3,1,4是同一个集合。 3、集合中的元素个数可以是有限的,也可以是无限的。 4、元素与集合的关系是“属于”或“不属于”,二者必取其一且仅取其一。 为了表示集合,在Pascal中引入了

9、集合类型。集合类型属于构造类型,是由其他的数据类型按照一定的规则构造而成。,集合类型的定义 type 集合类型标识符set of 基类型 限定基类型为枚举类型、字符型、布尔型以及它们的子界和整型子界。由于基类型中不能超过256个可能值,且它们的序数值应在0255之间,因此基类型不能是短整型、整型、长整型。 表示一个集合值的最通用的方法是逐个枚举集合的元素,下面是集合值标记的例子: 3,9,15,20 由3,9,15,20组成的集合 空集 lp,z 由字符l,m,n,o,p,z组成的集合,例如: TYPE numbers=1100; prime=SET OF numbers; caps=SET

10、OF AZ VAR p1,p2,p3:prime c1,c3,c5:caps;,集合类型,集合变量的取值 集合变量的取值范围是包括空集合在内的所有子集。集合值用方括号作为分隔符,内为元素序列,元素之间用逗号隔开。赋值语句同样适用于集合类型数据。利用赋值语句,可以将计算集合表达式所得结果的值赋给集合变量。 集合的值不能直接以其书写的形式输出,还需要增加一些必要的语句,如利用选择语句和保留字IN等。 例 集合变量说明 var A,B,C,D,E,F:set of 17;I:INTEGER; 赋值语句 D:=1,3,5,7;E:=2,4,6;F:=1,2,3; 输出E的集合值 FOR I:=1 TO

11、 9 DO IF I IN E THEN WRITE(I:2);输出结果为:2 4 6,集合类型,集合的运算,集合类型,例4-3:筛选求素数 例:输入一系列字符,对其中的数字字符、字母字符和其它字符分别计数。输入?后结束。 var ch:char; letter:set of char; digit:set of 09; i,j,k:integer; begin letter:=az,AZ; digit:=09; i:=0; j:=0; k:=0; repeat readln(ch); if ch in letter then i:=i+1 else if ch in digit then j

12、:=j+1 else k:=k+1; until ch=?; writeln(letter:,i,digit:,j,other:,k); readln; end.,数组,数组是一些具有相同类型的元素按一定顺序组成的序列。数组中的每一个数据元素都可以通过数组名和唯一的索引号来存取,它们被顺序地安排在内存中的一段连续的存储区中。 在Object Pascal中数组可分为静态数组和动态数组两种类型。根据数组的结构,可分为一维数组、二维数组和多维数组。 数组的定义: type 类型标识符=array下标类型1,下标类型2,下标类型n of 元素类型; 其中下标类型必须是有序的(整型、字符型、布尔型、枚

13、举型、子界型等) ,而元素类型可以是任意的。在同一数组中,所有元素的数据类型必须一致。,静态数组,静态数组在程序初始化时必须分配内存单元,明确其固定的大小和元素的数据类型。 静态一维数组: type 类型标识符=array下标类型 of 元素类型; var 数组变量名:类型标识符; 如: type data=array150 of integer; var a,b:data; 类型和变量是两个不同概念,不能混淆。就数组而言,程序的执行部分使用的不是数组类型(标识符)而是数组变量。如上定义,在程序中data不能在执行部分出现。 type axcolor=(red,green,blue); var

14、 color:arrayaxcolor of integer;/结构类型做下标需先声明。,数组,也可以将数组类型定义和变量定义合并。 如:var a,b:array150of integer; 数组元素的操作: 数组元素的访问:数组名下标值 如:data3,colorblue。对于静态数组的下标,其范围已在定义时给定,不得在程序执行过程中改变。 数组元素的赋值:数组元素与简单变量一样,直接赋值即可,如data3:=23+63,colorblue=255。 由于数组的下标为顺序类型构成,故可用顺序函数low、high分别返回数组的最小下标值和最大下标值,可用length返回数组的长度。,数组,例

15、1:教材例题(随机数的产生、线性查找) 例2:读入个学生的学号和成绩,计算他们的平均分,若比平均分高分的等级为A,比平均分高小于分的等级为B,低于平均分的等级为C,输出他们的成绩和等级。 例3:将一个十进制自然数转换成二进制数。 例4:随机产生10个两位数,按从小到大排序。,数组,静态二维数组: type 类型标识符=array下标类型1, 下标类型2 of 元素类型; 例如:var a:array14,13of integer; 则表示a是二维数组,共有4*3=12个元素,它们是: a1,1a1,2a1,3 a2,1a2,2a2,3 a3,1a3,2a3,3 a4,1a4,2a4,3 因此可

16、以看成一个矩阵,a4,2即表示第4行、第2列的元素。,数组,虽然逻辑上可以把二维数组看作是一张表格或一个矩阵,但在计算机内部,二维数组的所有元素对应的存储单元是连续的,与一维数组的存储方式在本质上是相同的。 对于整个二维数组的元素引用时,大多采用二重循环来实现。如给上例定义的二维数组a进行赋值: for i:=1 to 9 do for j:=1 to i do ai,j:=i*j; 同样用二重循环来实现二维数组的输入与输出: for i:=1 to 4 do for j:=1 to 3 do read(ai,j); for i:=1 to 4 do begin for j:=1 to 3 d

17、o write(ai,j:5); writeln; end;,数组,例1:已知数组A中,每个元素A(I,J)在存贮时要占3个字节,设I从1变化到8,J从1变化到10,分配内存时是从地址SA开始连续按行存贮分配的。试问:A(5,8)的起始地址为( A )。 A) SA+141 B) SA+180 C) SA+222 D) SA+225 例2:仔细阅读下列程序段: var a:array13,14 of integer; b:array14,13 of integer; x,y:integer;,数组,begin for x:=1 to 3 do for y:=1 to 4 do ax,y:=x-

18、y; for x:=4 downto 1 do for y:=1 to 3 do bx,y:=ay,x; writeln(b3,2); end. 上列程序段的正确输出是( )。 A) -1 B) -2 C) -3 D) 4 例3:教材例题(二维数组的输入输出) 例4:输入4名学生数学、物理、英语、化学、pascal五门课的考试成绩,求出每名学生的总分、平均分,打印出表格。,数组,多维静态数组:允许定义任意维,但一般不超过三维。 静态数组的注意问题: 1、零基准数组:即下标从0开始的数组 如:array05 of Char 零基准数组主要用于存贮NULL字符结束的字符串,元素类型为Char的零基

19、准数组与Pchar类型赋值兼容。 在调用Windows的API需要用到以NULL字符结束的字符串。 2、数组的整体赋值 可以让一数组元素逐个给另一数组元素赋值,达到整体赋值的目的,也可数组直接整体赋值,但数组的整体赋值仅限于类型相容的数组,因为类型相容是赋值相容的前提条件,只有类型相容的变量才可以进行关系运算。,数组,当满足下列两个条件之一时,可以认为类型T1和类型T2是类型一致的: T1和T2有完全相同的类型标识符。 T1被声明为与T2等价的类型。 例如下面3种类型是一致的: type T1=Integer; T2=Integer; T3=T1; T1和T2类型一致,是因为它们有完全相同的类

20、型标识符,T3和T1类型一致,是因为T3被声明与T1等价的类型。 注意:下面的两个类型不是一致的,尽管它们的类型描述完全相同: T1:Array1100 of Integer; T2:Array1100 of Integer; 要使T2成为与T1一致的类型,应该这么写: T1,T2:Array1100 of Integer;,4、把数组作为过程或函数的形参 5、开放式数组 指数组作为形参传递给过程或函数时,其长度是不确定的,这样在调用这个过程或函数时,可以传递不同长度的数组实参。详见P73。,动态数组,动态数组不必定义数组的长度,而在程序中动态地分配数组的存储空间,以便更灵活地使用数组的特性。

21、 一维动态数组 声明格式:type 类型标识符=array of 元素类型; 如: type data=array of integer; var bank:data; 可见定义时不必声明数组的长度,但在程序中使用动态数组之前,需要调用SetLength过程指定: SetLength(数组变量名,数组元素个数),如SetLength(bank,30) 最需要注意的一点是,动态数组是一个零基准数组,第一个元素的下标应该为0。,多维动态数组 声明格式: type 类型标识符=array of array of array of 元素类型; 如:type score= array of array

22、of integer; var fs:score; begin setlenght(fs,4,7); end; 动态数组还允许对每行单独设置长度,即每行的长度可以不等,这也是静态数组做不到的。 如: setlenght(fs,4); setlenght(fs0,4); setlenght(fs1,3); setlenght(fs2,10);,数组,例:改写教材例题,使之显示九九乘法表。,记录类型,在delphi编程中对于组织和处理成批的数据来说,数组是一种十分方便、灵活的数据类型,但数组在使用中有一个基本限制,这就是一个数组中的所有元素都必须具有相同的类型。但在实际问题中可能会遇到另一类数据,

23、它是由性质各不相同的成份组成的,即它的各个成份可能具有不同的类型。例如,有关一个学生的数据包含下列项目: 学号 字符串类型 姓名 字符串类型 年龄 整型 性别 字符型 成绩 实型数 Pascal给我们提供了一种叫做记录的结构类型。在一个记录中,可以包含不同类型的并且互相相关的一些数据。,记录类型的定义 记录由一组称为“域”的分量组成,每个域可以具有不同的类型。 记录类型定义的一般形式: type 类型标识符=record 域名1:类型1; 域名2:类型2; : : : : 域名n:类型n; end;,以上学生的数据可定义为: type studata=record num : string6;

24、 name : string8; age : 1025; sex : char; chinese:real; maths:real; english:real; end;,注意: 1、域名也称域变量标识符。在同一个记录类型中,不能有相同的域名,但在不同的记录类型中可以有相同的域名(访问时须在域名前冠以记录变量名)。 2、各个域的类型可以是简单的数据类型,也可以是数组等构造类型。 如:在定义学生记录前先定义一个数组类型来存放成绩: s:array13 of real; 用s1、s2、s3存放一个学生的chinese、maths 、english成绩。,记录,记录类型的定义和变量可合并定义,如:

25、type date=record year:19001999; month:112; day:131 end; var x:date; 可以合并成: var x: record year:19001999; month:112; day:131 end; 不过由于记录类型的描述稍复杂,建议分开声明。,记录,记录域的访问 记录域的访问有两种方法:直接引用和开域引用。 1、直接引用方式为: 记录变量名.域名 如前面定义的记录X,其3个分量分别为:x.year ,x.month ,x.day。对域变量的赋值可以用read语句或赋值语句: read(x.year,x.month,x.day); x.y

26、ear:=2003; x.month:=12; x.day:=18; 如域类型是数组类型,则引用方式为: 记录变量名.数组名i for i:=1 to 3 do read(studata.si);,记录域可进行其基类型的各种运算,但记录作为一个整体,只有赋值这一个运算,即把一个记录整体赋给另一个类型一致的记录。 如:var jsj1,jsj2:student; jsj2:=jsj1; /把jsj1中的记录值赋给jsj2 2、开域引用: 开域语句一般形式: with do ,1、在do后的语句中使用with后的记录的域时, 只要直接写出域名即可,即可以省略记录变量名和“.“。 例如: write

27、(Input year:);readln(x.year); write(Input month:);readln(x.month); write(Input day:);readln(x.day); 可以改写成: (在with后只使用一个记录变量名) with x do begin write(Input year:);readln(year); write(Input month:);readln(month); write(Input day:);readln(day); end;,2、当一个记录类型的某个域类型也是记录类型时,即记录的嵌套。如 记录定义 var x:record i:in

28、teger; y:record j:05; k:real; end; m:real end;,如使用with开域语句输入数据,则: with x do begin read(i); with y do read(j,k); readln(m); end; 或简写为: with x,y do readln(i,j,k,m); 注意,这要求两个记录内的域名不能相同。,记录与数组 记录与数组是两种即有区别又有联系的构造类型。 数组中的元素其类型是相同的,但元素的个数在一定范围内是可变的。而记录中的字段可以是不类型,但字段 的数量是固定的。 数组的元素是通过数组变量名加方括号和下标来访问的,而记录中的

29、字段是通过记录变量名加一个小圆点和字 段名来访问的。 在描述复杂的总是时,往往把数组和记录结合起来使用,例如一个班级有若干名同学,每个同学的情况用一个 记录来描述,这就需要构造一个元素类型为记录的数组类型。 这就是数据库表的雏型。,记录数组 上面用 var stu:studata; 定义一个记录型变量存放一个学生的数据,如 全班学生的数据的处理要用“记录数组”。 var students:array145 of studata; 数组的每个元素studentsi又都是记录类型。 记录数组的引用形式为: 数组名i.域名 如: students5.age 变体记录(详见教材),指针类型,有些变量在

30、程序运行前已确定必须使用的,我们称为静态变量。还有些变量,只有在程序运行后才能知道是否使用,这样的变量称为动态变量。 例如,从文件中读入一批整型数据,只知道数据间用空格分隔,但不知道有多少个。这样如果用数组来存储这些数据,数组定义多大就是一个问题。太少存储不下,太多浪费空间。这就要用到动态变量。在PASCAL中的动态变量不在变量说明中出现,而是通过“指针”来建立的。,指针,指针是通过地址来访问变量的一种特殊的数据类型,属于动态的数据结构,它可以在需要时产生,用完后则又可以取消或回收,以减少占用的内存空间。指针变量与其他类型的变量不同,它占有的不是数据,而是地址。 由于动态数据结构的变量是在程序

31、执行过程中动态生成的,所以不能预先予以说明,无法预先给这些变量起名字,访问时也无法通过名字直接输出或显示,而只能用指针得到其地址,然后间接访问。,声明格式: TYPE 指针类型名=基类型;其中“”为指针符 VAR 变量名1,变量名2 :指针类型名; 例如: TYPE studrec=RECORD name : STRING20; score : integer; END; stuptr=studrec; VAR p,p1,p2:stuptr;,变量p1,p2是指针变量,它存储另一个变量学生记录(studrec)的地址。而学生记录在说明部分只有类型说明,没有变量定义。也就是说,当程序刚开始执行时

32、,学生记录没有占用存储空间。 2、动态变量 应用一个指针指向动态存储单元即动态变量的形式如下:指针变量名 例如:p、q、r 指针变量p和它所指向的动态变量p之间有如下关系:,P是指向该动态变量的指针变量名,P则称为动态变量或标志变量。P的值是P的首地址,P的值为与基类型相同的一个值。语句p:=5;把整数5存放到p所指向的动态变量p中;语句i:=p;把p所指向的p中的值赋给整型变量i 。 如果指针变量p并未指向任何存储单元,则可用赋值语句:p:=nil;其中nil是保留字,表示“空”(C语言里面用null)。,对指针的操作 指针主要有4种用法:建立(new),使用,运算,撤销(dispose)。

33、 1建立new(p) 在Turob Pascal程序中,动态变量不能由var直接定义而是通过调用标准过程new建立的。过程形式为: new(指针变量名); 如果有下列变量定义语句: var p:integer;,仅仅说明了p是一个指向整型变量单元的指针变量,但这个整型单元并不存在,在指针变量p中还没有具体的地址值。在程序中必须通过过程调用语句:new(p);才在内存中分配了一个整型变量单元,并把这个单元的地址放在变量p中,一个指针变量只能存放一个地址。在同一时间内一个指针只能指向一个变量单元。当程序再次执行new(p)时,又在内存中新建立了一个整型变量单元,并把新单元的地址存放在p中,从而丢失

34、了旧的变量单元的地址。,2使用指针 (1)给变量(记录)的域赋值:p.name:=liming; (2)P作为一个变量用。给整个变量赋值:p:=stud2; (3)同类型指针可赋值:p2:=p1; 注意,赋值后原p2中的地址被覆盖。如原p2指向某一变量,则该变量就“丢失”了!因此,如果p2原指向某一变量,在进行上述赋值前,应把地址转移到另一变量中,或把指向的变量“撤销”。 (4)指针可作为基类型,构造出其他类型,例如数组:pntarr:ARRAY11000 OF stuptr; (5)当指针变量p1中,没有存放其它数据的地址时,可以认为指针变量p1指向空,记为:p1:=nil。,3撤销disp

35、ose(p) 为了节省内存空间,对于一些已经不使用的现有动态变量,应该使用标准过程dispose予以释放。过程形式为:dispose(指针变量名);为new(指针变量名)的逆过程,其作用是释放由指针变量所指向的动态变量的存储单元。例如在用了new(p)后再调用dispose(p),则指针p所指向的动态变量被撤销,内存空间还给系统,这时p的值为 nil。,注意: 1、指针变量独立存在是无意义的,必须与另一基类型的变量同时存在。当基类型的变量占内存很小,或不进行大量的释放操作时,一般就不必用指针。 2、P与P的区别 P是指向该动态变量的指针变量名,P则称为动态变量或标志变量。P的值是P的首地址,P的值为与基类型相同的一个值。 3、定义后及时分配存储单元 定义了一个指针变量后,并没有为该指针分配动态存储单元,此时的P的值无定义,调用P则会产生运行错误。若想使该指针可用,可以对指针赋值,也可以通过NEW()过程分配存储单元。 4、使用后及时收回存储单元 指针使用后,不会自动归还占用的存储空间,应及时使用DISPOSE()过程来释放P所占用的存储单元,以免浪费有限的存储空间。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1