第四节 记录类型和文件类型

前面介绍的数组类型和集合类型有一个共同点,那就是在同一个数组或集合中的各有元素都必须具有相同的类型。如果要处理如下表所示的学生档案卡片上的数据,各栏目的数据类型不一样(学号,姓名,成绩…),需要用不同的类型表示。

学号

姓名

性别

出生年月

语文

数学

英语

平均分

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

为此,PASCAL系统定义了记录类型,可用来表示不同类型的数据。

[例5.14]建立一张学生情况表格,求出每位学生的平均成绩,并输出这张表格。

解:①定义记录类型:Date(表示日期记录,有三个域:day 日,mon月,yea年);

      Studa(表示学生情况记录,有六个域:nu学号,na姓名,dd出生年月,se性别,s成绩,ave平均分);

    ②读入记录数据;

    ③计算学生的平均成绩;

    ④输出记录内容。

PASCAL程序:

Program Exam514;

  Const n=2; m=3;                    {为了简单,人数N=2课目M=3}

  Type  Date=Record                   {定义Date(日期)记录类型}

               day: 1..31;            {域名day表示天,为子界型(1..31)}

               mon: 1..12;            {域名mon表示月,为子界型(1..12)}

               yea: 1970..1999;     {域名yea表示年,为子界类型}

             End;

        Studa=Record                  {定义Studa(学生情况)记录类型}

                nu: string[5];       {域名nu表示学号,为字符串类型}

                na: string[8];       {域名na表示姓名,为字符串类型}

                dd: Date;             {域名dd表示日期,为记录类型(Date)}

                se: char;             {域名se表示性别,为字符类型}

                s: array[1..m] of real;  {域名s表示成绩,为数组类型}

                ave: real             {域名s表示平均分,为实数类型}

              End;

       Sarr=array[1..n] of Studa; {定义Sarr为数组类型,各元素为记录类型}

  Var  Stu: sarr;                    {变量Stu为数组(Sarr)类型}

Procedure rrd(var stu:sarr);      {定义输入和计算过程}

  var  i,k: integer;

       t: real;

       a: studa;                     {变量a为记录(Studa)类型}

  begin

    for k:=1 to n do

      begin

        with a,dd do                {开域语句,打开当前记录a和dd,进行以下操作}

          begin

            write(k:2,' nu: '); readln(nu);    {输入学号}

            write(k:2,' na: '); readln(na);    {输入姓名}

            write(k:2,' se: '); readln(se);    {输入性别}

            write(k:2,' day: '); readln(day);  {输入出生日}

            write(k:2,' mon: '); readln(mon);  {输入出生月}

            write(k:2,' yea: '); readln(yea);  {输入出生年}

            t:=0;

            for i:=1 to m do           {输入m科的成绩分}

                begin

                  write('s[',i,']='); read(s[ i ]);

                  t:=t+s[ i ]           {累加总分}

                end;

            readln;

            ave:=t/m;                 {计算平均分}

            stu[k]:=a                   {将当前记录存入stu[k]中}

          end;

      end

  end;

Procedure print1;         {打印表格线}

  var  i: integer;

  begin

    for i:=1 to 60 do write('-');

    writeln;

type  记录类型名 = record

                      域名:类型;

                      …

                      域名:类型;

                   end;

 


  end;

Procedure print2;        {打印表头和表格栏目}

  begin

    writeln(' ':18,'________ table _________' );

    print1;

    write(' num.', ' ':6, 'name', ' ':7, 'mm/dd/yy', ' ':4 );

    writeln('sex  ', 'Chin', ' ':2, 'math', ' ':2, 'Engl', ' ':2, 'vaer' );

    print1

  end;

Procedure print3(stu : sarr);   {打印记录数据}

  var i, j : integer;

  begin

    print2;

    for j:=1 to n do

      with stu[ j ], dd  do

        begin

          write(nu:5, na:9, '  ':8, mon:2, '/ ', day:2, '/ ',

                yea:4, '  ' );

          write(se:3, '  ' );

          for i:=1 to m do write(s[ i ]:6:1);

          writeln(ave:6:1);

          print1

        end

  end;

