PASCAL语言 基础教程二

PASCAL语言 / 2011年03月04日 12时46分 / 12136人浏览
第五章、选择结构 本章讨论程序的分支结构,其主要知识是布尔运算(逻辑运算)。 第一节、布尔运算(逻辑运算) 要判断“A>B”是否成立,其结果不是一个具体的数值,而是“真”或“假”,即“是”或“否”的问题。这类问题在我们日常生活中是很多的,诸如这类判断的问题,其结果都是只有两个:真或假,这就是我们所说的布尔运算(逻辑运算)。 一、             布尔常量和布尔变量 布尔型的常量或变量的值只有两个:TRUE(真)和FALSE(假)。要把一个变量定义成布尔类型,用的数据类型是:BOOLEAN。例如程序: var a,b:boolean; begin     a:=true;     b:=false;     …… end. 二、布尔表达式 布尔表达式有以下两种操作: 1、  关系运算符:=;<>; >; <; >=; <=,是用来进行关系操作(对比)运算的符号,其结果为BOOLEAN型。如:2=3,其结果为FALSE。*注意:这里的“=”与赋值符号“:=”是完全不同的,其作用和结果均不同。 2、  逻辑运算符:AND(逻辑和);OR(逻辑或);NOT(逻辑非)。是用来进行逻辑值的    逻辑运算的。如:(2=3)AND (4<>3),值为FALSE。 布尔表达式的运算顺序是:()à函数àNOTà*,/.DIV,MOD,AND,+,-,ORà>,<,>=,<=,<>,=。 布尔表达式中的逻辑运算如下表所示:a和b均为布尔型表达式或常/变量.
a b A and b A or b Not a Not b
true false false true false True
true true true true false False
false true false true true False
false false false false true True
由上可以看出: 1、  用AND运算时,左右两个值同为TRUE时,运算结果才为TRUE,即两个条件同时满足,结果才为TRUE。这就是我们平常所说的“和”。 2、  用OR运算时,左右两个值只需有一个为TRUE,运算结果就为TRUE,即两个条件满足其中一个,结果就为TRUE。这就是我们平常所说的“或”。 3、  用NOT运算时,只是把其后的逻辑值取反,即“非”。 4、  例:[例4、1]
Program q41;Var a,b,c,d:integer; P:boolean; Begin    A:=1;    B:=2;    C:=3;    D:=4;    P:=(a=b);    Writeln(p);    P:=((a<b) and (c<d));    Writeln(p);    Writeln((a>d) or (c>b)); End.  说明四个整数型变量 说明一个布尔型变量 程序开始 赋值 赋值 赋值 赋值 把(A=B)这个逻辑运算的结果赋给P,即P的值为FALSE 打印P 把((a<b) and (c<d))这个逻辑运算的结果赋给P 打印P 打印(a>d) or (c>b)这个逻辑运算的结果 程序结束
程序运行结果是: false true true 由上可以看出:逻辑运算中的关系运算均用括号“()”括起来。关系运算/逻辑运算的结果也是一个值(BOOLEAN型),所有布尔运算也是表达式,可以赋给一个变量,也可以直接用输出语句输出。打印输出时,屏幕上就显示“false”或“true”。 第二节、条件语句 条件语句是用一个布尔表达式的值来决定程序的走向。即程序提供一个分支,由布尔表达式的值来决定程序究竞运行哪个分支。即程序已经不是顺序结构了,而是提供了一个分支结构。每次只可能运行其中的一个分支。如下图所示:               ˇ  布尔表达式 
语句序列1
ˇ
语句序列2
ˇ
FALSE
ˇ
TRUE
ˇ  条件语句有两种格式: 1、if <布尔表达式> then <语句>; 2、if <布尔表达式> then <语句1> else <语句2>; 格式1的作用是:如果布尔表达式值为TRUE(即该条件满足),则运行语句,否则不运行任何语句。 格式2的作用是:如果布尔表达式值为TRUE(即该条件满足),由运行语句1,否则(即布尔值为FALSE,亦即条件不满足)就运行语句2。注意:只有条件语句结束时才有分号。 注意:如果条件语句中的分支语句不止一句,可用“begin……end;”来框住,加以区别。如:以下两个程序都为从键盘输入1个整数,打印出它的算术平方根。[例4、2]:
Program q421;Var a:integer; Begin    Readln(a);    If (a<0) then    Begin       Writeln(‘WRONG!’);    End else    Begin       Writeln(a);       Writeln(sqrt(a):8:2);    End; End. Program q421;Var a:integer; Begin    Readln(a);    If (a<0) then Writeln(‘WRONG!’) else Writeln(sqrt(a):8:2); End.
  条件语句的嵌套:条件语句是可以嵌套的,例如: if a>0 then if a>1 then …… else …… else ….; 上述语句看起来无法理解,但如果我们把它改写为以下形式时,就一目了然了: if a>0 then begin         if a>1 then begin             ……         end else begin             ……         end else begin         …… end;     也就是说,第二个IF语句只是第一个IF语句中的一部分,即嵌入的一个IF语句。 例:输入一个年份,判断它是否闰年。我们知道,每四年中有一年是闰年,即有366天,而其余三年是平年,只有365天,而按照规定:1、如果哪一年的年份能被4整除,则该年一般为闰年;2、这样,每100年又会少一天,所以又规定如果该年能被4整除,又能被100整除,则认为该年不是闰年,而是平年;3、这样,每400年又会多出一天,所以又规定,如果哪一年能被400整除,则该年又是闰年。     由上可知:1980,1996,1984年均为闰年,1900年为平年,而2000年为闰年。 程序如下:[例4、3]
