p26 记录

p26记录

一、记录的概念

在程序中对于组织和处理成批的数据来说,数组是一种十分方便的数据类型,而且数组的使用很灵活。但是数组也有一个显而易见的缺陷,那就是:一个灵敏组中的所有数据元素都必须具有相同的类型。但有一批数据是由性质各不相同的多种成分组成的。例如,要处理100名学生的档案情况,每个学生的数据包含以下几个数据项:

学号      字符串类型

姓名      字符串类型

年龄      整型

性别      字符型

是否团员  布尔型

家庭住址  字符串类型

电话号码  字符串类型

语文成绩  实型

数学成绩  实型

英语成绩  实型

政治成绩  实型

从上面我们可以看出,这种数据的各个成分是完全不同的数据类型,我们很难用数组或其他数据结构来形象有效地组织和处理。为此,Pascal为我们提供了一种叫“记录”的数据类型。

记录是由一些称为“域(又叫成员)”的数据成分所组成的一种构造类型。其中每个域(成员)可以具有不同的类型。,例如,对上面的例子我们就可以把它定义成一个记录类型,它是由11个“域(成员)”所组成:学号、姓名、年龄、性别、是否团员、家庭住址、电话号码、语文成绩、数学成绩、英语成绩、政治成绩。其中学号、姓名、家庭住址、电话号码是字符串类型;年龄是整型;性别是字符型;是否团员是布尔型;其他域为实型。

正因为在一个记录中允许多种不同类型的数据共存,所以记录类型在程序设计中用途非常广泛。

二、记录类型的定义及记录变量的说明

记录类型由用户根据需要在程序的type区中自行定义,基本形式为:

type 类型标识符=record

           域名1:类型;

           域名2:类型;

              …

           域名n:类型;

end;

如,以上有关学生的数据可以定义成以下的记录:

type studata=record

     num:string[6];

     name:string[10];

     age:integer;

     sex:char;

     ty:boolean;

     add:string[30];

     tel:string[11];

     chinese:real;

     maths:real;

     english:real;

     politics:real;

  end;

对于记录类型的定义,有以下几点需要注意:

(1)在一个记录类型中,不能有相同的域名;在多个不同的记录类型中可以有相同的域名;

(2)在记录中,各个域的类型可以是简单的数据类型,也可以是数组等其他构造类型。

如:在定义学生记录前先定义一个数组类型用来存放成绩:

type score:array[1..4] of real;

则,在上面的记录类型定义中,可以将几门课的成绩域(即:chinese,maths,english,politics)合并成一个域:s:score;

也可以直接写在一起,即s:array[1..4] of real;

这样,s[1]、s[2]、s[3]、s[4]就分别表示一位学生的语文、数学、英语、政治成绩。

定义了记录类型后,我们就可以定义一些记录型变量了,记录型变量的定义同其他类型变量的定义方式相同。如:var stu:studata;这样,就定义了一个记录类型变量stu,用来存放一位学生 的数据。

可以将记录类型的定义和记录型变量的定义放在一起,如定义一个学生的出生日期:

type date=record

        year:1980..1999;

        month:1..12;

        day:1..31;

      end;

var d:date;

可以合并如下 :

var d:record

        year:1980..1999;

        month:1..12;

        day:1..31;

      end;

三、记录成员的引用

在使用记录时,需要注意以下两点:

(1)对记录的操作,除了可以进行整体赋值外,只能对记录的成员逐个引用;

(2)记录的每个成员只能参加其基类型所允许的运算操作。

假设有以下说明:var a,b:studata;

即a,b属于同记录类型,若记录a中每个成员都已有确定的值,那么在程序的执行部分就可以执行如下语句:b:=a;

它表示将a记录的每个成员的值赋给b记录的各个同名成员。

对记录成员的引用方式有两种,一种为直接引用,一种为开域引用。

直接引用方式如下:记录名.域名

如上面定义学生出生日期记录d中,就有3个变量,分别表示为d.year、d.month、d.day。对域变量的赋值可以通过read语句,也可以通过赋值语句。如:

read(d.year,d.month,d.day);

d.year:=1980;d.month:=10;d.day:25;

对于域类型又是数组的,引用形式具体为:

记录名.数组名[i];

如读入一位学生的4门成绩,可以写成:

for i:=1 to 4 do

    read(studata.s[i]);

在程序中对记录进行处理时,经常需要引用同一记录中的不同域,如果每次都要用“记录名.域名”的形式,非常麻烦。为此,Pascal专门提供了一条with 语句以简化对记录的引用,称为“开域引用”,with语句又叫“开域语句”。

with 语句的格式为:

      with 记录名 do 语句;

如下面的程序段:

write(‘input year:’);

readln(d.year);

write(‘input month:’);

readln(d.month);

write(‘input day:’);

readln(d.day);

可以写成:

with d do

  begin

    write(‘input year:’);

    readln(year);

    write(‘input month:’);

    readln(month);

    write(‘input day’);

    readln(day);

  end;

关于开域语句有以下几点说明:

(1)在with ...do 后面语句中使用记录的域时,只要简单地写出域名就可以了,域名前的记录变量和“.”均可省略;

(2)with ...do 后面的语句可以是一个简单语句,也可以是一个复合语句;

(3)由于开域语句是一种构造语句,因此Pascal语言规定在with ...do后面的语句当中不能改变已开域的记录;

