該內容爲學習 《PASCAL程序設計 第2版》鄭啓華編著 的筆記,部分與c語言對比學習,方便記憶。
函數與過程程序設計
函數
1. 定義:
FUNCTION <函數名>(<參數表>):<函數類型>;
<說明部分>;
BEGIN
<函數體>
END;
- 函數體由給函數名賦值的語句構成,函數類型即函數的返回值類型,返回的是函數名的最終結果。
- 如果沒有參數,則括號也不需要。
- 如果有多種類型的參數,相同參數之間用逗號,不同參數之間用分號。
- 如果函數中需要用到變量,需在說明部分定義,爲局部變量。
2. 調用:
<函數名>(<實在參數表>)
如果沒有實在參數,則括號也略去。
3. 例子:
定義函數rand產生隨機數,使得生成一些兩位整數x兩位整數的式子,作答後判斷正誤。
PROGRAM game(input, ouput);
VAR
x, y, z, answer: integer;
seed: real;
{產生一個[0,1)的隨機數}
FUNCTION rand(VAR seed:real):real;
CONST
a= 93.0;
m = 8192.0;
c = 1.0;
BEGIN
seed := a*seed+c;
{seed/m - trunc(seed/m)獲取了seed/m的小數部分,其再乘以m,獲得一個[0,m)的數}
seed := round( (seed/m - trunc(seed/m)) * m );
{seed的範圍爲[0,m),計算得出的rand爲[0,1)}
rand := seed/m;
END;
{主程序}
BEGIN
seed := 0.7823;
REPEAT
{產生2個兩位的隨機整數x, y}
x := trunc(rand(seed)*100);
y := trunc(rand(seed)*100);
writeln(x:2, '*', y:2, '=?');
read(answer); {輸入算式答案}
{判斷正確與否}
z := x*y;
if answer=z
then writeln('yes!')
else writeln('no! it is ', z)
UNTIL answer=-1
END.
- 函數定義中,參數表中的VAR表明形式參數seed爲變量參數,若沒有VAR則爲值參數。
- 變量參數的改變會影響是實在參數的值,值參數的改變不影響實在參數的值。
上述例子中,rand函數爲產生隨機數的某種方法,可得到一個[0,1)之間的數。爲了使每次獲得的隨機數不同,需定義函數中的參數seed爲變量參數,隨着函數的調用而改變參數的值。
輸出結果:
0*84=?
0
yes!
13*98=?
4567
no! it is 1274
83*26=?
543
no! it is 2158
69*34=?
435
no! it is 2346
20*27=?
345
no! it is 540
過程
1. 定義:
PROCEDURE <過程名>(<形式參數表>);
<說明部分>;
BEGIN
<過程體>
END;
- 參數表中包括值參數和變量參數,過程的結果由變量參數送回,可以包括多個結果或無結果。
- 過程體的通常任務是對值參數進行計算,計算結果賦值給變量參數。
- 無參數時,形式參數表和括號都應略去。
2. 調用:
<過程名>(<實在參數表>)
過程的調用必須作爲一個單獨的語句。
3. 例子:
打印表頭。
PROGRAM table(input, ouput);
{打印表頭}
PROCEDURE printhead;
VAR
i: integer;
BEGIN
for i:=1 to 21 do
write('*');
writeln;
writeln('* this is the table *');
for i:=1 to 21 do
write('*');
writeln;
END;
{主程序}
BEGIN
printhead;
END.
該過程既無結果也無參數,輸出:
*********************
* this is the table *
*********************
對比
- 函數通過函數名回送一個結果值,需說明返回值的類型;過程的結果由參數送回,可以包括多個結果或無結果。
- 函數體中必須要有給函數名賦值的語句,過程體不需要也不能有。
- 函數的調用可以出現在表達式中,過程的調用必須作爲一個單獨的語句。
例:輸入x值,計算y。有 , 。
函數實現:
PROGRAM ysh1(input, ouput);
VAR
x, y: real;
{函數}
FUNCTION sh(t:real):real;
BEGIN
sh := (exp(t)-exp(-t))/2;
END;
{主程序}
BEGIN
read(x);
y := sh(1+sh(x))/(sh(2*x)+sh(3*x));
writeln('x=', x, ', y=', y);
END.
過程實現:
PROGRAM ysh2(input, ouput);
VAR
x, y, s1, s2, s3: real;
{過程}
PROCEDURE sh(t:real; VAR s:real);
BEGIN
s := (exp(t)-exp(-t))/2;
END;
{主程序}
BEGIN
read(x);
sh(x, s1);
sh(1+s1, s1);
sh(2*x, s2);
sh(3*x, s3);
y := s1/(s2+s3);
writeln('x=', x, ', y=', y);
END.
輸入輸出結果:
5
x= 5.0000000000000000E+000, y= 1.3899708997173883E+026
函數與過程作爲參數
作爲參數的函數或過程本身只能有值參數。使用:
PROGRAM test(input, output);
VAR
s1, s2: real;
FUNCTION f1(p1:real):real;
BEGIN
...
END;
FUNCTION f2(function f(p:real):real; a:real):real;
BEGIN
...
END;
BEGIN
read(s1);
s2 := f2(f1, s1);
END.
嵌套與遞歸
1. 嵌套:
形式1:定義2個並列的函數,主程序可以調用2個函數,函數2能調用函數1,函數1不能調用函數2。
PROGRAM test(input, ouput);
VAR
x1, x2, y1, y2: real;
FUNCTION fun1(p1:real):real;
BEGIN
...
END;
FUNCTION fun2(p2:real):real;
BEGIN
...
fun2 := fun1(p2);
END;
BEGIN
read(x1, x2);
y1 := fun1(x1);
y2 := fun2(x2);
writeln(y1, y2);
END.
形式2:在函數1中定義函數2,則函數1能調用函數2,函數2不能調用函數1,主程序只能調用函數1。
PROGRAM test(input, ouput);
VAR
x1, y1: real;
FUNCTION fun1(p1:real):real;
FUNCTION fun2(p2:real):real;
BEGIN
...
END;
BEGIN
fun1 := fun2(p1);
END;
BEGIN
read(x1);
y1 := fun1(x1);
writeln(y1);
END.
形式3:第一種情況中加上向前引用說明和保留字FORWARD,則函數1和2能互相調用。
PROGRAM test(input, ouput);
VAR
x1, x2, y1, y2: real;
FUNCTION fun2(p2:real):real;
forward;
FUNCTION fun1(p1:real):real;
BEGIN
...
fun1 := fun2(p1);
END;
FUNCTION fun2;
BEGIN
...
fun2 := fun1(p2);
END;
BEGIN
read(x1, x2);
y1 := fun1(x1);
y2 := fun2(x2);
writeln(y1, y2);
END.
類似於c的聲明,不過一般很少有函數要互相調來調去,按順序寫就好了,或者乾脆所有函數都聲明。
2. 遞歸:
- 直接遞歸:函數1直接調用其本身。
- 間接遞歸:函數1調用函數2,函數2又調用函數1。
例:遞歸計算 n! 。
PROGRAM facn(input, ouput);
VAR
x, y: integer;
FUNCTION fac(n:integer):integer;
BEGIN
if n=0
then fac := 1
else fac := n*fac(n-1)
END;
{主程序}
BEGIN
read(x);
y := fac(x);
writeln(x, '!=', y);
END.
輸出結果:
3
3!=6
枚舉與子界
枚舉
1. 定義
TYPE
<枚舉類型標識符> = (<標識符>, ..., <標識符>);
VAR
<枚舉類型變量表>: <枚舉類型標識符>;
枚舉值只能是標識符(以字母開頭的字母數字組合),每個枚舉值只能出現在一個枚舉類型定義中,並且只能在該定義中出現一次。
例:
TYPE
day = (sunday, monday, tuesday);
month = (jan, feb, mar);
VAR
payday, firstday: day;
yearend, curmonth: month;
2. 運算
可以將枚舉值直接賦值給枚舉變量,或者同類型的枚舉變量賦值給另一個枚舉變量,例:
{枚舉值賦給枚舉變量}
curmonth := mar;
firstday := monday;
{枚舉變量賦給同類型枚舉變量}
payday := firstday;
枚舉變量可進行ord,pred,succ和關係運算,例:
{序號從0開始}
ord(jan) = 0
{第一個枚舉值無前導,最後一個枚舉值無後繼}
pred(monday) = sunday
succ(monday) = tuesday
3. 使用
枚舉類型不能直接read和write,可用其序號與CASE結合使用。
子界
1. 定義
TYPE
<子界類型標識符> = <常量1>..<常量2>;
VAR
<子界類型變量表>: <子界類型標識符>;
- 子界只能是有序類型(整型,字符型,布爾型,枚舉型),不能爲實型。
- 程序執行時會先檢查存儲在子界類型變量中的值是否符合其定義要求,若錯誤,會停止程序打出錯誤信息。
枚舉型的子界:
TYPE
day = (sun, mon, tue, wed, thu, fri, sat);
schoolday = mon..fri;
2. 運算
和其基類型運算一樣,只是限制了自身的值的範圍。
數組類型
一維數組
1. 定義
TYPE
<數組類型標識符> = array[<下標類型> of <基類型>];
VAR
<數組變量表>: <數組類型標識符>;
- 與c不同,下標從1開始。
- 值的表示和c語言相同,a[1]表示數組a的第1個元素值。
- 下標類型可爲:布爾,字符,枚舉,子界(1..10屬於子界類型而不是整型)。
- 基類型可以是任何標準類型或用戶定義類型,包括數組類型(字符串數組)。
例:day爲枚舉類型,數組類型art1由7個整型元素組成,art2由24個布爾類型元素組成。
TYPE
day = (sun, mon, tue, wed, thu, fri, sat);
art1 = array[day]of integer;
art2 = array['a'..'z']of boolean;
VAR
c: art1;
d: art2;
2. 使用
上述實例中數組類型art1值可能的對應關係如下:
c[sun] | c[mon] | c[tue] | c[wed] | c[thu] | c[fri] | c[sat] |
23 | 5 | 3454 | 33 | 57 | 24 | 543 |
基本與c語言相同,以下2句效果等價:
{a, b爲同類型的數組,下標1-10}
b := a;
for i:=1 to 10 do
b[i] := a[i];
多維數組
1. 定義
TYPE
<數組類型標識符> = array[<下標類型1>, ..., <下標類型n>]of <基類型>;
例:
TYPE
mat = array[1..5, 1..10]of real;
VAR
a, b: mat;
2. 使用
和c相同,a[i][j] 表示上述二維數組的某一元素。
緊縮字符數組
當數組元素爲字符型和布爾型時,按上述定義方式每個字節佔用一個存儲單元,假設每個存儲單元由32個二進位構成,則會造成空間浪費。因爲字符型僅需8個二進位,布爾型爲1個二進位。
1. 定義:
VAR
a: array[1..10]of char;
b: packed array[1..10]of char;
a爲一般字符數組,b爲緊縮字符數組。
2. 緊縮字符數組相當於一個字符串,可以執行整體讀語句:
readln(b);
輸入:abcdefg
結果:b爲(abcdefg ),結尾補3個空格
輸入:abcdefghijk
結果:b爲(abcdefghij),超出定義長度,多餘部分去除
3. 對b進行整體賦值和比較操作要求長度相同:
b := 'abcdefj'; {錯誤}
b := 'abcdefg '; {正確}
4. 通常在存儲字符數組和處理字符串時用b的形式以節約存儲空間,而在處理每個字符時用a的形式以節約訪問時間。pascal提供了2個標準過程用於a和b之間的轉換:
{將非緊縮數組a的第n個下標開始的元素存儲到緊縮數組b中,存儲的元素個數爲b的長度}
pack(a, n, b);
{將b的所有元素存儲到a中,存儲從a的第n個位置開始}
unpack(b, a, n);
通常上述的 n 寫爲 1。
保形數組參數
在數組作爲參數時,實在參數和形式參數的下標的上下界可以不一致,實在參數不得超過形式參數所允許的下標界限。
VAR
a: array[1..4, 1..4]of real;
b: array[1..6, 1..6]of real;
PROCEDURE pro(var a:array[l1..u1:integer; l2..u2:integer]of real);
...
過程pro可以以數組a, b爲實際參數進行運行,即使a, b的下標界限不相同。