PASCAL语言 基础教程三

PASCAL语言 / 2011年03月04日 12时48分 / 11875人浏览
第八章、自定义函数和过程 PASCAL语言提供了大量的标准函数及标准过程供我们直接使用,但有时我们也会用到非标准的函数或过程,尤其是在做递归、回溯、搜索问题时,使用PASCAL语言的自定义函数、过程功能,与BASIC相比,能帮我们节省至少一半以上的时间。同样一个搜索问题,用BASIC语言如果要2个小时编出程序,用PASCAL语言就可能不要1个小时。 第一节、自定义函数 自定义函数也是在程序头部说明,其本身就相当于一个小程序,也有其头部及主体。语法如下: FUNCTION 函数名(形式参数表):函数值的数据类型; 函数的头部(常/变量说明); BEGIN     函数语句;(其中一定要有一句对函数名的赋值) END;    {注意:这里是分号} 以上整个部分都位于程序的头部。自定义函数由“FUNCTION”引导,名称自定,形式参数表是指一个函数要求输入的参数(如:ABS(3.12),括号中的3.12就是形式参数),而每一个函数都是得到具体的值,所以也必须要说明该函数的值(即结果)的数据类型。 函数定义好后,就可在程序中调用,调用时和调用标准函数方法一样,都是把函数作为表达式或表达式中的一部分,放在赋值语句中或直接放在输出语句中。 [例7、1]编一程序,求两个自然数的最大公约数。
Var n,m:integer;Function num(a,b:integer):integer; Var c:integer; Begin   If a>b then c:=b else c:=a;   C:=c+1;   Repeat C:=c-1;   Until (a mod c=0) and (b mod c=0);   Num:=c; End; Begin   Write(‘please input 2 numbers:’);   Readln(m,n);   Writeln(num(m,n)); End. 说明程序主体中的两个变量M,N定义一个函数NUM,要求输入两个形式参数,值为整数 说明只在函数中用到的变量C 函数主体开始 在函数语句中必不可少的一句:对函数名赋值 函数结束 程序主体开始 在WRITELN语句中调用NUM函数 程序主体结束
在上述程序头部,定义了一个名为NUM的函数,所以在程序主体中,我们就可以随时调用它了。但一定要注意:在函数程序语句中一定要对函数名赋值,否则,该函数是无效的。另外:输入的数值的类型一定要和形式参数的类型相同。 两个重要概念:全局变量、局部变量 全局变量是在程序主体的头部说明的变量,是可以在程序的各个部分(包括主体、自定义函数、自定义过程)直接使用的。 局部变量是在程序的自定义函数或自定义过程的程序头部说明的变量,它们只能在所在的函数或过程中使用,不能在程序的其它部分使用。 如上述程序中的变量M,N就是全局变量,而变量C就是局部变量。A,B是形式参数(数值参数),是常量而不是变量。 所以,大家在编写PASCAL程序时一定要注意变量的命名,全局变量与局部变量不要取相同的名称。 递归函数 递归函数是PASCAL语言编程中通向高级算法的必由之路,要掌握递归函数必须要先掌握递归这个概念。 什么是递归呢?我们来看一个例题,在此之前我们先学会什么是数列。数列即一序列数的总称,如:1,2,3,4,5,6,7,8……是自然数数列;2,4,6,8,10,……是自然偶数数列;象这种以某种关系定义的数的序列就叫数列。数列的名称可任取,象上述第一个数列如果名为A,第二个数列名为B,则第一个数列的各个数字的名字就为:A1,A2,A3,A4……或A(1),A(2),A(3)……。数列A的数字关系是:(1)A(N)=A(N-1)+1(N>1);(2)A(1)=1;由此两个关系,我们只要知道该数列中任何一个数的序号,就可推知该数的数值。 那么如果对于数列A,我想知道A(100)是多少该如何推算呢? 由上述关系我们已经知道: A(100)=A(99)+1,即要知道A(100),我们就必须先知道A(99);而 A(99)=A(98)+1;即要知道A(99)就必须先知道A(98);由此类推 A(98)=A(97)+1; ……………… A(3)=A(2)+1; A(2)=A(1)+1;而此时就已经不用继续推算下去了,因为A(1)是已知的了。 而实际上,上述推算过程就是递归过程。即要完成某个计算,必须先完成其前的另一个计算,以此类推,直到推到一个已知的值为止。 [例7、2]有一个数列N,已知:N(1)=1,N(X)=N(X-1)*3-1(X>1),求N(100); 我们已经知道,由递归关系,我们要求N(100),就必须知道N(99)……N(1),而最终N(1)是已知的,所以这个递归关系我们就可以用PASCAL语言很好地表现出来。以下我们用递归函数来完成,请大家注意递归的实现方法,即自己调用自己。
Var n100:integer;Function dg(n:integer):integer; Begin   If n:=1 then dg:=1   Else begin Dg:=dg(n-1)*3-1;   End; End; Begin   N100:=dg(100);   Writeln(n100); End. 定义程序主体中的变量定义自定义函数DG,形式参数1个,用以记录现在是推算到了第几个数。 递归出口是当N等于1时,DG的值为1 如果N不等于1,我们就继续递归,这就是递归关系式 程序主体 调用递归函数
由上可以看出,用递归函数来实现算法,程序主体可以变得非常简单,只需少数几句即可。而递归函数就显得至关重要了,由上述程序可以看出,递归函数的实现实际上就是一个自己调用自己的函数。直到调用到已知的数为止。递归问题我们还将在递归过程中详细分析。 由上可见,递归过程实际上只有一句,IF 条件 THEN 出口 ELSE 调用下一次递归; 第二节、自定义过程 我们已经学过很多的标准过程,如:WRITE,READLN,STR等等,这些都是PASCAL的标准过程,我们可以随时调用。但有的时候,我们在程序中的不同地方会用到相同的一些语句,这时,我们就会把这些语句组合成一个自定义过程,以便在不同地方调用,这样,就可以节省大量的时间。并且,利用自定义过程,我们能够非常简单的实现递归、回溯。 自定义过程的说明语法如下(在程序头部说明): procedure 过程名(形式参数表); 过程变量(局部变量)说明部分; begin 语句体; end;    {此处是分号!}     自定义过程的调用语法如下: 过程名(数值参数表); 自定义过程实际上就是一个小的程序,只不过是划分开来,成为一个过程,然后在程序主体中以过程名来调用这些语句。 自定义过程的形式参数与自定义函数的用法一样,是输入过程中要用到的不同的输入值。如果过程中不要用到形式参数值,那么在说明过程的时候,过程名后面就不用加括号来说明形式参数。 [例7、3]编写一个程序,在屏幕上打印以下图形。 $$$$$  $$$$$   $$$$$    $$$$$     $$$$$ 分析,我们已经编写过类似的程序,这里我们将用一个过程来打印每一行的五个“$”号。只不过每一行开头的位置不同,所以我们把控制开头位置的数值做为一个形式参数,另外,把每行要把多少个“$”也作为形式参数之一。
Var I:integer;Procedure printrow(n,m:integer); Var r:integer; Begin   Write(‘ ‘:n);   For r:=1 to m do begin Write(‘$’);   End;   Writeln; End; Begin   For I:=1 to 5 do begin Printrow(I,5);   End; End.  形式参数N控制每行前多少个空格,M为每行多少字符 打印每行前N个空格 每行打印M个字符 输入数值参数,每行前I个空格,每行5个字符
    上述过程中我们只有两个需输入的参数,有时我们的过程中也会用到输出的参数,如STR(N,S)过程,N是输入的参数,而S是输出的参数,即输入N转化为字符串S输出。这种有输出参数的过程在形式参数说明中有所不同,即输出参数要用VAR来引导。下例就是这种情况。 [例7、4]编写一个程序,求X的N次方。 我们知道,PASCAL语言中没有求乘方的标准函数或过程,这里我们将自己编一个求乘方的过程,而该过程的形式参数就必须有两个输入参数,另外,我们计算出的幂值必须输出到一个变量中,这个变量也必须放在形式参数中,只不过这个参数与输入参数是不同的,所以必须以VAR引导加以说明,程序如下:
Var x,n:integer;C:longint; Procedure cm(a,b:integer;var d:longint); Var I:integer; Begin   D:=1;   For I:=1 to b do begin D:=d*a;   End; End; Begin   Write(‘please input x,n: ’);   Readln(x,n);   Cm(x,n,c);   Writeln(c); End. 说明主程序中要用到的X,N变量;说明乘幂C,用长整数型 过程CM,二个输入函数,D为输出变量 程序主体开始 调用CM过程,输入X,N,输出为C
请大家一定要看懂得上述程序的形式参数部分,分清其中的输入与输出参数。 递归过程 我们从一个例题中来看看递归的实际实现及运行过程。 [例7、5]打印‘A’、‘B’、‘C’、‘D’、‘E’这五个字符任意排列的所有情况。 分析,此题可用五重循环来做,但那样就把此题给复杂化了,运行速度也要慢很多,而此题用递归过程来做的话就要简单许多。我们把递归过程定为每次从五个字符中取一个字符,当然这个字符必须与已经取得的字符全不相同,而我们取得的字符存放在一个字符串中,并把它作为形式参数(这一点至关重要,否则答案将完全错误)。当我们已经取完五个字符后,在取第六个字符时,递归过程就将结束。这就是递归的出口。这样我们就能把所有结果找出来。程序如下:
Var t:longint;Procedure dg(n:integer;s:string); Var I:char; Begin   If n=6 then begin     T:=t+1; Writeln(t:5,’  ‘,s);   End else begin For I:=’A’ to ‘E’ do begin   If pos(I,s)=0 then begin     Dg(n+1,s+I);   End; End;   End; End; Begin   T:=0;   Dg(1,’’); End. 计算答案总数的计数器递归过程有两个形式参数,N表示当前取第N个字符,S存放已经取得的N-1个字符; N等于6时,递归到了一个答案 答案总数加1 把答案数及答案打印出来 从此句中返回调用此过程的上一过程 从A—E五个字符中取一个 如果这个字符在已经取得的N-1个字符中没有出现 就调用下一次递归,即调用自己,只不过参数N变为N+1,即下次将取第N+1个字符(相对于当前来说),而输入的S参数也变为已经加入第N个字符的新字符串。 程序主体开始 答案总数初值为0 调用递归过程,输入值1表示要找第1个字符,’’表示已经找到的0个字符
上述程序的运行过程如下:
过程步骤 N的值 S的值
1.以参数1,’’输入递归过程DG,开始递归第一层 1 ‘’
2.取到第一个字符,’A’ 1 ‘A’
3.以参数(N+1,S+I), 即(2,’A’)调用第二层递归,即第一层过程尚未结束, 就调用第二层递归过程, 此时,第一层过程保留在内存中,程序执行到循环语句的’A’, 程序返回此过程中时,将继续执行此循环语句,而此时此循环已被挂起 2 ‘A’
4.进入第二层递归,取到第二个字符,此时’A’已不能取, 只能取’B’ 2 ‘AB’
3.以参数(N+1,S+I), 即(3,’AB’)调用第三层递归,即第一层及第二层过程尚未结束, 就调用第三层递归过程, 此时,第一,二层过程保留在内存中, 3 ‘AB’
5.进入第三层递归,取到第三个字符,此时’A’和’B’已不能取, 只能取’C’ 3 ‘ABC’
…………    
接上. 以参数(N+1,S+I), 即(5,’ABCD’)调用第五层递归,即第一层到第四层过程尚未结束, 就调用第五层递归过程, 此时,第一至四层过程留在内存中, 5 ‘ABCD’
接上. 进入第五层递归,取到第五个字符,此时只能取’E’ 5 ‘ABCDE’
接上. 以参数(N+1,S+I),即(6,’ABCDE’)调用第六层递归,即第一层到第五层过程尚未结束, 就调用第六层递归过程, 此时,第一至四层过程留在内存中 6 ‘ABCDE’
接上. 进入第六层递归过程, 此时N=6条件满足,将不执行下一层递归,而是打印出第一个答案’ABCDE’, 并结束此次递归过程, 这意味着,程序将回到调用第六层递归的第五层递归的循环语句中 6 ‘ABCDE’
接上. 程序回到第五层递归过程中, 而此时, 循环已经执行到’E’, 无其它字母可加入,所以第五层递归将被自然结束,返回第四层递归过程的循环语句,注意: 此时,N已经变成5, 而S为’ABCD’, 与开始进入第五层递归是一致的,这就是把N和S作为形式参数的意义之处 5 ‘ABCD’
接上. 程序回到第四层递归中, 此时的循环执行到’D’, 还有’E’可取 4 ‘ABCE’
接上. 取完’E’后,程序又调用第五层递归,此时可取’D’, 5 ‘ABCED’
接上. 进入第六层递归,打印已经取得的新答案:’ABCED’    
接上. 取得新答案后, 返回第五层, 没有字符可取, 正常结束再返回第四层, 仍没有字符可取,再返回第三层,此时,第三层刚取完’C’,可取’D’ 3 ‘ABD’
接上,再重复上述过程,N及S的取值情况如下: 4 ‘ABDC’
  5 ‘ABDCE’
  4 ‘ABDE’
  5 ‘ABDEC’
  3 ‘ABE’
  4 ‘ABEC’
  5 ‘ABECD’