Begin

  rrd(stu);

  print3(stu);

  readln

end.

程序自定义Date记录类型,用来表示学生的出生年月日,含三个分量(称为域):

   day (日)     为子界类型(1..31);

   mon(月)      为子界类型(1..12);

   yea (年)     为子界类型(1970..1999);

自定义Stuta记录类型,用来表示学生情况,含六个域:

   nu(学号)       为字符类型(string [5] 为5个字符);

   na(学号)       为字符类型(string [8] 为8个字符);

   dd(出生年月日) 是前面所定义的date记录类型;

   se(性别)       是char字符类型 ;

   s(表示学生成绩)是数组类型,各元素为real实型;

   ave (学生平均分)是real实型 ;

程序定义的数组sarr的每个元素为Stuta记录(每个记录相当于一张学生情况卡片,整个数组相当于全体学生的情况卡片)。

自定义记录类型的一般格式为:

访问记录中的分量,有两种方式:

① 记录名.域名          例如对记录a中的nu赋值,可写成

                          a.nu:=1008; {将1008赋给记录a中的分量nu}

② with记录名 do 语句   开域语句,with后面可同时打开多个记录,

                         例如:with a, dd do语句;  { a, dd都是记录名}

[例5.15]利用记录类型将N个数由大到小排序,输出排序结果并显示每个数原来的位置序号。

PASCAL程序:

Program Ex59;

  Type dd=Record                        {定义DD记录类型}

            ii:integer;                 {域名ii表示数}

            id:integer                  {域名id表示数ii的位置序号}

          End;

   Var a:array[1..100]of dd;

       i,j,k,n:integer;

       t:dd;

   Begin

     Write('Please Input Number of elements:');

     read(n);

     writeln('Input elements:');

     for i:=1 to n do

       begin

         read(a[i].ii);

         a[i].id:=i;

         for j:=1 to i-1 do

           if a[j].ii<a[i].ii then

              begin

                t:=a[i];

                for k:=i-1 downto j do

                  a[k+1]:=a[k];

                a[j]:=t;

              end;

        end;

      for i:=1 to n do

        begin

          write(a[i].ii:5,'(',a[i].id:2,')');

          if i mod 10=0 then writeln

        end;

        readln;writeln;

    End.

 

PASCAL系统自定义文件类型,可非常方便地实现对外存贮器的存取使用。常用的文件类型有顺序文件(File}和文本文件(Text)。

 

[例5.16]建立一个由1到50连续整数为分量的顺序文件。

解:①定义顺序文件类型(file);

    ②说明文件变量名;

    ③用assign过程指派一个文件变量和实际磁盘文件名对应;

    ④建立一个实际文件;

    ⑤将变量的值写入文件中;

    ⑥关闭文件。

Program Exam516;

type fdata=file of integer;                   {定义文件类型}

var fd: fdata; i, k : integer;                  {fd为文件变量}

begin

  assign(fd, ’a: files’); rewrite(fd);       {指派并建立文件}

  for I:=1 to 50 do write(fd, i ); close(fd); {写文件,最后关闭文件}

end.

[例5.17]输出一个由1到50连续整数为分量的顺序文件。

解:①定义顺序文件类型(file);

    ②说明文件变量名;

    ③用assign过程指派文件变量和实际磁盘文件名对应;

    ④打开与文件变量对应的磁盘文件,并将文件分量指针设置在开头位置;

    ⑤读出指针所指的文件分量,赋给变量;

    ⑥关闭文件。

Program Exam517;

type fdata=file of integer;                   {定义文件类型}

var fd: fdata; i, k : integer;              {fd为文件变量}

begin

  assign(fd, ’files’); reset(fd);            {指派并恢复文件指针}

  for I:=1 to 50 do read(fd,i); close(fd);   {读文件,最后关闭文件}