即假设有以下开域语句;with x do 语句y;

在执行时,不允许语句y影响已开域的记录x 。所以,下面的语句是不合法的:

with a[i] do

  begin

    ...

    i:=i+1;

  end;

这是因为i:=i+1改变了a[i],所以造成不能正常运行。

(4)关于记录的嵌套:在定义一个记录类型中也可以引用另外一个记录类型,但记录的嵌套层次是有限的。

如:下列记录的说明是合法的:

var x:record

       i:integer;

       y:record

         j:0..5;

          k:real;

      end;

    m:real;

end;

此时,若使用开域语句输入数据则可以写成:

with x do

  begin

    read(i);

    with y do

       read(j,k);

    read(m);

  end;

也可以简化成:

  with x,y do

  read(i,j,k,m);

四、记录数组

上面,我们用var stu:studata;定义了一个记录型变量stu用来存放一位学生的数据,如果有100位学生的数据该如何组织和处理呢?这就要用到“记录数组”。

所谓记录数组是指一个数组的每个元素类型(基类型)又是一个记录类型。如:

var students:array[1..100] of studata;

这样,就定义了一个记录数组students ,这个数组的每个元素students[i]又都是一个记录类型。

记录数组的引用形式为:

  数组名[i].域名

如:第十位学生的年龄可以表为:

students[10].age

注意:

(1)要理解“记录数组”和“域的基类型是数组类型的记录”这两个概念,、区分两者的使用场合和具体引用形式。后者的引用形式为:记录名.数组名[i];

(2)Pascal允许把记录定义成压缩式的,只需在关键字record之前加上packed,其意义类似于压缩数组。

五、变体记录

在我们前面所讲的记录中,每个记录的域个数和类型是固定不变的。然而实际问题中,仅有这样的数据类型是不够的。如:在学生档案的登记中,对男同学要求只登记身高,而对女同学则要求只登记体重,那么这样的数据想要定义成记录该怎么办呢?这就用到“变体记录”。

如上例就可以定义成这样的记录:

type stu=record

       score:array[1..6] of 0..100;

       age:integer;

       case sex:char of

             ‘m’:(weight:70..150);

              ‘f’:(high:real);

     end;

这里所定义的stu是一个变体记录类型,记录中score,age 域分别表示学生的各科成绩和年龄,是男女同学共同的。而从case 之后则根据性别登记不同的内容,若sex是‘m’则登记女生的体重,若sex是‘f’则登记男生的身高,两者是可选的,并且只能选其一。实际上case后面就是记录的“变体”部分,of后面列举了sex的所有可能情况,‘m’和‘f’就是情况常量,每种情况常量之后跟着一个冒号和一对圆括号,括号内列出了每种情况的域名和基类型。情况常量后面可以不写域名,但必须写冒号和一对圆括号。

例1输入20位学生的数据记录(包含学号、姓名、性别、年龄、成绩五个域),按成绩从高到低排序输出。

程序代码如下:

program aa;

const n=20;

type student=record

       no:integer;

       name:string[15];

       sex:char;

       age:10..18;

       score:real

     end;

var stu:array[1..n] of student;

      t:student;

      i,j:integer;

begin

  writeln(‘input’,n,’no name sex age score’);

  for i:=1 to n do   {对齐,用开域语句读入n个学生的记录}

    with stu[i] do read(no,name,sex,age,score);

  for i:=1 to n-1 do   {排序}

    for j:=i+1 to n do

    if stu[i].score<stu[j].score

    then begin

          t:=stu[i];

          stu[i]:=stu[j];

          stu[j]:=t;

         end;

    writeln(‘no name sex age score’);

    for i:=1 to n do {对齐,用开域语句输出排序好的N个学生的记录}

      begin

         with stu[i] do

           write(no:8,name:8,sex:2,age:4,score:8:1);

          writeln;

        end;

      end.

例2编程读入一组日期,输出第二天的日期。输入日期的格式是月、日、年,输出格式是月/日/年。如:输入7 31 1994 ,输出8/1/1994

问题分析:可以用一个记录变量today来表示日期,遇到一个日期后,应判断输入的日期是否为当月的最后一天或当年的最后一天,做相应的处理便可。

程序代码如下:

program aa;

const n=10;

type date=record

     month:1..12;

     day:1..31;

     year:1900..2100;

   end;

var today:array[1..n] of date;

    i:integer;f:boolean;

    maxday:28..31;

begin

  f:=true;

  for i:=1 to n do

    with today[i] do readln(month,day,year);

  for i:=1 to n do

    with today[i] do

      begin

        case month of 

            1,3,5,7,8,10,12:maxday:=31;

                 4,6,9,11:maxday:=30;

                        2:if ((year mod 4=0) and (year mod 100<>0))

                            or (year mod 400=0)

                            then maxday:=29

                            else maxday:=28;

                         else f:=false;

          end;

             if day=maxday

               then begin

                     day:=1;

                     if month=12 then begin

                                        month:=1;year:=year+1;

                                       end;

                      else month:=month+1;

                    end;

                  else if (day>maxday) or (day<0)

                        then f:=false

                        else day:=day+1;

                if f then writeln(month:2,’/’,day:2,’/’,year:4);

                else writeln(‘data error!’)

         end;

    end.

posted @ 2010-10-11 20:51  lj_cherish  阅读(219)  评论(0)    收藏  举报