……………… …… ……
从上述分析中,可以看出整个递归过程完全是动态的,不停地在各层递归过程之间调用,也包括返回第一层的情况,这样就能把所有答案都找出来。下面我们以取‘ABC’三个字符的全排列来看其生成树的全过程: 第0层:                                      开始(1) 第一层:               A(2)                    B(7)                   C(12) 第二层     AB(3)     AC(5)         BA(8)       BC(10)        CA(13)     CB(15) 第三层   ABC(4)       ACB(6)    BAC(9)         BCA(11)   CAB(14)       CBA(16) 由上可以看出,共生成了16个节点(NODE),我们把每一个状态,即每一个递归过程产生的字符串叫做一个节点,请大家记住这个概念。从开始第一个节点开始,我们的子点遍历过程是按数字大小来标明的,即(1)--(16)这16个节点是按顺序生成的,结果共有6个,这6个节点产生的顺序也可看出是按数字大小来产生的。整个递归过程共产生了三层节点,每个目标节点都是直线产生,每条能够走通的路线都一定能产生出目标节点,这就是递归,同样,这就是我们所说的深度优先搜索问题,即搜索方向是直向深处的节点的。 另外,上述图中,程序经过每个节点的顺序我们也能很清楚的说出了:(开始)1à2à3à4à3à2à5à6à5à2à1à7à8à9à8à7à10à11à10à7à1à12à13à14à13à12à15à16à15à12à1(结束)。 上述到达4、6、9、11、14、16节点是找到了答案,由小节点往大节点走时是调用深一层递归过程,而大节点往小节点走时是由深层的节点返回上一层节点,这其实也就是回溯了。从这种观点来看,递归与回溯的差别是很小的,递归是在找到一个答案之前,即中途是不会返回上一层的,而回溯是在中途就有可能无法展开下一层节点,而只能返回上一层。下面我们将以数个例子来更深入地说明递归回溯这两大重点。 [例7、6]从键盘输入一个正整数N,求把它分解成若干个小于等于N的正整数之和的所有情况。 分析:我们完全可模仿[例7、5]的方法,把递归过程定为每次从1到N-1这些正整数中取一个整数,而我们取得的数字经转换为字符后,也存放在一个字符串中,并把它作为形式参数。然后把M减去这整数后再做为新的参数,当我们新的参数已经为0时,递归过程就将结束。这就是递归的出口。这样我们就能把所有结果找出来。程序如下:
Var a,t:longint;Procedure shu(n:integer;s:string); Var I:integer;     C:string; Begin   If n=0 then begin     T:=t+1; Writeln(t:5,’ ’,a,’= ‘,copy(s,1,length(s)-1));   End else begin For I:=1 to n do begin   Str(I,c);   Shu(n-i,s+c+’+’); End;   End; End; Begin   T:=0;   Readln(a);   Shu(a,’’); End. 键盘输入值及计算答案总数的计数器递归过程有两个形式参数,N表示剩下的整数是多少,S存放已经取得的数字 N等于0时,递归到了一个答案 答案总数加1 答案打印(去掉最后一个加号) 从此句中返回调用此过程的上一过程 从1—N的整数中取一个整数 转换为字符串 调用下一次递归,即调用自己,只不过参数N变为N-i,即下次将用N-I来减,输入的S参数也变为已经加入新取的这一个数字及加号。 程序主体开始 答案总数初值为0 读入A 调用递归过程,输入值A及’’(空字符串)
这又是一个典型的递归算法,下面我们看一个回溯算法。 [例7、7]八皇后问题,要在国际象棋棋盘中放八个皇后,使任意两个皇后都不能互相吃,共有多少种放法,全部打印出来。 分析:皇后能吃同一行、同一列、同一对角线的任意棋子。所以,我们可以这样考虑:在每一行中放一个皇后,从第一行开始,在往每新的一行加皇后时,我们必须确保这个皇后必须不能与已经取得的所有皇后都不在同一列或同一条对角线。我们定义一个数组来存放八个皇后的在1到8行中的列位置,所以形式参数就可以只要一个----行号,当行号达到9时,我们就找到了一个答案。这样,我们就能把所有答案找出来。
Program eight_queen(input,output);Uses crt; var a:array[1..8] of byte;     t:integer; procedure qu(n:byte); var k,x:integer;     b:boolean; begin   if n=9 then   begin     t:=t+1;     writeln(t);     for k:=1 to 8 do     begin       for x:=1 to 8 do if (a[k]<>x) then         write('.':3) else write('O':3);       writeln;     end;     writeln;     readln;   end else begin     for k:=1 to 8 do begin       b:=true;       for x:=1 to n-1 do begin         if (a[x]=k) or          (abs(a[x]-k)=abs(x-n)) then           b:=false;       end;       if b then begin         a[n]:=k;         qu(n+1);       end;     end;   end; end; begin   clrscr;   t:=0;   qu(1);   writeln;   writeln('      total ',T,' ');readln; end. 程序名调用CRT单元 定义数组A用来存放每行皇后的列位置 T用来存放答案总数 回溯过程名为QU 过程开始 如果N=9表达已经放了8个皇后,以下语句是打印这个结果 打印结束,此过程正常结束,返回上一层 以下语句为在第N行中放一个皇后 从第1列到第8列都可能 B用来判断是否能在第K列放皇后,初值为TRUE 此循环用来把已经放置的所有皇后与新皇后位置进行比较,如果同一列或同一对角线则B为FALSE. (a[l]=k) 是判断是否同列, (abs(a[l]-k)=abs(l-n))是判断是否同对角线 如果B仍为TRUE则表示第K列可放置皇后 记录第N行皇后的位置 调用下一层回溯,下一层是在第N+1行放皇后 程序主体开始 清屏 答案总数初值为0 调用回溯过程 打印答案总数
从上述程序中可以看出,回溯过程和递归过程的程序看起来完全是同一类型的,程序也几乎相同,都是定义了出口,然后中间就是调用过程,展开下一层节点。但实际运行过程中,回溯和递归是有差别的,递归是每次顺一条路往下走都能找到答案,然后才往回回溯;而回溯则不然,在中间某层时,就有可能走不通,下一层一个节点都无法展开,这时就只能在中途就回溯了。 如:我们把8皇后问题中简化为4皇后问题。如果我们的前两个皇后放的位置为:1、3,这时,第三个皇后是无法放下去的(为什么?),这时就只能回溯,返回第二层(这个返回是循环结束,正常结束此次过程,于是返回调用它的上一层过程),第二个皇后就放到第4个位置,位置变为:1、4,这时,再展开第3个皇后,可放在第三2个位置,位置变为:1、4、2,再展开第4个皇后,这时,第四个皇后又无法放下,于是返回第三层,第三层已别无选择,再返回第二层,仍无其它选择,于是返回第一层,第一个皇后放在第2个位置,再展开第二层,放第4个位置,再展开第三层,放第1个位置,再展开第四层,放第3个位置,这时,才找到第一个答案。 从这我们完全可以看出,递归在找到一个答案前,是不会中途回溯的;而回溯在找到第一个答案前有可能就已经回溯了好几次了。递归算法是往下展开时就一直往下走;而回溯则是中途可以任意返回,回溯是能进则进,不能进则退。两种算法的程序是相似的,但运行过程是不同的。 练习 请大家用递归或回溯算法完成下列各题: 1、  把正整数M分解成N个正整数之和。 2、  路径问题:已知下列各点之间的通向问题,请打印出由0至N(由键盘输入)的所有走法。
1   3   5   7   9
                 
