pascal語言基礎(三)

該內容爲學習 《PASCAL程序設計 第2版》鄭啓華編著  的筆記,部分與c語言對比學習,方便記憶。

pascal語言基礎(一)

pascal語言基礎(二)

 

集合類型

定義

TYPE
    <集合類型標識符> = set of <基類型>;
VAR
    <集合類型變量表>: <集合類型標識符>;

基類型必須是有序類型(整型子界、字符型、布爾型、枚舉型等),例:

TYPE
    digit = set of 1..9;
VAR
    od, even: digit;
BEGIN
    od := [1, 3, 5, 7, 9];
    even := [2, 4, 6, 8];

 

運算

在處理集合前,一般需要賦予初值(常爲空集或全集):

od := [];        {空集}
od := [1..9];    {全集}

1. 並交差(要求2集合類型相容)

{並,+}
[1, 3, 4] + [1, 2, 4] --> [1, 2, 3, 4]
['a', 'c', 'f'] + ['b', 'c', 'd', 'f'] --> ['a', 'b', 'c', 'd', 'f']

{交,*}
[1, 3, 4] * [1, 2, 4] --> [4]
['a', 'b'] * ['c', 'd'] --> []

{差,-}
[1, 3, 4] - [1, 2, 4] --> [3]
['a', 'b', 'c'] - ['a', 'c', 'b'] --> []

集合中順序不重要。

2. 關係運算(=、<>、<=、>=)

關係運算的結果爲布爾型:

{=和<>用來檢查2個集合是否包含同樣的元素}
[1, 3] = [3, 1] --> true
[1, 3] <> [1, 3] --> false

{<=用來決定子集關係}
[1, 3] <= [1, 2, 3, 4] --> true
[] <= [1, 3] --> true

{>=用來決定包集關係}
[1, 3] >= [1, 3] --> true
[2, 4] >= [1, 2] --> false

另有新運算 IN ,用於決定一個特定的元素是否在集合中:

1 in [1, 2, 3] --> true
1 in [3,2 4] --> false

以下2種寫法等價:

(ch>='0') and (ch<='9')
ch in ['0'..'9']

3. 輸入和輸出

集合變量不能直接輸入輸出,輸入通常爲:將集合置爲空集,然後逐個讀入集合的每個元素值,將構成的單指集合依次+進原集合變量;輸出通常爲:用IN依次檢查該集合基類型中的每一個元素是否在該集合中,若在則依次輸出對應元素。

例:輸入一串字符,以'?'結束,組成元音字母集合s1,輔音字母集合s2,然後輸出兩集合元素以及元素個數。

PROGRAM sets (input, output);
  VAR
    s1, s2: set of 'a'..'z';
    n1, n2: integer;
    ch: char;
  BEGIN
    s1 := [];
    s2 := [];
    n1 := 0;
    n2 := 0;

    read(ch);
    write(ch);
    while ch<>'?' do
      {判斷輸入的ch是元音還是輔音,加入對應的集合}
      BEGIN
        if ch in ['a'..'z']
          then if ch in ['a', 'e', 'i', 'o', 'u']
                   then s1 := s1+[ch]
                   else s2 := s2+[ch];
        read(ch);
        write(ch); 
      END;
    writeln;

    {輸出}
    for ch:='a'to'z' do
      if ch in s1
        then BEGIN
               write(ch);
               n1 := n1+1;
             END;
    writeln;
    writeln('n1=', n1);

    for ch:='a'to'z' do
      if ch in s2
        then BEGIN
               write(ch);
               n2 := n2+1;
             END;
    writeln;
    writeln('n2=', n2);
    
  END.

可能的輸入輸出:

sdgdgdffdsvsdgda?
sdgdgdffdsvsdgda?
a
n1=1
dfgsv
n2=5

 

類型間的關係

關係:同一、 相容、賦值相容。

符合如下任一條則說明兩個變量屬於該關係:

同一(對稱) 相容(對稱) 賦值相容(不對稱,e對v賦值相容,v:=e)

1. 使用同樣的類型標識符說明

2. 類型標識符不同,但已被形如t1=t2的說明定義爲等價

3. 在同一變量說明語句中使用

1. 它們是同一的非結構變量

2. 它們是同一類型的子界,或一個是另一個的子界

3. 它們是有相容的基類型的集合類型

4. 它們是具有同一長度的串類型

5. 整型和實型之間

1. e和v是類型同一的非文件類型

2. v是實型,e是整型或整型的子界

3. e和v是相容的簡單類型,且e的值是v所允許的值

4. e和v是相容的集合類型,且e的每一個值都是v所允許的值

5. e和v是相容的串類型

 

三者之間不存在蘊含關係,關係圖如下:


 

記錄類型

記錄是2個或多個有關數據項的彙集,一個記錄的每個分量可以具有不同的類型,類似於c語言中的結構體。

定義

TYPE
  <記錄類型標識符> = RECORD
                     <域標識符表>: <類型>;
                     ...
                     <域標識符表>: <類型>
                   END;

域標識符表可以是一個標識符或多個標識符,在多個標識符的情況下,每個標識符之間用 ','(逗號) 隔開。

年月日的記錄如下:

TYPE 
  mont = (jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec);
  date = RECORD
           month: mont;
           day: 1..31;
           year: integer
         END;
VAR
  day1, day2: date;

 

WITH語句(開域語句)

一般形式:

with <記錄變量名錶> do
  <語句>

語句可以是單條語句,或是用BEGIN..END括起來的多條語句。