Program q43;Var y:integer; Begin      Readln(y);      if (y mod 4=0) then begin         if (y mod 100=0) then begin            if (y mod 400=0) then begin               writeln('run');            end else begin                writeln('ping');            end;         end else begin              writeln('run');         end;      end else begin          writeln('ping');      end; end.  
  第三节、多分支语句 IF语句只能使程序有两个分支,当遇到需要有两个以上分支时,IF语句就很不适用了,这时我们可以用CASE语句,它能使程序有很多个分支。其效果如下图:
表达式
语句序列1
语句序列2
case
……
其格式为:
语句序列N
CASE 表达式 OF 常量1:语句序列1; 常量2:语句序列2; …… 常量N:语句序列N; else 语句序列N+1; END; 其中语句序列如果只有一句,可直接写在常量后的冒号后;如果语句序列有很多句,则应该用BEGIN……END加以框住。 CASE语句的作用是,根据表达式,表达式可以有多个值,分别对应于常量1、2等值时,就运行该常量后所对应的语句。 例:输入1到7之间的某个整数,打印出其对应的星期的英语名:[例4、4]: program q44; var n:integer; begin     write(‘n=’);     readln(n);     case n of         1:writeln(‘Monday’);         2:writeln(‘Tuesday’);         3:writeln(‘Wednseday’);         4:writeln(‘Thursday’);         5:writeln(‘Friday’);         6:writeln(‘Saturday’);         7:writeln(‘Sunday’);         else writeln(‘WORNG!’);     end; end. 例:输入一个学生的数值化成绩,把它转化为等级化成绩。即100-90是A,89-80是B,79-70是C,69-60是D,59-0是E。[例4、5];
Program q44;Var s:integer;    G:char; Begin    Write(‘Input the score:’);    Readln(s);    Case s div 10 of       10,9:g:=’A’;       8:g:=’B’;       7:g:=’C’;       6:g:=’D’;       else g:=’E’;    end;    writeln(s,’   ‘,g); end.  用S DIV 10这个表达式作条件; 当 S DIV 10等于10或9时,表示S是90至于100之间的值
  第四节、标号说明及转移语句 此节不用掌握 在几乎所有语言中,都有GOTO(转移)语句,其作用是当程序运行到该句时,自动转移到其指定的标号(行号)语句去执行。 说明语法:LABEL 标号;  如:LABEL 10,20; 转移语句用法:GOTO 标号; 例:[例4、5]: program q45; label 10; begin     10: write(‘*’); goto 10; end. 运行上述程序时,程序将在屏幕不停地打印出“*”,而不会停止,必须由用户按下CTRL+BREAK才能中断。 练习 1、  设X,Y,Z的值分别是FALSE,TRUE,FLASE。写出下列逻辑表达式的值: not x and not y; true and x or y; (x and z) or (z and y); x or z and y; 2、  编写一个程序,功能是从键盘输入一个整数,判断它是否二位数,如果是,就打印它,然后结束程序,否则继续要求输入数。 3、  编写一个程序,功能是从键盘输入三个整数,打印出其中最大的一个值。 4、  编写一个程序,功能是从键盘输入1—12中的某一个数字,由电脑打印出其对应的月份的英语名称。 5、  以下程序的功能是从键盘输入一个式子,它只有三个字符,第一个及第三个都是数字,中间那个是运算符,程序能把它的结果打印出来。试在程序空中填上相应的语句。     注意:计算机是不懂得把输入的字符串进行计算的,我们必须自己动手把其中的数字转化成数值型的数据,这其中我们使用了VAL函数,如程序中的:Val(s[1],a,c),是把S字符串中的第一个字符转换为数值A,同时输出了一个错误代码C(其实对我们是没有用的)。