0   2   4   6   8
提示:用一个10X10的数字矩阵(定义一个二维数组)来存放各点之间的相通情况,然后用递归从一点往另一点逐步展开,到目标点为止。如:我们定义的下列二维数组常量就说明了任意两点之间是否相通: const a:array[0..9,0..9] of integer=((1,1,0,0,0,0,0,0,0),                                         (0,1,1,0,0,0,0,0,0),                                         (0,0,1,1,0,0,0,0,0),                                         (0,0,0,1,1,0,0,0,0),                                         (0,0,0,0,1,1,0,0,0),                                         (0,0,0,0,0,1,1,0,0),                                         (0,0,0,0,0,0,1,1,0),                                         (0,0,0,0,0,0,0,1,1),                                         (0,0,0,0,0,0,0,0,0)) 3、  填数问题:从整数1至10中任取九中不同的数,填入下面九个格子中,使所有相邻(左、右、上、下)两个格子中数的和都是素数。试找出所有答案:
                    例如: 1 2 5
        4 3 8
        7 10 9
4、  中国象棋的马从半张棋盘的左下角跳到右上角,如果规定只许往右跳,不许往左跳,打印出所有的解。 5、  有一台阶共20级,标为0至20号,现从0级开始往上走,每次只能走一级或二级台阶,请打印出所有从0级走至20级的情况。 提示:每次往上走一级或二级台阶,所以我们的递归过程中也有两种调用下一层的情况:(1)当目前的级数小于20时,可往上走一级; (2)当目前的级数小于19时,可往上走二级。 即:我们可把当前在第几级作为形式参数N,当级数N=20时,就找到了一个答案。当N<>20时:如果N<20,则往上走一步;如果N<19则往上走二步。 6、  一张地图,有12个区域(如下所示),用四种颜色着色,要求相邻的区域不用同种颜色,问共有多少种方案?打印所有结果。                         12                         10       11         5                 4         9                          1        7      6          2             3     8 提示:用一个12X12的数字矩来表示任意两个区域是否相邻,然后在递归往1至12区域上着色时,就可判断该区域上能否用某种颜色。 7、  编一上程序将1,2,3……2N这2N个数排成一个圈,使每相邻数之和为素数。 第九章、顺序文本文件 文本文件在PASCAL语言中的使用是非常方便,它使我们能够把数据存放在磁盘文件中,也使人们能够从磁盘文本文件中读取大量数据。这是参加信息学竞赛必不可少的技能。 PASCAL语言的文件有几种,如:顺序文本文件、随机文件、类型文件等等。我们最常用的就是顺序文本文件,这也是使用最方便的文本文件。我们这里只介绍顺序文本文件。顺序文本文件只把数据按顺序存放到文件中,而不管数据的类型如何。如:如果文件中只有以下几个字符: 12345 当我们把这几个字符读出赋给一个整数型变量时,值就是12345;而如果读给一个字符串型变量时,值就是‘12345’。 一、             文件名     和DOS文件一样,PASCAL语言的顺序文本文件名也包括主名与扩展名,其中主名最多8个字符,扩展名最多3个字符。另外,文件名也可指定路径,如果不指定路径,则系统默认为当前目录。 二、文件说明:     说明一个顺序文本文件,即只需在变量说明中说明此文件的文件名对应的变量的类型应为TEXT型。如:VAR F1,F2:TEXT;即说明了两个顺序文本文件名变量。 三、几个命令: 1、  ASSIGN(文本文件变量,文件名):把文件名赋给一个文本文件名变量。如:ASSIGN(F1,‘T1.TXT’);即把变量名F1定义为对应T1.TXT这个DOS文件。这样,我们在使用这个文件时,就可直接用F1这个变量来调用。 2、  RESET(文本文件):打开文本文件,文件准备好被读。如:RESET(F1);这样,F1对应的文本文件就可用以下语句来读了。此时,文件的指针定位在第一行的第一个数据。 3、  READ()/READLN():从已打开的文本文件中读数据。如:假设F1对应的顺序文本文件名为:T1.TXT,文件内容为: 12       345  312 A   AB   CD 当我们RESET(F1)后,文件的指什定位在12这个数据前。如果我们顺序用以下语句,功能分别为: READ(F1,A);       {A的值为12,此时指针指在345前} READLN(F1,B):     {B的值为345,此时312虽然没有被读出,但因为用READLN                       语句读数据,所有312将不被读出,而指针将换行,指向A} READLN(F1,D,E,F); {一次把该行三个数据都读出,分别赋给D、E、F三个变量                        (字符型),此时,指针已经指向文件结束位置} 4、  EOF();判断文件是否结束的函数。如:经过上述读取数据后,此时,EOF(F1)的值为TRUE。 5、  REWRITE(文件名变量):打开文本文件,准备重写文件内容。如:REWRITE(F1);此时F1对应的文本文件内容将被全部清除,文件指针指向头部,等待被写入新的数据。 6、  APPEND(文件名变量):打开文本文件,准备添加文件内容。如:APPEND(F1);此时F1对应的文本文件内容保持不变,文件指针指向文件结束位置,等待写新的数据,新的数据将被添加在此文件的后面。请大家注意上述两个语句的区别。 7、  WRITE(文件名变量,变量表)/WRITELN(文件名变量,变量表):往已经打开的数据文件中写入新的数据。如:当REWRITE(F1)后,如果我们用了以下语句: WRITE(F1,123); WRITE(F1,456); WRITELN(F1,‘   ’,789); WRITELN(F1); WRITELN(F1,‘A’,‘ ’,‘B’); 此时文件的内容已经变量为: 123456   789                               {注:此处为空行} A B 请大家注意此文件的结果,为什么会这样? 8、  CLOSE(文件名变量):关闭文本文件。任何一个用RESET,REWRITE或APPEND语句打开的文件,最后都必须用CLOSE语句来关闭文件。如:CLOSE(F1);关闭文件F1。 四、例题: [例8、1]把1到100这100个数字写到一个文本文件(ANSWER.TXT)中。 Var I:integer; F:text; Begin   Assign(f,’answer.txt’);   Rewrite(f);   For I:=1 to 100 do writeln(f,I);   Close(f); End. [例8、2]把以下文本文件中的十个整数读出来,然后按大小顺序写回此文件中。 NUMBER.TXT 3 5 7 1 2 8 12 54 14 9 程序如下: var f:text; n:array[1..10] of integer; I,j:integer; begin   assign(f,’number.txt’);   reset(f);   read(f,n[1],n[2],n[3],n[4]);   readln(f);   readln(f,n[5],n[6],n[7],n[8],n[9],n[10]);   close(f);   {此处语句为排序数组N,大家自已加入};   rewrite(f);   for I:=1 to 10 do writeln(f,I);   close(f); end.