end.

顺序文件在磁盘上以二进制形式存储,所以又称为二进制文件。

另一种常用的文件类型是文本文件,以ASCII码的形式存储,比较通用,可以用DOS命令TYPE显示文件内容。

 

[例5.18]建立 由50个随机整数组成、文件名为f1.dat的TEXT文件。

解:①定义文件变量f为文本文件类型(TEXT);

    ②指派f与磁盘(指定盘符a:)上的f1.dat对应;

    ③建立文件;

    ④产生1~50个随机整数,写入文件中;

    ⑤关闭文件。

Program Exam518;

  const

    n=50;

var

    s: integer;                          {s为rr型}

    f: text;                             {f为text类型}

    i: integer;

begin

  assign(f, ’a: f1.dat’ );           {用文件变量f与a驱磁盘上f1.dat文件对应}

  rewrite(f);                           {建立与f对应的实际文件名}

  randomize;                            {初始化随机函数}

  for I:=1 to n do

    begin

      s:=random(99)+1;                 {产生一个100以内的随机整数赋给s}

      write(f, s:6);                   {将s写入文件中}

      if I mod 5=0 then writeln(f)   {每行写5个数据}

    end;

  close( f )                             {关闭文件}

end.

 

[例5.19]读出a驱上磁盘文件f1.dat,并输出打印文件内容。

解:①定义文件变量f为text类型;

    ②定义输出打印过程;

    ③定义读文件过程。

Program Exam519;

  const

    n=50;

var

    s: array[1..n] of integer;

    f: text;                          {文件变量f为文本类型(text)}

procedure pf ;                        {输出打印过程}

var i: integer;

  begin

    for I:=1 to n do

    begin

      write(s[ i ]:6);                {打印S数组元素}

      if I mod 10=0 then writeln

    end;

  writeln

  end;

procedure rf ;                         {读出文件的过程}

  var i: integer;

  begin

    assign(f, 'a: f1.dat' ) ;       {指派a盘上f1.dat文件}

    reset(f ) ;                         {打开并恢复文件指针}

    i:=0;

    while not (eof ( f ) ) do         {当文件没有结束时就做以下语句}

      begin

        if not(eoln(f)) then           {如果不是行尾就读入数据}

             begin

               inc( i ); read(f, s[ i ]); {读入数据到数组S中}

             end

          else readln(f );             {否则就换行读}

      end;

    close(f )                           {关闭文件}

  end;

begin

  rf ;                                {读文件}

  pf                                   {输出}

end.                

文件类型常用指令表

  操 作

       格      式

       注     释

指派文件

 assign(文件变量, ’路径: 文件名’ );

 将文件变量指定为实际文件

建立文件

 rewrite(文件变量);

 建立一个文件

写文件

 write(文件变量,变量);

 将变量值写入文件分量

打开文件

 reset(文件变量);

 打开文件,指针恢复到开头

读文件

 read(文件变量,变量);

 读文件分量值赋给变量

关闭文件

 close(文件变量);

 

文尾函数

 Eof(文件变量)

 判断所读文件结束时为ture

行尾函数

 Eoln(文件变量)

 判断行结束时为 ture

 

习题5.4

1.将2 ~ 500范围的素数存入a: \ prin中。

2.读出a: \ prin文件,并按每行8个数据的格式打印。

3.用随机函数产生100个三位数的随机整数,存入文件名为 ff.dat中,然后读出该文件内容,进行从大到小排序,将排序后的数据按每行10个的格式显示,并存入文件名为fff.dat中。

4.将一段英文句子存入Eng.dat文件中(以每句为一行),然后读出并显示。(也可用汉语拼音代替英文句子)

5.建立N个学生档案卡,每张卡包含:编号、姓名、性别、年龄、三科成绩的等级(分A、B、C三档),编程示例输出显示。

 

 

 

第五节  指针类型与动态数据结构