Var a,b,d:real;    C:word;        S:string[3]; Begin    Readln(s);    Val(s[1],a,c);                    ;    Case s[2] of       ‘+’:d:=a+b;       ‘-’:d:=a-b;       ‘*’:       ;       ‘/’:d:=a/b;    end;    writeln(s,’=’,     );    end.  把S定义成三个字符的字符串; 把S串中的第一个字符转换为数值; 把S串中的第三个字符转换为数值; 用S串中的第二个字符作为条件表达式;
  第六章、重复结构 重复结构就是循环结构,是指某些语句需要重复执行而设定的程序结构。在PASCAL语言中,共有三种重复结构语句,功能各有不同。 第一节、直到语句  直到循环语句的语法格式是: repeat 语句序列;(循环体) until 布尔表达式; 其作用是:重复执行语句序列(循环体),直到布尔表达式的值为TRUE为止。即,当执行完一次语句序列后,布尔表达式的值已经为TRUE了,这时循环将不会再被执行,而转向执行UNTIL语句以下的语句。 例:计算M=1+2+3+4+……,直到M的值大于5050为止。[例:5、1] var m,I:integer; begin     m:=0;     I:=0;     Repeat         I:=I+1;         M:=m+I;     Until m>5050;     Writeln(I,’   ’,m); End. 在上述程序中,我们使用了PASCAL中的两个作用强大的概念:累加和循环。 累加:我们在上述程序中没定了两个累加器:I,M。累加器初值我们在第一句中设定了为0,之后每次运行一次I:=I+1后,I的值就比原来大1。每运行一次M:=M+I后,M的值就被M+I所替代。 循环:这里我们使用的是直到循环,即重复执行循环体中的两个语句,直到M>5050这个条件满足为止(即这个布尔表达式的值为TRUE为止)。 上述程序运行后,会在输出屏幕上显示两个值:101   5151。即当I的值为101时,这时所算得的M的值为5151。亦即,1+2+3+……101=5151。 象上述这种X=1+2+3+……这种加法,我们就把它叫累加,这里的X就是累加器,一般初值为0。 而N=1*2*3*4*5*6*……这种乘法我们把它叫累乘,这里N就是累乘器,一般初值为1(为什么?)。 一般的:1*2*3*……N,我们把这个式子的结果叫做N的阶乘(N!)。如:4!=1*2*3*4。 例:计算19![例5、2] var I:integer;    x:longint; begin    I:=0;    X:=1;    Repeat       I:=I+1;       X:=x*I;    Until I=19;    Writeln(x); End.    当程序开始时,I的初值被定为0,X的初值被定为1(累乘器)。然而开始进入循环,每次I的值比原来增加1,然后再乘进X中去,直到I等于20时,最后一次把I乘进X后,这时I=20这个条件已经满足(I=20的值已经为TRUE),所以循环就被退出,而程序转向执行UNTIL以后的语句:WRITELN(X);。    请大家想一想,为什么X要定义为LONGINT型。 第二节、当语句 当语句的语法格式是: while 布尔表达式 do begin    语句序列;(循环体) end; 其作用是,当布尔表达式的值为TRUE时,才会运行语句序列(循环体),否则循环将不会被执行,即从循环头部就退出,而转向执行END后的语句。 例:计算19![例5、3] var I:integer;    x:longint; begin    I:=0;    X:=1;    While I<19 do begin       I:=I+1;       X:=x*I;    End;    Writeln(x); End. 请大家把此程序与上一节的[例5、2]进行比较,看两种循环在运用时有何不同。 WHILE语句是在循环开始时就判断布尔表达式的值时否为TRUE,如果为TRUE,就进入循环,运行循环体,如果为FALSE,就不运行循环体,而直接转向执行END后的语句WRITELN(X);。 REPEAT与WHILE循环的示意框图如下所示:                 REPEAT                          WHILE
循环体
布尔表达式
循环体
true
false
布尔表达式
false
true
  从上述框图中可以看出,要使用循环语句时,必须要确定循环体及条件(布尔表达式)两个重要因素,亦即首要考虑的是:我要重复执行哪些语句,我要重复到什么时候为止! [例5、4],从键盘上输入两个整数M,N,求它们的最大公约数。 分析:我们只需从M,N中更小的一个数开始,每次让其减1,直到这个数能同时被M和N数整除为止。在下述程序中,我们在程序头部调用了CRT单元,是为了使用CLRSCR语句来清屏,即把输出屏幕上的字符清除干净。 Uses crt;                              {调用CRT单元} Var m,n,x:integer; Begin    Clrscr;                             {清屏}    Write(‘Please input 2 numbers:’)    Readln(m,n);    If m>n then x:=n else x:=m;    While (n mod x<>0) or (m mod x<>0) do begin       x:=x-1;    End;    Writeln(x); End.    上述程序如果改用REPEAT语句来做的话,程序为: uses crt; var m,n,x:integer; begin    write(‘Please input 2 numbers:’)    Readln(m,n);    If m>n then x:=n+1 else x:=m+1;    Repeat       X:=x-1;    Until (m mod x=0) and (n mod x=0);    Writeln(x); End. 请大家考虑上述两个程序为何会有这样有不同之处。 第三节、FOR循环语句 前面所计的两个语句都是在未知循环次数的情况下而用的循环语句,但在程序中,如果我们已经知道循环的次数而来编程序的话,就可以使用FOR循环语句,这也是PASCAL及其它高级语言中用得最多的语句。其语法格式有两种,如下: (1) 增量为1: for 变量名:=初值 to 终值 do begin    语句序列(循环体); end; (2) 增量为-1: for 变量名:=初值 downto 终值 do begin    语句序列(循环体); end; 变量名的类型由程序头部中定义,而其初值、终值必须和它是同一类型。该变量的类型是能是有序数据类型。 上述两种格式都是用变量的初值与终值来规定循环的次数。如以下两个小程序:
Var I:integer;Begin    For I:=1 to 5 do begin      Write(I);    End; End. 运行结果: 12345 Var I:integer;Begin    For I:=5 downto 1 do begin      Write(I);    End; End. 运行结果: 54321
由上可以看出FOR循环的作用。 [例5、5]:从键盘输入一个字符串,把它按正序及逆序分别输出: uses crt; var s:string;    l,I:integer; begin    clrscr;    write(‘Please input the string:’);    readln(s);    l:=length(s);    for I:=1 to l do begin       write(s[I]);    end;    writeln;    for I:=l downto 1 do begin        write(s[I]);    end; end.  [例5、6]计算 uses crt; var s,a:integer; begin    clrscr;    s:=0;    for a:=1 to 10 do begin       s:=s+a*a;    end;    writeln(s); end.    [例5、7]:计算:1+3+5+7+……101的值: uses crt; var m,n:integer; begin    clrscr;    m:=0;    for n:=0 to 50 do begin       m:=m+(2*n+1);    end;    writeln(m); end. 请大家注意上述程序中的几个小技巧,一个是FOR N:=0 TO 50,共循环51次;一个是M:=M+(2*N+1),其是的2*N+1得到的是一序列的奇数。 第四节、多重循环语句 多重循环语句即循环嵌套,也就是一个循环语句的循环体中还有循环语句。 [例5、8]编程序打印九九乘法表: uses crt; var I,j:integer; begin     clrscr;     for I:=1 to 9 do begin         for j:=1 to 9 do begin             write(j:1,’*’,i:1,’=’,I*j:2);         end;         writeln;     end; end. 运行结果:
1*1= 1 2*1= 2 3*1= 3 4*1= 4 5*1= 5 6*1=6 7*1= 7 8*1= 8 9*1= 9
1*2=2 2*2= 4 3*2= 6 4*2= 8 5*2=10 6*2=12 7*2=14 8*2=16 9*2=18
1*3=3 2*3= 6 3*3= 9 4*3=12 5*3=15 6*3=18 7*3=21 8*3=24 9*3=27
1*4=4 2*4= 8 3*4=12 4*4=16 5*4=20 6*4=24 7*4=28 8*4=32 9*4=36
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 6*5=30 7*5=35 8*5=40 9*5=45
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 7*6=42 8*6=48 9*6=54
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 8*7=56 9*7=63
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 9*8=72
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
    注意:循环有嵌套时,必须分清层次,切不可把循环进行交叉。 [例5、9]编程序分别打印以下三图: (1)                           (2)                           (3) *****                            *****                            ***** *****                             *****                          ***** *****                              *****                        ***** *****                               *****                      ***** *****                                *****                    *****