對記錄的賦值:

{原始的賦值方法}
day1.month := mar;
day1.day := 3;
day1.year := 2020;
day2 := day1;

{使用with語句後}
with day1 do
  BEGIN
    month := mar;
    day := 3;
    year := 2020;
  END;

 

記錄數組

類似於c語言的結構體數組,一個數組的分量是記錄類型稱爲記錄數組(記錄數組首先是個數組,數組的分量是記錄)。

例:輸入全班學生的姓名和成績,按照某一標準給學生成績評定等級,最後輸出各位學生的姓名、成績、等級。

思路:定義一個記錄類型student,它的域包括姓名name,成績score,等級grade。其中name是一個字符串(由緊縮型數組定義),score是實型,grade是字符型。然後再定義一個記錄數組類型studenta,它的分量類型爲student,存儲班上所有學生的信息。

CONST
  n = 30;  {班級學生人數}
TYPE
  alfa = packed array[1..15]of char   {姓名的字符串}
  student = RECORD
              name: alfa;
              score: real;
              grade: char;
            END;
  studenta = array[1..n]of student;
VAR
  students: studenta;

給記錄數組賦值時:

with students[i] do
  BEGIN
    name := 'li hong        ';  {共15位}
    score := 93.5;
    grade := 'A';
  END;

 

層次記錄

記錄的域爲記錄類型,則爲記錄的嵌套,也就是層次記錄。類比多維數組,記錄的嵌套也可以是多重的。

例:職員的記錄類型,包括編號,姓名,生日,家庭地址。

TYPE
  alfa = packed array[1.15]of char;
  date = RECORD
           year: integer;
           month: 1..12;
           day: 1..31;
         END;
  address = RECORD
              city: alfa;
              street: alfa;
              streetnum: integer;
            END;
  employee = RECORD
               num: integer;
               name: alfa;
               birth: date;
               home: address;
             END;
VAR
  programmer: employee;

其中生日和家庭地址的類型是記錄,給該層次記錄賦值可寫爲:

programmer.num := 1;
programmer.birth.year := 1998;
programmer.home.city := 'changsha       ';

可使用with語句簡寫:

with programmer, birth, home do
  BEGIN
    num := 1;
    year := 1998;
    city := 'changsha        ';
  END;

需注意在with..do之間的順序問題,首先programmer必須在第一位。如果birth和home不是並列關係,那麼順序需層次漸進。

在上例中birth和home是並列的,如果這2條記錄中沒有同名的域名,那麼順序無所謂;如果有同名域名,爲了不引發問題,需分開寫:

with programmer, birth do
  BEGIN
    num := 1;
    year := 1998;
    with home do
      BEGIN
        city := 'changsha        ';
      END;
  END;

 

記錄變體

1. 一般形式:

TYPE
  <記錄類型標識符> = RECORD
                     {固定部分}
                     <域標識符表>: <類型>;
                     ...
                     {變體部分}
                     case <標誌域>: <類型> of
                       <常量表>: (<域表>);
                       ...
                   END;
  • 固定部分和變體部分出現的域名不能相同
  • 如果常量表中沒有對應的域,此時域表爲空,用一個()空括號對錶示
  • <域表>內也可以有變體部分,變體部分必須在對應的固定部分之後
  • case..of 可以不需要end作爲結束

2.  例:接上個例子,職員的記錄類型爲編號、姓名、生日、婚姻狀況。

其中,婚姻狀況爲,已婚、離異、單身。對於已婚的職員,需附加配偶姓名和孩子個數;對於離異的職員,需附加離婚日期;對於單身的職員,需附加是否單獨住。

TYPE
  alfa = packed array[1..15]of char;
  date = RECORD
           year: integer;
           month: 1..12;
           day: 1..31;
         END;
  marristat = (married, divorced, single);
  employee = RECORD
               {固定部分}
               num: integer;
               name: alfa;
               birth: date;
               {變體部分}
               case ms:marristat of
                 married: (spousename: alfa;
                           child: integer);
                 divorced: (divorcedate: date);
                 single: (livesalone: boolean); 
             END;

其中,marristat爲枚舉類型,ms是類型爲marristat的特殊域,稱爲標誌域。當ms取值爲married時,會附加定義2個域spousename和child,另2個分支不會被定義,因此此時programmer.spousename和programmer.child可以被引用,而programmer.livealone不存在。

在定義變體部分時,下面2句等價:

case ms:marristat of

ms: marristat;
case marristat of

3. 讀記錄

VAR
  marry, live: char;
BEGIN
  {讀固定部分}
  with employee, birth do
    readln(num, name, year, month, day);
  {讀變體部分}
  with employee do
    BEGIN
      {讀標誌域值}
      read(marry);
      if marry='m'
        then ms:=married
      else if marry='d'
             then ms:=divorced
      else ms:=single;
      {根據標誌域值讀附加域值}
      CASE ms OF
        married: readln(child, spousename);
        divored: with divorcedate do
                   readln(year, month, day);
        single: BEGIN
                  readln(live);
                  livesalone := (live='t');
                END;
      END;{end case}
    END;{end with}
END.

首先鍵盤輸入職員編號、姓名、生日的年月日,然後輸入一個字母m,d,s代表該職員的婚姻狀況。如果輸入的是m,則接着輸入孩子個數和配偶姓名;如果輸入的是d,則接着輸入離婚的年月日;如果輸入的是s,則接着輸入t或者f,t代表單獨住f代表不是。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章