前面所学的变量都具有共同的特点:系统依据程序说明部分获得变量名和类型信息,即为变量分配对应大小的存储空间,在程序执行过程中,各变量对应的存储空间始终存在且保持不变,这些变量均称为静态变量。

与静态变量对应的是动态变量,在程序执行过程中可以动态产生或撤消,所使用的存储空间也随之动态地分配或回收。为了使用动态变量。PASCAL系统提供了指针类型,用指针变量(静态变量)来指示动态变量(存储地址变量)。下面介绍如何利用指针建立动态数据结构。

 

[例5.19] 分别用简单变量和指针变量交换两个变量的值。

解:设两个变量a,b的值分别为5, 8

(1)用简单变量交换:

Program Exam519;

  const  a=5; b=8;                             {常量}

  var c: integer;

  begin

    c:=a; a:=b; b:=c;                        {用简单变量交换}

Type  指针类型名 = ^ 基类型;

 


    writeln(’a=’:8, a, ’b=’:8, b );

    readln

  end.

 

(2)用指针变量交换:

Var  指针变量名 :  ^ 基类型;

 


Program Exam519_1;

  type pon= ^ integer;                          {pon为指针类型}

  var  a,b,c: pon;                              {a,b,c为指针变量}

  begin

    New(指针变量);

 


      new(a ); new(b ); new(c );              {开辟动态存储单元}

      a ^ :=5;  b ^ :=8;                        {给a,b指向的存储单元赋值}

      c:=a; a:=b; b:=c;                        {交换存储单元的指针}

      writeln('a=':8, a ^ , ‘b=':8, b ^ );  {输出a,b所指单元的值}

    Dispose(指针变量);

 


      readln

  End.

 

        指针变量名 ^

 


第(1)种方法,直接采用变量赋值进行交换,(实际上给各存储单元重新赋值)其过程如下图所示:

 

第(2)种方法,对各存储单元所保存的值并不改变,只是交换了指向这些单元的存储地址(指针值),可以简略地用如下图示说明:

(图中“—→”表示指向存储单元)

指针类型的指针变量a,b存有各指向单元的地址值,将指针交换赋值步骤为:

①将c:=a (让c具有a的指针值);

②将a:=b (让a具有b的指针值);

③将b:=c (让b具有c的指针值);

最后输出a,b所指向存储单元(a ^ 和b ^ )的值,此时的a指向了存储整数8的单元(即a ^ = 8),b指向了存储整数5的单元(即b ^ = 5)。存储单元的值没有重新赋值,只是存放指针值的变量交换了指针值。

    程序Exam519_1  Type pon= ^ integer; 是定义指针类型,一般格式为:

                

    基类型就是指针所指向的数据元素的数据类型。也可以将类型说明合并在变量说明中直接定义说明:

例如Exam519_1中类型说明与变量可以合并说明为:

Var  a,b,c: ^ integer;    {与程序中分开说明的作用相同}

定义了指针变量的类型之后,必须调用New过程开辟存储单元,调用格式如下:

如果不再需要指针变量当前所指向的存储单元,可调用Dispose过程释放所占用的存储单元,Dispose和New的作用正好相反,其格式为:

指针所指向的存储单元用如下形式表示:

程序中的a ^ 表示指针变量a所指向的存储单元,与指针变量的关系如下图所示:

 


在程序中对所指存储单元(为a ^)可以视作简单变量进行赋值计算和输出。

如:a ^ := 5

 

[例5.20] 利用指针对数组元素值进行排序。

解:①定义一个各元素为指针类型的数组a :

    ②定义一个交换指针值的过程(swap);

    ③定义一个打印过程(print);

    ④定义过程(int)将数组b的值赋给a数组各元素所指向的各存储单元。

    ⑤过程pixu用交换指针值的方式,按a数组所指向的存储单元内容值从小到大地调整各元素指针值,实现“指针”排序;

    ⑥按顺序打印a数组各元素指向单元的值(a[ i ] ^ )。

Program Exam520;

  const n=8;

        b: array[1..n] of integer

          =(44,46,98,86,36,48,79,71);

  type pon= ^ integer;

  var  a: array[1..n] of pon;

  Procedure swap(var p1, p2: pon);  {交换指针}

    var p: pon;

    begin

      p:=p1; p1:=p2; p2:=p

    end;

  Procedure print;         {打印数组各元素指向单元(a[ i ] ^ )的值}

    var i: integer;

    begin

      for i:=1 to n do write(a[ i ] ^ :6);

      writeln; writeln;

    end;

  Procedure int;        {将数组b的值赋给a数组各元素所指向的存储单元}

    var i: integer;

    begin

      for i:=1 to n do

       begin

         new(a[ i ]);

         a[ i ] ^ :=b[ i ];

       end;

      print;

    end;

  Procedure pixu;                 {排序}

    var i,j,k: integer;

    begin

      for i:=1 to n-1 do

        begin

          k:=i;

          for j:=i+1 to n do

            if a[j] ^ < a[k] ^  then  k:=j;

          swap(a[k], a[ i ])

        end

    end;

  Begin

   int;

   pixu;

   print;

   readln

  End.

 

[例5.21] 有m只猴子要选猴王,选举办法如下:

所有猴子按1 . . m编号围坐成圆圈,从第一号开始按顺序1, 2, . . , n连续报数,凡报n号的退出到圈外。如此循环报数,直到圈上只剩下一只猴子即当选为王。用指针(环形链表)编程。

解:①让指针pon指向的单元为记录类型,记录内容含有两个域:

 

             编号变量  链指针变量

 

 

②用过程crea建立环形链;

③用过程king进行报数处理:      每报数一次t计数累加一次,当所报次数能被n整除,就删去该指针指向的记录,将前一个记录的链指针指向下一个记录。删去的指向单元(记录)应释放。直到链指针所指向的单元是同一单元,就说明只剩下一个记录。

④打印指向单元记录中编号域(num)的值。

program Exam521;

 type  pon= ^ rec;                {指向rec类型}

       rec=record                    {rec为记录类型}

             num: byte;            {域名num为字节类型}

             nxt: pon                {域名nxt为pon类型}

           end;

 var hd: pon;

    m, n: byte;

 procedure crea;                   {建立环形链}

    var s,p: pon;

         i: byte;

    begin

      new(s);  hd:=s;  s ^ . num :=1;  p:=s;

      for i:=2 to n do

        begin

          new(s);  s ^ . num :=i;  p ^ . nxt:=s;  p:=s

        end;

      p ^ . nxt :=hd

    end;

 procedure king;                   {报数处理}

   var p,q: pon;

       i, t: byte;

   begin

     p:=hd;  t:=0;  q:=p;

     repeat

       p:=q ^ . nxt;  inc(t);

       if t=n then

          begin

            q ^ . nxt :=p ^ . nxt;  dispose(p);  t:=0

          end

        else q:=p

     until p=p ^ . nxt;

    hd:=p

   end;

 begin

   write('m, n=');  readln(m, n);     {输入m只猴,报数到n号}

   crea;

   king;

   writeln('then king is :', hd ^ . num);

   readln

 end.

 

习题5.5

1.请将下列八个国家的国名按英文字典顺序排列输出。

   China(中国)      Japan(日本)    Cancda(加拿大)  Korea(朝鲜)

   England(英格兰)  France(法兰西)  American(美国)  India(印度)2.某医院里一些刚生下来的婴儿,都还没有取名字,全都统一用婴儿服包装,很难区分是谁的小孩。所以必须建立卡片档案,包含内容有编号、性别、父母姓名、床号。实际婴儿数是变动的,有的到期了,家长要抱回家,要从卡片上注销;新的婴儿出生,要增加卡片,请编程用计算机处理动态管理婴儿的情况。

posted on 2011-06-02 14:24  shallyzhang  阅读(364)  评论(0)    收藏  举报