(1)Uses crt; Var I,j:integer; Begin   Clrscr;   For I:=1 to 5 do begin     For j:=1 to 5 do begin       Write(‘*’); End; Writeln;   End; End. (2)Uses crt; Var I,j:integer; Begin   Clrscr;   For I:=1 to 5 do begin     Write(’:20+i);     For j:=1 to 5 do begin       Write(‘*’); End; Writeln;   End; End. (3)Uses crt; Var I,j:integer; Begin   Clrscr;   For I:=1 to 5 do begin     Write(’:20-I);     For j:=1 to 5 do begin       Write(‘*’); End; Writeln;   End; End.
请大家注意看清上述三个小程序,其功能是分别打印出上述三个由“*”组成的小图形。三个图形的不同之处是:第一个直上直下,是个矩形;第二个是左斜的平行四边形;第三个是右斜的平行四边形。所以三个对应的程序也就有所不同,第(2)、(3)个程序比第(1)个多了一句,即加粗加线的那一句。这两句的作用是使每一行开头打印几个空格,即让图形左或右斜。WRITELN的作用是打印完一行后换行。 [例5、10]编程打印下列图形:             1            222           33333          4444444         555555555
Uses crt;Var I,j:integer; Begin   Clrscr;   For I:=1 to 5 do begin Write(‘ ’:20-I); For j:=1 to 2*I-1 do begin   Write(I:1); End; Writeln;   End; End.  清屏 打印每一行前的20-I个空格,这样每行都比上一行左移 每一行打印2*I-1列 打印该行行数
[例5、11]打印1—100间的所有素数: 素数,即为除了1和它本身外没有另外的因数的整数。所以我们判断一个数N是否素数,可以用2至N-1所有数去除N,如果没有一个数能被N整除,则N为素数。 当然,其实我们可以不用用2至N-1这第多的数去除,而只需用2至不大于N的平方根的整数去除N即可(为什么)? 这里我们的程序就用2至TRUNC(SQRT(N))来判断,到后面我们还会谈到:如果要判断一个数是否素数,可只用小于TRUNC(SQRT(N))的所有素数去除即可。
Var I,j:integer;    P:boolean; Begin   For I:=2 to 100 do begin     P:=true; For j:=2 to trunc(SQRT(I)) do begin   If I mod j=0 then p:=false; End; If p then write(I:5);   End; End.  循环从2至100 再判断I是否素数前,先把判断器P的值设为TRUE 用2至trunc(SQRT(I))的数来除I 如果I能整除J,则P的值改为FALSE 如果P的值仍为TRUE,则I就是素数,打印出来
[例5、12]以下是A,B,C三人说的话: A:“B在说谎”;B:“C在说谎”;C:“A、B都在说谎”。现在问,到底谁说真话,谁说谎? 分析:A、B、C三人,要么说谎,要么说真话,即三个的状态要么为FALSE,要么为TRUE,所以,可让A、B、C三个变量进行循环,循环初值为TRUE,终值为FALSE。而三个人所说的话即为三个逻辑表达式,其值也为TRUE或FALSE,并且与A、B、C的值是有关系的。A、B、C三个所说的话转化为逻辑表达式即为: A:B=FLASE; B:C=FALSE; C:(A=FALSE) AND (B=FALSE) 以上三个逻辑表达式的值中,TRUE的个数应该与A、B、C三个变量中TRUE的个数相同。并且,每一个变量的值应该与其对应的话的逻辑表达式的值相等。如:A应该等于(B=FALSE)这个逻辑表达式。程序如下:
Var a,b,c:boolean;Begin   For a:=false to true do begin     For b:=false to true do begin        For c:=false to true do begin          If (a=(b=false)) and (b=(c=false)) and (c=((a=false) and (b=false)))          then Begin            Writeln(a:10,b:10,c:10);         End;       End; End;   End; End.
  第五节、练习 1、  随机产生一些1—100之间的整数,直到产生的数为50为止。 2、  计算1—1000之间能同时被3和5整除的整数的和。 3、  打印下列图形:                     1                    121                   12321                  1234321                   12321                    121                     1 4、  一百匹马驮一百块瓦,一匹大马可以驮3块,一匹母马可驮2块,小马2匹可驮1块。试编程求需要各种马多少匹? 5、  有三种纪念邮票,第一种每套一张售价2元,第二种每套一张售价4元,第三种每套9张售价2元。现用100元买了100张邮票,问这三种邮票各买几张? 6、  赵、钱、孙、李、周五人围着一张圆桌吃饭。饭后,周回忆说:“吃饭时,赵坐在钱旁边,钱的左边是孙或李”;李回忆说:“钱坐在孙左边,我挨着孙坐”。结果他们一句也没有说对。请问,他们在怎样坐的? 7、找数。一个三位数,各位数字互不相同,十位数字比个位、百位数字之和还要大,且十位、百位数字之和不是质数。编程找出所有符合条件的三位数。     注:1. 不能手算后直接打印结果。         2. “质数”即“素数”,是指除1和自身外,再没有其它因数的大于1的自然数。 8、选人。一个小组共五人,分别为A、B、C、D、E。现有一项任务,要他们中的3个人去完成。已知:(1)A、C不能都去;(2)B、C不能都不去;(3)如果C去了,D、E就只能去一个,且必须去一个;(4)B、C、D不能都去;(5)如果B去了,D、E就不能都去。编程找出此项任务该由哪三人去完成的所有组合。 9、输入一个字符串,内有数字和非数字字符。如A123X456Y7A,302ATB567BC,打印字符串中所有连续(指不含非数字字符)的数字所组成的整数,并统计共有多少个整数。 10、A、B、C三人进入决赛,赛前A说:“B和C得第二,我得第一”;B说:“我进入前两名,丙得第三名”;C说:“A不是第二,B不是第一”。比赛产生了一、二、三名,比赛结果显示:获得第一的选手全说对了,获得第二的选手说对了一句,获得第三的选手全说错了。编程求出A、B、C三名选手的名次。 11、甲、乙、丙、丁四人共有糖若干块,甲先拿出一些糖分给另外三人,使他们三人的糖数加倍;乙拿出一些糖分给另外三人,也使他们三人的糖数加倍;丙、丁也照此办理,此时甲、乙、丙、丁四人各有16块,编程求出四个人开始各有糖多少块。 12、截数问题: 任意一个自然数,我们可以将其平均截取成三个自然数。例如自然数135768,可以截取成13,57,68三个自然数。如果某自然数不能平均截取(位数不能被3整除),可将该自然数高位补零后截取。现编程从键盘上输入一个自然数N(N的位数<12),计算截取后第一个数加第三个数减第二个数的结果。 13、从键盘输入一段英文,将其中的英文单词分离出来:已知单词之间的分隔符包括空格、问号、句号(小数点)和分号。     例如:输入:There are apples; oranges and peaches on the table.     输出:there           are           apples           oranges           and           peaches           on           the           table 14、山乡希望小学收到一箱捐赠图书,邮件上署名是“兴华中学高二班”,山乡希望小学校长送来了感谢信,可是兴华中学高二年级有四个班,校长找来了四个班的班长,问他们是哪 个班做的这件好事。一班的班长说:“是四班做的。”二班的班长说:“是三班做的好事。”三班的班长说:“不是我们班。” 四班的班长说:“三班的班长说的不对。”     四个班的班长都说不是自己班做的,这就难坏了校长,后来得知四个班的班长中有两个 说得是真话,有两个没有说真话,请你利用计算机的逻辑判断编一个程序,找出究竟是哪个班做了这件好事。不能手算后直接打印结果。 15、A,B,C,D,E五个人合伙夜间捕鱼,凌晨时都疲惫不堪,各自在河边的树丛中找地 方睡着了,日上三竿,E第一个醒来,他将鱼数了数,平分成五分,把多余的一条扔进河中,拿走一份回家去了,D第二个醒来,他并不知道有人已经走了,照样将鱼平分成五分,又扔掉多余的一条,拿走自己的一份,接着C,B,A依次醒来,也都按同样的办法分鱼(平分成 五份,扔掉多余的一条,拿走自己的一份),问五人至少合伙捕到多少条鱼。     也许你能用数学办法推出鱼的条数,但我们的要求你编出一个程序,让计算机帮你算出鱼的总数。 16、试编程找出能被各位数字之和整除的一切两位数。 17、一个正整数的个位数字是6,如果把个位数字移到首位,所得到的数是原数的4倍,试编程找出满足条件的最小正整数。 18、某本书的页码从1开始,小明算了算,总共出现了202个数1,试编程求这本书一共有多少页? 19、从键盘上输入两个不超过32767的整数,试编程序用竖式加法形式显示计算结果。 例如: 输入 123, 85       显示: 123            + 85          ---------             208   20、有30个男人女人和小孩同在一家饭馆进餐,共花了五十先令,其中男宾3先令,女宾2先令,小孩1先令。试编程求出男人女人小孩各多少人? 第七章、数组、集合与自定义数据类型 第一节、数组 在一个程序中,如果所要用到的常量、变量不多,并且彼此之间无序列化的联系,我们一般定义成不同的常/变量名即可。但如果要用到的常/变量个数很多,彼此之间有着序列化的联系时,我们就会把它们定义成一个数组。数组—即一序列的数(各种类型的数据)组成的一个数据的序列。这些数据共用一个名称,只不过下标不同。 例如:在我们的数学学习中,在解一元二次方程时,方程有两个解,我们会分别用X1、X2来表示。而在PASCAL语言中,我们用X[1]、X[2]来表示,即下标是放在中括号中的。 一、一维数组 数组如果要使用的话,就必须先在程序头部的常量/变量说明中先说明,说明语法是: 变量名:ARRAY[下标初值..下标终值] OF 数据类型; 如:VAR N:ARRAY[1..10] OF INTEGER; 作用是说明一个名为N的整数型数组,可用的下标为1至10,即可用10个变量。 再如:CONST M:ARRAY[1..5] OF CHAR=(‘A’,‘B’,‘C’,‘D’,‘E’); 作用是说明了一个名为M的字符型数组常量,下标范围为1至5,因为是常量,所以在后面指明了这五个常量的值分别为:‘A’,‘B’,‘C’,‘D’,‘E’。 在程序头部说明了数组后,在程序中就可以使用了,使用方法为:常/变量名[下标号]。如,M[1]即调用M[1]这个常量,其值为‘A’。 [例6、1]从键盘输入10个整数,然后把它们排序,从大到小打印出来。 分析:排序是各种语言中的一个必需掌握的要点。排序有很多种方法,但不论是哪种方法,都是把这些据存放在一个数组中,然后再对其进行排序操作。排序一般有以下几种方法: 1、  双数组法:再定义另一个与存放数据数组同类型的数组,然后把数据数组中最大的一个数找出来,存放为另一数组中的第一个;再找第二、第三个等等。其中的细节问题就是:在数据数组中找到最大的一个后,就把它的值赋成一个非常小的值,然后再找最大的一个,这样就能顺序把数据从大到小存放到另一个数组中,也即排好了序。 2、  冒泡法:这是最常用的一种排序方法,其实质是:先把数据存放在数组中,然后从第一个开始,分别与其后所有数据进行比较,如果第一个比其后某个数据小,则交换它们的值,一直到第一个与其后所有数据比较完,这时第一个数据就是最大的一个;然后再把第二个数据再与其后数据进行比较,比较完后,第二个数据则为第二大的,这样直到倒数第二个数据比较完后,整个数组就已经按从大到小的顺序排列了。其作用示意如下:        假设我们已经把6个数据分别存放在N[1]至N[6]中,其值分别为:3,1,5,9,2,6。
交换前的值为: 3,1,5,9,2,6
第一步,把第一个值与其后第一个进行比较,这时3>1,所以值不变: 3,1,5,9,2,6
第二步:把第一个值与其后第二个进行比较,这时3<5,所以值交换: 5,1,3,9,2,6
第三步:把第一个值与其后第三个进行比较,这时5<9,所以值交换: 9,1,3,5,2,6
…… ……
当第一个值与其后所有值比较完后,第一个值已经是最大的,数组值为: 9,1,3,5,2,6
这时,重复上述第一步的操作,只是把第一个值换成第二个值,第一个值即第二个值与其后第一个值进行比较,这时1<3,所以交换其值: 9,3,1,5,2,6
第二个值与其后所有值比较完后,数组值为: 9,6,1,3,2,5
再重复进行第三个值与其后值的比较,直到第五个值与第六个值比较完后,这时数组的值已经变为: 9,6,5,3,2,1
至此,数组已经按从大到小的顺序排好了。  
程序如下 :[例6、1]
Var n:array[1..10] of integer;I,j,t:integer; Begin   For I:=1 to 10 do Readln(n[I]);   For I:=1 to 9 do begin For j:=I+1 to 10 do begin   If n[I]<n[j] then begin     T:=n[I];     N[I]:=n[j];     N[j]:=t;   End; End;   End;   For I:=1 to 10 do begin Write(n[I]:5);   End; End. 说明一个数组型变量从键盘读入10个数据存放在数组N中 参加比较的第一个数据为第1至第9个。 第二个数据为第一个数据之后所有的数据 如果n[I]<n[j]则用以下三句来交换其位置 打印排序后的结果
  二、二维数组 1、  矩阵:我们在PASCAL语言中接触到的一般是数字矩阵,如: 1 2 3 4 5 6 3 4 5 6 7 9 1 5 8 9 4 2 7 5 3 2 1 7 如果要存放这样的矩阵数据,我们可以定义几个数组来存放,每个数组存放一行或一列,但最好的办法是定义一个二维数组来存放。二维数组有两个下标,可以分别对应矩阵中的行号、列号,从而能更加方便的存取数据。定义的语法是:     变量名:ARRAY[下标初值1..下标终值1,下标初值2..下标终值2] OF 数据类型; 例如:VAR A;ARRAY[1..4,1..6] OF INTEGER; 数组A就可存放上述矩阵的所有数值。或者定义一个常量:    CONST B:ARRAY[1..4,1..6] OF INTEGER=((1,2,3,4,5,6),                                          (3,4,5,6,7,9),                                          (1,5,8,9,4,2),                                          (7,5,3,2,1,7));     这样我们就能在程序直接使用,如:B[1,5]是指第一行的第五个数据,即5;B[3,2]指第三行第二个数据,即5,等等。 第二节、集合     集合是一序列有共同性质或联系的数据组成的一个集体。如日常生活中所说的:一个班的全体同学;一个书架上所有的书等。而在PASCAL语言中,集合一般都是指一系列的数值或字符等数据,如:小于10的正整数;26个英语字母等。集合也象常/变量一样有自己的名字,即集合名,它是在程序头部象定义变量一样来定义的。 定义集合:VAR 集合名:SET OF 数据类型; 这里需要注意的是:集合只能定义成整数(byte)、布尔型或CHAR型的。 如:VAR S:SET OF byte; 其作用是定义了一个整数型的集合S。 集合的赋值:集合的值实际上应该是一些数据的总和。一个集合的值(元素)是用中括号“[]”括起来的。如: S:=[];是把S赋成一个空集合。 S:=[1,2,4];是把S赋成一个有三个元素的集合。 集合的运算:集合的并、交、差运算及关系运算。 1、  并:用运算符“+”:即把两个集合的元素合并。如:S:=[1,2]+[4,5];是把S赋值成四个元素。 2、  交:用运算符“*”:即取两个集合的相同元素。如:S:=[1,2,3]*[3,4,5];这时S的值被赋成了一个元素[3]。 3、  差:用运算符“-”:即取属于前一集合但不属于后一集合的元素。如:S:=[1,2,3]-[2,5,6];这时S的值被赋成了[1,3]。 4、  关系运算:这是在PASCAL语言中集合概念最重要的部分,是用来判断集合之间或集合与元素之间关系的运算。有以下几种: A、=:判断两个集合的元素是否完全相同; B、<>:判断两个集合是否不相等; C、>=:包含; D、<=:包含于; E、IN:存在于。即用来判断一个元素是否存在于一个集合中。 第三节、自定义数据类型 PASCAL语言不仅直接提供大量的可直接使用的数据类型,还提供了功能强大的扩展自定义功能,用户可以自己定义适合自己程序中使用的数据类型。这种自定义数据类型同样是在程序头部加以说明,引导字是TYPE,定义好类型后,就可能把常/变量定义成这种类型了。这样的自定义数据类型有两种定义方式,分别是:枚举类型、子界类型。 一、             枚举类型 日常生活中的一个星期中的每天的名称:SUNDAY、MONDAY等,颜色的名称:RED、BLUE等,如果我们的PASCAL程序中要使用这些数据的话是很不方便的,所以我们可以使用自定义枚举类型来使它运用起来更加方便。 定义语法如下:TYPE 类型名=(标志符); 如:TYPE COLOR=(RED,BLUE,GREEN,YELLOW,BLACK,WHITE);          WEEKDAY=(SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY);          MONTH=(JAN,FEB,MAR,APR,MAY,JUN,AUG,SEP,OCT,NOV,DEC); 这样,我们就能在定义常/变量时把常/变量定义成这些类型。如: VAR C:COLOR;     W:WEEKDAY;     M,N:MONTH; 在程序中,我们使用上述四个变量时,它们的值只能是对应的类型中的值。如:C这个变量的值就只能是:RED,BLUE,GREEN,YELLOW,BLACK,WHITE。 注意:枚举类型的数据是有序的。即可用函数:PRED()前趋;SUCC()后续。这两个函数的用法我们将在下面介绍。 枚举类型数据的运算: 1、  赋值:如:C:=BLUE;              W:=FRIDAY; 2、  判断:如:BLUE>GREEN的值为TRUE; 3、  函数:PRED()、SUCC()、ORD()。因为枚举类型是有序的,所以可以使用上述三个和序数有关的函数。如: A、  SUCC(FRIDAY)的值为SATURDAY;即FRIDAY之后的一个值。 B、  PRED(YELLOW)的值为GREEN。即YELLOW之前的一个值。 C、  ORD(BLUE)的值为2;即BLUE在其对应的枚举类型中排在第二位。 二、子界类型 子界类型也是自定义数据类型中的一种。在上一节的枚举类型中我们知道,枚举类型是把一种数据类型所有的值都列举出来。而当需要自定义的类型是一序列连续的数据,并且数量很大时,枚举类型就不适合了,这时,我们就会采用子界类型。子界类型,顾名思义,就是当数据是连续的时,可以指定其上界及下界来定义。定义方法与枚举类型相似。 TYPE 类型名称=上界..下界; 如:TYPE YEAR=1900..2000;是定义一个名为YEAR的数据类型,其值可取为1900—2000。 再如:TYPE NUMBER=1..9;            CHARACTER=’a’..’z’; 上述语句定义了两个子界类型的变量,第一个NUMBER的取值为1至9;第二个CHARACTER的取值为小写字母‘a’至‘z’。 三、记录类型 记录型数据类型是PASCAL语言中做搜索问题中一定要用到的数据类型,所以,它在PASCAL语言中占着非常重要的地位。学过数据库管理软件的人都知道,在数据库文件中,有一个非常重要的概念—记录,例如:一个人的各门成绩,一个人的各种信息(姓名、性别等等),我们都把它们存放成一条记录而给予一个统一的名称。 1、 记录说明:记录类型和枚举类型一样,都要在程序头部用TYPE引导说明。语法如下: TYPE 类型名称=RECORD 域变量1:基类型; 域变量2:基类型; ………… END; 然后在常/变量说明中就要以用这种类型了。在程序中使用必须指定变量名与域名。 [例6、2]编一程序,用来记录20个学生的姓名、年级、班级、性别、语文成绩、数学成绩、总分,平均分。 Type student=record     Name:string;     Grade,class,chinese,mathe,sum:integer;     Average:real;     Male:boolean; End; Var s:array[1..20] of student;     I,j:integer; Begin     For I:=1 to 20 do begin         Write(‘please input the student’s name,grade,class,male,chinese,mathe);         Readln(s[I].name);         Readln(s[I].grade);         Readln(s[I].class);         Readln(s[I].male);         Readln(s[I].chinese);         Readln(s[I].mathe);         S[I].sum:=s[I].chinese+s[I].mathe;         S[I].average:=s[i].sum/2     End; ………… {如果程序要求打印或排序,只需在此增加这些功能语句} end. 第四节、字符串 在PASCAL语言中,字符串的处理是非常方便的,在定义字符串时,我们不仅可以定义成CHAR型(单个字符);STRING型(任意个字符);STRING[N]型(指定只有N个字符)。在后两种类型中,我们都可以使用:变量名[I],来指定字符串中的第I字符,以便得到它的值或对其赋值。而且,我们还可以使用如下函数对字符串进行各种操作: 1、  CHR(N):返回N(ASCII码)对应的字符。如:CHR(66)的值是’b’; 2、  UPCASE(C):把字符串全部转成大写字母。 3、  CONCAT(S1,S2):把两个字符串相加,如:CONCAT(‘ABC’,‘123’)的结果是‘ABC123’; 4、  COPY(S,M,N):这是很有用的一个函数,它的作用是取字符串S第M个字符开始的N个字符作为一个新的子串。如:COPY(‘ABCDE’,3,2)的值是‘CD’; 5、  LENGTH(S):求字符串S的长度。如:LENGTH(‘ABCD’)的值是4; 6、  DELETE(S,M,N):与COPY的功能正好相反,作用是把字符串S的第M个字符开始的N个字符删除掉。如DELETE(‘ABCDEF’,3,2)的结果是‘ABEF’; 7、  INSERT(S1,S2,N):把字符串S1插入到字符串S2中,插在S2的第N个字符。如:INSERT(‘ABCD’,‘12345’,2)的结果是:‘1ABCD2345’。 8、  POS(S1,S2):这是一个非常有用的函数,其作用是判断S1是否是S2的子串,返回结果是:(1)如果是子串,只返回S1在S2中的起始位置;(2)如果不是子串,则返回0。如:POS(‘123’,‘ABCDEF’)的值为0;POS(‘AB’,‘BABCD’)的值为2; 另外,我们还可以使用如下几个过程: 1、  STR(N,S):这是一个过程,作用是把N这个数值转化为S这个字符串。如:STR(123,S),作用是把S的值赋成了‘123’; 2、  VAL(S,N,CODE):这也是一个过程,作用是把S这个字符串转化为N这个数值,并且同时返回CODE这个错误代码(整数型)。如:VAL(‘135’,N,C);作用是把N的值赋成了135这个数值,而且返回C这个错误代码。为什么会有错误代码呢?大家看这个语句是否错误,错在哪里:VAL(‘12ABC’,M,C); [例6、3]把26个英语字母正向、逆向打印出来。 Const s:string[26]=’abcdefghijklmnopqrstuvwxyz’; Var t:string[26]; I:integer; Begin   t:=’                          ‘;           {共26个空格}   For I:=1 to 26 do begin T[I]:=s[27-I];   End;   Writeln(s);   Writeln(t); End. [例6、4]找出所有的四位回文数:(回文数就是一个数从左往右读与从右往左读都是同一个数) var s:string[4]; n:integer; begin   for n:=1000 to 9999 do begin str(n,s); if (s[1]=s[4]) and (s[2]=s[3]) then write(n:6);   end; end. 或者用如下程序: var n:integer; s,t:string; begin   for n:=10 to 99 do begin str(n,s); t:=s+s[2]+s[1]; write(s:6);   end; end. 上述两个程序,哪个快,哪个慢?