huong dan hoc pascal

232
Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal NGÔN NGỮ LẬP TRÌNH PASCAL 1. Nguồn gốc Pascal là một trong các ngôn ngữ lập trình cấp cao được giáo sư Niklaus Wirth ở trường kĩ thuật Zurich (Thụy Sĩ ) thiết kế và công bố vào năm 1971. Ông đặt tên cho ngôn ngữ này là Pascal để tưởng nhớ đến Blaise Pascal, nhà toán học, triết học nổi tiếng của Pháp ở thế kỉ XVII, người đã sáng chế ra máy tính cơ khí đầu tiên cho nhân loại. Ngày nay, Pascal là một trong những ngôn ngữ lập trình bậc cao ưu việt nhất trong lĩnh vực giảng dạy và lập trình chuyên nghiệp. 2. Tính chất cơ bản: a) Pascal là một ngôn ngữ có định kiểu rõ ràng : _ Mọi biến và hằng của kiểu dữ liệu nào chỉ được gán các giá trị của đúng kiểu dữ liệu đó, không được tự do đem gán cho các giá trị của kiểu dữ liệu khác. _ Việc định kiểu một cách chặt chẽ như vậy khiến cho người lập trình luôn luôn phải có các biểu thức tương thích với nhau về kiểu dữ liệu. b) Pascal là một ngôn ngữ thể hiện tư duy lập trình có cấu trúc : _ Dữ liệu được cấu trúc hóa : từ dữ liệu đơn giản hoặc có cấu trúc đơn giản người lập trình có thể xây dựng các dữ liệu có cấu trúc phức tạp hơn. _ Mệnh lệnh được cấu trúc hóa : từ các lệnh chuẩn đã có, người lập trình có thể nhóm chúng lại với nhau và đặt giữa hai từ khóa Begin và End khiến chúng trở thành một ngôn ngữ phức tạp hơn gọi là lệnh hợp thành hay lệnh ghép. _ Chương trình được cấu trúc hóa : một chương trình có thể chia thành các chương trình con tổ chức theo hình cây phân cấp. Mổi chương trình con nhằm giải quyết một nhiệm vụ xác định cụ thể, điều này giúp cho người lập trình có thể giải quyết từng phần một, từng khối một và có thể cho nhiều người tham gia lập trình, mỗi người phụ trách một vài khối. 3. Các phần tử cơ bản của ngôn ngữ Pascal : a) Bộ kí tự : _ Bộ 26 chữ Latin : Chữ lớn : A, B, C, …, Z Chữ nhỏ : a, b, c, …, z _ Kí tự gạch nối : - _ Bộ chữ số thập phân : 0, 1, 2, …, 9 _ Các kí hiệu toán học : +, -, *, /, +, <, >, ( ), [ ] 1

Upload: lieu-vu-nang

Post on 03-Jan-2016

84 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

NGÔN NGỮ LẬP TRÌNH PASCAL1. Nguồn gốc

Pascal là một trong các ngôn ngữ lập trình cấp cao được giáo sư Niklaus Wirth ở trường kĩ thuật Zurich (Thụy Sĩ ) thiết kế và công bố vào năm 1971. Ông đặt tên cho ngôn ngữ này là Pascal để tưởng nhớ đến Blaise Pascal, nhà toán học, triết học nổi tiếng của Pháp ở thế kỉ XVII, người đã sáng chế ra máy tính cơ khí đầu tiên cho nhân loại.

Ngày nay, Pascal là một trong những ngôn ngữ lập trình bậc cao ưu việt nhất trong lĩnh vực giảng dạy và lập trình chuyên nghiệp.

2. Tính chất cơ bản:a) Pascal là một ngôn ngữ có định kiểu rõ ràng : _ Mọi biến và hằng của kiểu dữ liệu nào chỉ được gán các giá trị của đúng kiểu dữ liệu đó, không được tự do

đem gán cho các giá trị của kiểu dữ liệu khác._ Việc định kiểu một cách chặt chẽ như vậy khiến cho người lập trình luôn luôn phải có các biểu thức tương

thích với nhau về kiểu dữ liệu.

b) Pascal là một ngôn ngữ thể hiện tư duy lập trình có cấu trúc :_ Dữ liệu được cấu trúc hóa : từ dữ liệu đơn giản hoặc có cấu trúc đơn giản người lập trình có thể xây dựng

các dữ liệu có cấu trúc phức tạp hơn._ Mệnh lệnh được cấu trúc hóa : từ các lệnh chuẩn đã có, người lập trình có thể nhóm chúng lại với nhau và

đặt giữa hai từ khóa Begin và End khiến chúng trở thành một ngôn ngữ phức tạp hơn gọi là lệnh hợp thành hay lệnh ghép.

_ Chương trình được cấu trúc hóa : một chương trình có thể chia thành các chương trình con tổ chức theo hình cây phân cấp. Mổi chương trình con nhằm giải quyết một nhiệm vụ xác định cụ thể, điều này giúp cho người lập trình có thể giải quyết từng phần một, từng khối một và có thể cho nhiều người tham gia lập trình, mỗi người phụ trách một vài khối.

3. Các phần tử cơ bản của ngôn ngữ Pascal :a) Bộ kí tự :_ Bộ 26 chữ Latin :

Chữ lớn : A, B, C, …, ZChữ nhỏ : a, b, c, …, z

_ Kí tự gạch nối : -_ Bộ chữ số thập phân : 0, 1, 2, …, 9_ Các kí hiệu toán học : +, -, *, /, +, <, >, ( ), [ ]

b) Từ khóa :_ Từ khóa chung : Program, Begin, End, Procedure, Function …_ Từ khóa để khai báo : Const, Var, Type, Array, String, Record … _ Từ khóa của lệnh lựa chọn : If … Then … Else, Case … Of_ Từ khóa của của lệnh lặp : For … To … Do, While … Do_ Từ khóa điều khiển : With, Goto, Exit_ Từ khoá toán tử : And, Or, Not, In, Div, Mod

c) Tên chuẩn :Trong Pascal có các tên chuẩn sau đây :

Boolean, Char, Integer, Word, Byte, Real, TextFalse, True, MaxintAbs, Arctan, Chr, Cos, Sin, Eof, Eoln

1

Page 2: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Exp, Ln, Odd, OrdRound, Trunc, Sqr, Sqrt, Pred, SuccDispose, New, Get, Put, Read, ReadlnWrite,WritelnReset, Rewrite

d) Danh hiệu tự đặt : Trong Pascal, để đặt tên cho các biến, hằng, kiểu, chương trình con người ta dùng các danh hiệu. Danh hiệu của

Pascal được bắt đầu bằng một chữ cái, sau đó là các chữ cái, chữ số, dấu nối. Bài 2: CẤU TRÚC CHUNG CỦA MỘT CHƯƠNG TRÌNH PASCAL

1. Chương trình viết bằng Pascal gồm các phần sau:

Program Ten_chuong_trinh ;(* Phần khai báo dữ liệu *)Label …Const …Type …Var …(* Phần mô tả chương trình con *)Procedure …Fuction …(* Thân chương trình chính *)Begin …(* Các lệnh được viết ở đây *)End(* Kết thúc chương trình *)

2. Ví dụ:

Program Ve_hinh ; Var a, x : Integer ; {-----------------------------------------}Procedure Hinh_chu_nhat ; Begin Writeln ('*******') ; Writeln ('* *') ; Writeln ('* *') ; Writeln ('*******') ;End ;{-----------------------------------------}BEGIN Write ('Ve bao nhiêu hinh chu nhat : ') ; Readln (x) ; a := 0 ; Repeat a := a + 1 ; Hinh_chu_nhat ; Until a = x ;END.

2

Page 3: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

3. Giải thích sơ lược từng phần của chương trình: a) Phần tiêu đề:

Cho biết tên của chương trình Ví dụ : Program Ve_hinh ;

Phần này luôn được bắt đầu bằng từ khóa Program và chấm dứt bằng dấu " ; "Phần tiêu đề có thể không có cũng được.

b) Phần khai báo dữ liệu:Khai báo một biến là xác định rõ xem biến đó thuộc kiểu dữ liệu nào. Một chương trình

Pascal thường có các khai báo dữ liệu sau :Const (* Khai báo hằng *)…Type (* Khai báo kiểu dữ liệu mới *)…Var {Khai báo các biến}

Phần khai báo có thể có hoặc không, tuỳ theo nhu cầu.Ví dụ : Chương trình trên có các kiểu biến là a, x. Chúng thuộc kiểu dữ liệu Integer, tức là số

nguyên

c) Phần khai báo chương trình con:Phần này mô tả một nhóm lệnh được đặt tên chung là một chương trình con để khi thân

chương trình chính gọi đến thì cả một nhóm lệnh nào đó được thi hành.

Ví dụ :

Procedure Hinh_chu_nhat ; Begin Writeln (' ******** ') ; Writeln (' * * ') ; Writeln (' * * ') ; Writeln (' ******** ') ;End ;

Phần này có thể có hoặc không tùy theo nhu cầu.

d) Phần thân chương trình:Nằm giữa Begin và End, là các lệnh mà chương trình cần thực hiện. Sau từ End là dấu chấm

(.) để báo kết thúc chương trình.Phần này bắt buộc phải có đối với mọi chương trình.

Ví dụ : 

BEGIN Write (' I like Pascal ') ;END.

e) Dấu chấm phẩy:Dấu chấm phẩy (;) được dùng để ngăn cách câu lệnh của Pascal và không thể thiếu được.

3

Page 4: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

f) Lời giải thích:Các lời giải thích được đặt giữa hai kí hiệu : {} hoặc (* *)Phần giải thích này là phần trao đổi thông tin giữa người với người, máy sẽ bỏ qua

Ví dụ :

Var X : Integer ; (* Số hình vuông phải vẽ *)

Bài 3: KHÁI NIỆM CHUNG VỀ DỮ LIỆU VÀ KIỂU DỮ LIỆU

Chúng ta có thể định nghĩa dữ liệu (Data) là tất cả những gì được máy tính xử lý. Các loại dữ liệu cần tới máy tính xử lý có rất nhiều, tồn tại dưới nhiều dạng khác nhau về bản chất, về ý nghĩa, không riêng gì về số liệu mà còn là các kí tự, các mệnh đề logic, thể hiện qua các đối tượng cụ thể cần xử lý như tiền lương, địa chỉ, tên tuổi, văn bản, tín hiệu... Song nếu xét về phương diện điện tử thì máy tính chỉ hiểu các thông tin được biểu diễn dưới dạng mã nhị phân.Về phương diện ngôn ngữ bậc cao thì dữ liệu đã được khái quát hóa với các kiểu dữ liệu. Khi này, ta không cần quan tâm đến biểu diễn chi tiết trong máy tính của các kiểu dữ liệu.

Một kiểu dữ liệu (Data Type) được định nghĩa với 2 điểm chính :_ Một tập hợp các giá trị mà một biến thuộc kiểu đó có thể nhận được._ Trên đó xác định một phép toán.

Cần nhớ rằng một biến phải gắn liền với một kiểu dữ liệu và chỉ một mà thôi. Trong ngôn ngữ Pascal, kiểu dữ liệu có thể rất phức tạp nhưng nói chung đều được định nghĩa ra từ các kiểu đơn giản nhất, không có cấu trúc.

Kiểu vô hướng (Scalar Type) hay kiểu đơn giản (Simple Type) là kiểu dữ liệu gồm một tập các giá trị của nó được sắp xếp theo một thứ tự tuyến tính. Chúng ta sẽ nghiên cứu kĩ hơn về kiểu vô hướng và các kiểu dữ liệu phức tạp khác. Trong phần tiếp theo, sẽ nói về 5 kiểu dữ liệu vô hướng đơn giản nhất, đã được định nghĩa sẵn và còn được gọi là kiểu đơn giản chuẩn (Simple Standar Type).

_ Trước khi đi vào nghiên cứu các kiểu số nguyên và kiểu số thực quen biết, chúng ta hãy xét khái niệm kiểu Logic ( Boolean ). Trong thực tế chúng ta thường hay gặp loại đại lượng chỉ có hai giá trị : Đúng hoặc Sai. Ví dụ một mệnh đề, một câu hỏi, một phép toán... có thể được xem xét xem đúng hay sai. Ví dụ khi ta viết 3 < 1 thì đây là một mệnh đề có giá trị là Sai.

_ Theo định nghĩa, một giá trị thuộc kiểu logic Boolean là một đại lượng nhận một trong hai giá trị Logic: TRUE (đúng) hoặc FALSE (sai). True và False là tên các giá trị đã được định nghĩa sẵn. Kiểu Boolean cũng đã định nghĩa sẵn quan hệ thứ tự False < True.

_ Các phép toán sau có thể áp dụng cho các giá trị Boolean và cho ta kết quả cũng là kiểu Boolean.

+ Phép And ( phép "và" logic )+ Phép Or ( phép "hoặc" logic )+ Phép Not ( phép "đảo" hay "phủ định" logic ) + Phép Xor ( phép "hoặc triệt tiêu" ).

Ví dụ1 : False And True = False

4

Page 5: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Not False = True

_ Chúng ta có thể tóm tắt quy tắc thực hiện phép And và Or như sau : + Phép And chỉ cho kết quả là True khi và chỉ khi hai toán hạng đều là True. + Phép Or chỉ cho kết quả là False khi và chỉ khi hai toán hạng đều là False. + Phép Xor luôn luôn cho kết quả là True khi hai toán hạng khác nhau. Còn nếu hai toán hạng giống nhau, Xor sẽ cho kết quả là False.

* Hai vế của biểu thức so sánh phải cùng kiểu nhau ( trừ kiểu thực và nguyên ) và chúng có thể là các kiểu Real, Integer, Char, Boolean, Vô hướng do người sử dụng định nghĩa (sẽ học sau ).

Ví dụ 2 : 3 < 5 cho ta giá trị True False < Truecho ta giá trị True 3.5 > 10 cho ta giá trị False

Cách viết 3 < True là không chấp nhận được vì hai vế của biểu thức không cùng kiểu cho phép : 3 thuộc kiểu số nguyên, True thuộc kiểu Boolean

Kiểu số nguyên đã được máy định nghĩa sẵn với từ khóa INTEGERMột giá trị kiểu số nguyên là một phần tử của tập các số nguyên mà ta có thể biểu diễn

được trên máy, nghĩa là nó là một tập nhỏ của không gian các số nguyên chứ không phải tất cả mọi số nguyên đều có thể xử lý trên máy tính được. Thông thường nhất, các số nguyên được biểu diễn bằng hai byte (16 bit) nên phạm vi của nó là từ -32768 đến + 32767

Các số nguyên được viết ra bằng các dãy chữ số 0, 1, 2,... 9 với chữ số đầu có thể là dấu dương + hoặc dấu âm -, hoặc không có dấu.

Ví dụ : +234, -32767, -1, 23 Maxint là tên giá trị cực đại cho phép của kiểu nguyên, tức là Maxint = + 32767.

a) Các phép tính số học đối với số nguyên:

_ Phép cộng và trừ : với kí hiệu là + và - như thường lệ. _ Phép nhân : được kí hiệu bằng dấu *._ Phép chia : được kí hiệu bằng dấu /._ Phép chia lấy phần nguyên được thực hiện với từ khóa Div.Ví duï : 14 Div 4 cho giá trị bằng 3 _ Phép chia lấy số dư của 2 số nguyên, còn gọi là Modun, được thực hiện với từ khóa ModVí duï : 14 Mod 4 cho giá trị bằng 2

_ Hàm Boolean Odd(n) cho giá trị True nếu n là một số lẻ, False nếu n là số chẳn.* Khi thực hiện các phép tính số học đối với số nguyên, cần hết sức thận trọng xem các phép toán đó có cho kết quả vượt ra khỏi phạm vi biểu diễn số nguyên của máy không.

Ví dụ : 32000 + 800 - 2000 = 29200 song máy tính sẽ xử lý sai vì lúc làm phép cộng giữa 32000 với 800 đã cho ra kết quả trung gian là 32800, vượt quá giới hạn 32767 của máy. Máy có thể phát hiện và báo lỗi trường hợp quá giới hạn này.

b) Các phép tính quan hệ đối với số nguyên: Các số nguyên có thể so sánh với nhau và với số thực qua các phép toán quan hệ như

đã nói ở mục trước. Kết quả của phép toán quan hệ là kiểu Boolean tức là có giá trị True (Đúng) hoặc False (Sai).

5

Page 6: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Ví dụ : Biểu thức 3 < 5 cho ta giá trị True

c) Mô tả số nguyên với Byte, Word, LongInt, ShortInt :Bên cạnh cách biểu diễn số nguyên như ở trên (biểu diễn bằng 2 byte), Pascal còn có thêm

một kiểu đơn giản chuẩn làkiểu biểu diễn số nguyên bằng một byte. Phạm vi biểu diễn số nguyên khi này là từ 0 đến 255 và được gọi là kiểu Byte.

Ngoài ra, Turbo Pascal từ Version 4.0 trở đi và một số Pascal khác đã đưa thêm vào các định nghĩa kiểu số nguyên mới với các từ khoá Word, ShortInt (Short Integer), LongInt (Long Integer).

Kiêu Pham vi biêu diênKích thuoc (byte)

Byte 0... 255 1ShortInt -128... 127 1

Integer -32768... 32767 2

Word 0... 65535 2LongInt -2147483648... 3147483647 4

1. Kiểu số thực (Real): Tương tự như định nghĩa kiểu số nguyên, kiểu số thực là tập hợp các số thực có thể biểu diễn được trong máy tính và được máy định nghĩa sẵn với từ khóa REAL. Các phép toán cộng (+), trừ (-), nhân(*), chia (/) cũng như các phép toán quan hệ (=, < >,

<, >, > =, <=) đều có thể áp dụng cho các toán hạng là số thực lẫn toán hạng là số nguyên.* Lưu ý : không tồn tại các phép toán Div, Mod cho kiểu số thực.

Trong máy tính, các số thực được biểu diễn và được viết dưới 2 dạng : dạng bình thường và dạng có phần số mũ.

+ Dạng viết thập phân bình thường như :3.14 3.0 -13.2 - 0.002

* Lưu yù : trong cách viết số thực của Việt Nam, của Pháp..., người ta dùng dấu phẩy. Nhưng trong cách viết số thực của Anh, Mĩ, người ta dùng dấu chấm + Dạng viết có số mũ :

Gồm 2 phần : phần định trị và phần mũ viết sau chữ E để biểu diễn số mũ cơ số 10.

Ví duï : 623.12345 = 6.2312345E + 02

Do giá trị số thực có thể biểu diễn dưới dạng có dấu phẩy (hay dấu chấm) di động được nên người ta còn gọi đây là cách biểu diễn dấu phẩy động để phân biệt với cách biểu diễn số dưới dạng dấu phẩy tĩnh là cách biểu diển trong đó dấu phẩy cố định.

2. Mở rộng việc mô tả và khai báo số thực :

Kiêu Pham vi biêu diênKích thuoc (byte)

Real 2.9E-39... 1.7E+38 6Single 1.5E-45... 3.4E+38 4

Double 5.0E-324... 1.7E+308 8

6

Page 7: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Extended 1.9E-4951... 1.1E+4932 10

Các hàm sau đây được định nghĩa sẵn và được sử dụng với đối số là các số thực hoặc các số nguyên :

+ Abs(x) : cho ta giá trị tuyệt đối của toán hạng x : | x |. Kiểu kết quả cùng kiểu với đối số, nghĩa là nếu x là thực thì Abs(x) cũng là số thực, nếu x là số nguyên thì Abs(x) cũng là số nguyên. + Sqr(x) : Cho giá trị bình phương của x. Kiểu kết quả cùng kiểu với đối số x. + Các hàm sau áp dụng cho đối số nguyên hoặc thực nhưng kết quả thì luôn luôn là kiểu

thực : - Sin(x), Cos(x), Arctan(x) : là các hàm lượng giác bình thường. - Sqrt(x) : tính căn bậc hai của x. - Succ(x) : đối số nguyên n, cho số nguyên tiếp theo n, tức là n + 1. - Pred(x) : đối số nguyên n, cho số nguyên trước n, tức là n - 1. - Odd(n) : đối số nguyên n, True nếu n lẻ, False nếu n chẵn.

Việc chuyển một số thực sang số nguyên được thực hiện bởi 2 hàm chuẩn : hàm làm tròn và hàm cắt :

+ Hàm cắt Trunc(x) cho ta một số nguyên là phần nguyên của x, tức là cắt bỏ đi phần lẻ thập phân của x.Ví dụ : Trunc (3.146) = 3. + Hàm làm tròn Round(x) cho ta một số nguyên của x bằng cách qui tròn phần lẻ thập phân của x. Nói cách khác, Round(x) cho ta số nguyên gần với x nhất. Ví dụ : Round (56.678) = 57.

Chúng ta có thể viết định nghĩa của Round qua Trunc như sau :+ Nếu x >= 0 thì Round(x) = Trunc(x + 0.5)+ Nếu x < 0 thì Round(x) = Trunc(x - 0.5)

Máy tính điện tử không chỉ có khả năng xử lý các dữ liệu bằng số nguyên, số thực mà nó còn có khả năng xử lý các dữ liệu kiểu kí tự như khi ta soạn thảo văn bản, quản lý hồ sơ.

Các kí tự là tất cả các chữ viết mà ta thường dùng như các chữ cái a, b, c..., các chữ số từ 0 đến 9, các dấu phân đoạn như ;, !,... Kiểu kí tự được định nghĩa trong Pascal với từ khóa Char.

Một giá trị kiểu kí tự là một phần tử của một tập hữu hạn các kí tự được sắp xếp có thứ tự. Tất cả các máy tính đều dùng tập kí tự như vậy để trao đổi thông tin qua các thiết bị vào ra. Có nhiều cách sắp xếp bộ chữ khác nhau và không tồn tại bộ chữ chuẩn cho tất cả các máy tính.

Tuy vậy một bộ mã các kí tự được dùng rất phổ biến để trao đổi các thông tin giữa các thiết bị nhất là trên máy vi tính, đó là bộ mã kí tự ASCII (xem ở phần Phụ lục).

Trong bảng mã ASCII, các kí tự từ 0 đến 31 là các kí tự điều khiển, không in ra được, dùng để điều khiển các thiết bị ngoại vi, điều khiển các thủ tục trao đổi thông tin. Ví dụ khi thiết bị nhận kí tự số 7 (Bel), máy sẽ ra một tiếng chuông. Kí tự số 27 (Esc) cũng thường dùng để thoát khỏi các tình huống, để nhận biết các mã đặc biệt khác như điều khiển máy in bằng dãy kí tự bắt đầu là Esc...

Phần còn lại trong bảng mã ACSII bố trí toàn bộ các chữ cái A, B, C..., các chữ số từ 0 đến 9, các dấu chấm câu, các kí tự đặc biệt... Ví dụ khi nhận kí tự số 50 máy sẽ hiện lên màn hình chữ số 2.

Riêng kí tự 127 (Del) lại được dùng làm kí tự điều khiển xóa. Nếu bạn dùng Editor , phím Del trên màn hình chính là phím tạo ra mã số 127 để xóa một kí tự trên màn hình.

7

Page 8: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Có 2 hàm chuẩn là Ord và Chr cho phép thiết lập tương quan giữa bộ mã kí tự và một tập con các số tự nhiên

+ Ord( ) - Hàm Ord('c') cho ta số thứ tự của kí tự 'c' trong bảng mã.+ Chr( ) - Hàm Chr(n) cho ta kí tự có số thứ tự là n.

Hàm chuẩn Pred (trước) và Succ (tiếp theo sau) có thể áp dụng cho đối số là kí tự, kết quả là kí tự. Giả sử Ch là một kí tự nào đó, vậy thì :

+ Hàm chuẩn Pred(Ch) cho ta một kí tự nằm trước kí tự Ch trong bảng mã kí tự : Pred(Ch) = Chr(Ord(Ch) - 1)

+ Hàm chuẩn Succ(Ch) cho ta một kí tự nằm sau kí tự Ch trong bảng mã kí tự : Succ(Ch) = Chr(Ord(Ch) + 1)

1. Khai báo hằng:Hằng là các đại lượng không thay đổi giá trị. Có các loại hằng số (nguyên và thực), hằng kí tự,

hằng Boolean. Khai báo hằng : các hằng (hằng số, hằng kítự, hằng Boolean) được khai báo bằng một tên đặt trong phần khai báo Const ở đầu chương trình.

Cách viết : Tên_hang := Giá_tri_cua_hang ;

Một dòng khai báo hằng được kết thúc bằng dấu chấm phẩy. Tên hằng được viết theo quy tắc viết tên đã trình bày ở chương trước.

Ví dụ :

Const B = True ; (* hằng Boolean *) A = 5 ; (* hằng số nguyên *) Pi = 3.14 ; (* hằng số thực *) CCC = ‘Z’ ; (* hằng kí tự *)

* Các hằng giữ nguyên giá trị của nó trong suốt chương trình.

2. Khai báo biến:Biến (variance) là đại lượng có thể thay đổi giá trị. Tên biến của chương trình là tên của ô nhớ cất

giữ dữ liệu. Khác với hằng, biến có thể thay đổi đựoc giá trị của nó. Các biến được khai báo bằng cách đặt tên các biến vào phần khai báo biến ở đầu chương trình, sau từ khóa Var.

Cách viết : Tên_biên : Kiêu_du_liêu_cua_biên ;

Dấu hai chấm bắt buộc phải có để ngăn cách hai phần của khai báo biến. Dấu chấm phẩy kết thúc một dòng khai báo.

Nhiều biến có cùng kiểu có thể đựoc khai báo với nhau bằng cách viết tên các biến đặt cách nhau qua dấu phẩy (,) như các biến M23, A25, AAA ở ví dụ dưới đây :

Var M23, A25, AAA : Real ; My_name : String [ 25 ] ; Y : Boolean ; X : Integer ;

8

Page 9: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

a) Chúng ta đã làm quen với khái niệm kiểu dữ liệu ở trên. Đối với các kiểu dữ liệu cơ sở (real, Integer, Byte, Char, Boolean) đã được Pascal định nghĩa sẵn nên khi khai báo biến ta có thể dùng trực tiếp các kiểu dữ kiệu này ngay. Còn các kiểu dữ liệu khác thì ta phải định nghĩa ra, mô tả một cách tường minh trong phần khai báo của chương trình sau từ khóa Type. Sau đó sẽ khai báo các biến thuộc kiểu dữ liệu mới mô tả. Chúng ta sẽ dần dần tìm hiểu sau này.

b) Cách khai báo

Type Tên kiêu = Mô ta xây dung kiêu ;

Ví dụ:

Type SoNguyen = integer ; Ten = String[11] ; Tuoi = 1.. 100 ; Color = (Red, Blue, Green) Thu = (ChuNhat, ThuHai, ThuBa, ThuTu, ThuNam, ThuSau, ThuBay) ;

Và khi đã khai báo kiểu thì ta có quyền sủ dụng để khai báo biến.

Ví dụ:

Var I, J : SoNguyen ; Khach_hang : Ten ; T : Tuoi ; Mau : Color ; Ngay_hoc : Thu ;

Biểu thức (Expression) là một công thức tính toán để có một giá trị theo một quy tắc toán học nào đó. Một biểu thức bao gồm : toán tử (operator) và toán hạng (operand). Toán tử đựoc viết ra bằng dấu phép toán. Toán hạng có thể là hằng, là hàm, là biến. Các phần tử của biểu thức có thể được phân thành số hạng, thừa số, biểu thức đơn giản.

Ví duï: 3 + PI * Sin ( x) ;

Trong ví dụ này, các toán tử (các phép toán) la phép cộng (+) và phép nhân (*). Các toán hạng là hằng số 3 và PI, là hàm Sin với đối số là biến X. * Biểu thức số học là biểu thức có giá trị bằng số (là Integer, Byte, Real) * Biểu thức logic Bun ( Boolean ) là biểu thức có giá trị là True hoặc False. * Một biểu thức chứa các toán tử quan hệ ( <>, <, >, <=, >=, = ) đựoc gọi là một biểu thức Boolean

đơn giản hay một biểu thức quan hệ. Các toán hạng trong biểu thức quan hệ có thể là các số nguyên, số thực, kí tự và chúng phải tương thích nhau về kiểu.

Ví dụ minh họa về trình tự tính toán :

9

Page 10: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

7 + 3 * 5 = 7 + ( 3 * 5 ) = 22 5 / 2 * 3 = ( 5 / 2 ) * 3 = 7.518 Div 4 * 4 = ( 18 Div 4 ) * 4 = 16 2 * ( 3 + 5 ) = 2 * 8 = 16

Ví duï: Để giải phương trình bậc hai ta có thể phát biểu điều kiện về các hệ số A, B, C như sau :

Nếu ( (A = 0) And (B = 0) And (C = 0) ) = True thì bài toán không có lời giải.

hoặc có thể viết gọn hơn :

Nếu (A = 0) And (B = 0) And (C = 0) thì bài toán không có lời giải.

Bài 4: CÁC CÂU LÊNH TRONG PASCAL1. Câu lệnh ( Instruction, Statement ):

Bên cạnh phần mô tả dữ liệu là phần là phấn lệnh (intruction) của chương trình. Phần này xác định các công việc mà chương trình phảo thực hiện để xử lý các dữ liệu đã được mô tả và khai báo. Các câu lệnh cách nhau bằng dấu chấm phẩy. Câu lệnh chia ra hai loại :

_ Câu lệnh đơn giản : là những câu lệnh không chứa các lệnh khác. Đó là phép gán, lời gọi chương trình con loại Procedure ( thủ tục ) bao hàm rất nhiều quá trình xử lý khác nhau như :

+ Vào dữ liệu : Read, Readln + Ra dữ liệu : Write, Writeln + Xử lý tập tin : Reset, Rewrite, Assign

_ Câu lệnh có cấu trúc : là khối lệnh, lệnh thử và rẽ nhánh, lệnh lặp. Lệnh hợp thành hay lệnh ghép bao gồm nhiều lệnh đơn giản và có khi có cả lệnh ghép bên trong.

Các lệnh này được thực hiện theo thứ tự như đã viết trong lệnh ghép Nó bắt đầu bằng từ Begin và kết thúc bằng từ End.

Mỗi một câu lệnh của Pascal bao giờ cũng được đặt cách nhau bằng dấu chấm phẩy (;). Dấu chấm phẩy chỉ có tác dụng ngăn cách các câu lệnh chứ không phải là dấu kết thúc câu lệnh và nó không phụ thuộc vào câu lệnh.Pascal không bắt buộc viết mỗi câu lệnh một dòng. Vấn đề là chúng ta phải trình bày chương trình sau cho đẹp, rõ ràng, thể hiện được thuật toán ...

Ví dụ : chúng ta có thể viết liền nhau trên một dòng chương trình :

X := 2 ; Y := 3 < 5 * 8 ; Z := Pi ;

hoặc viết thành từng dòng :

X := 2 ; Y := 3 < 5 * 8 ; Z := Pi ;

* Phép gán : Phép gán được dùng để gán giá trị của một biểu thức, một hằng vào một biến.

10

Page 11: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Phép gán được kí hiệu là := .

Biến := Biểu_thức ;

Vế trái của phép gán chỉ có thể là biến mà thôi.

Ví du :

X := 6 ; (* có nghĩa là biến X nhận giá trị bằng 6 *) Y := True ; (* có nghĩa là biến Y nhận giá trị True *)X := X + 3 ; (* có nghĩa là giá trị của X sẽ bằng giá trị của X cộng với 3. Ví dụ nếu lúc đầu X

có giá trị là 6 thì sau khi thực hiện câu lệnh này, X sẽ có giá trị là 9. Xin bạn nhớ lại cho X chỉ là tên của một ô nhớ. X + 3 đựoc hiểu là lấy nội dung của ô nhớ X đem cộng với 3, sau đó lại để vào ô nhớ X *)

* Tính tương thích của các kiểu dữ liệu Nguyên tắc chung khi dùng phép gán thì kiểu của biến và kiểu của biểu thức ở vế phải phải giống

nhau.

Ví dụ : Một biến nguyên I không thể nhận một giá trị kí tự được.

I := 'A' ; là điều không thể chấp nhận được.

* Ngoại lệ : Tuy một biến nguyên không thể nhận giá trị là một số thực nhưng một số thực thì lại có thể nhận

một giá trị nguyên.

X := 6.0 ; là sai vì X là biến Integer, 6.0 là giá trị thực. M23 := 6 ; là đúng vì M23 là biến thực, nó có thể nhận trực tiếp giá trị nguyên. M23 sẽ chứa số

6 dưới dạng số thực 6.00000000E + 00.

2. Lệnh ghép (Compound Statement): Một nhóm lệnh đơn giản được đặt giữa hai chữ Begin , End sẽ tạo thành một câu lệnh hợp thành hay lệnh ghép với mẫu viết như sau :

Begin Câu lệnh 1 ; Câu lệnh 2 ; .................. Câu lệnh N ; End ;

Một lệnh ghép hiểu theo một nghĩa nào đó giống như việc ta đặt cặp dấu ngoặc đơn vào một biểu thức. Cấu trúc Begin...End của câu lệnh ghép sẽ cho ta thấy rõ hơn tính có cấu trúc của ngôn ngữ Pascal : nhóm các lệnh thành từng khối. Một khối lệnh chỉ có một đầu vào (qua chữ Begin) và một đầu ra (qua chữ End).

Màn hình là một thiết bị ra thông dụng nhất hiện nay. Để viết dữ liệu ra màn hình, Pascal có 3 mẫu viết như sau :

11

Page 12: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Write ( Item1, Item2, ..., ItemN ) ;Writeln ( Item1, Item2, ..., ItemN ) ; (* Write Line *)

Writeln ;

Trong đó, ( Item1, Item2,..., ItemN ) ; (* Write Line *) là các mục cần viết ra có thể là một hoặc những loại sau :

_ Biến Write ( A ) ;_ Hàm Write ( Sin(x) ) ;_ Biểu thức Write ( A * A + B - 2 + Cos(x) ) ;_ Hằng Writeln ( Pi ) ;_ Các giá trị có kiểu vô hướng chuẩn : Writeln ( Pi ) ;_ Một số kiểu có cấu trúc như mảng, xâu kí tự.

Cả 3 mẫu viết trên đều bắt đầu viết từ vị trí hiện tại của con trỏ màn hình. Tuy nhiên, sự khác nhau của 3 mẫu lệnh trên là vị trí của con trỏ màn hình sau khi kết thúc lệnh.

Trong mẫu viết Write ( Item1, Item2,..., ItemN ) ; sau khi viết ra các giá của Item1, Item2,..., ItemN trên cùng một dòng màn hính, con trỏ sẽ xuống đầu dòng tiếp theo.

Còn thủ tục Writeln ( Item1, Item2,..., ItemN ) ; sau khi viết ra các giá trị của Item1, Item2,..., ItemN, con trỏ sẽ không chuyển xuống đầu dòng tiếp theo mà được đặt ở vị trí sau giá trị của ItemN.

Thủ tục Writeln ; ( không có tham số ) sẽ chỉ làm một động tác đơn giản là đặt con trỏ xuống đầu dòng tiếp theo.

Vì vậy :

Writeln ( Item1, Item2,..., ItemN ) ;

tương tự với một lệnh ghép :

Write ( Item1, Item2,..., ItemN ) ;Writeln ;

CÁC CÁCH VIÊ T CÓ QUY CÁCH :

* Viêt ra kiêu sô nguyên :

Writeln (' 12345678 ') ;I := 123 ;Writeln ( I : 8 ) ;Writeln ( -25671 : 8 ) ;

sẽ viết ra màn hình :

12345678123

-25671

* Viêt ra kiêu sô thuc :

12

Page 13: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Writeln ( 73.123456789 : 12 : 6 ) ;Writeln ( R : 12 : 6 ) ;Writeln ( 3.14 : 12 : 6 ) ;

sẽ viết ra màn hình :

____73.123456___123.456000 (* 12 chỗ cho cả số *) _____3.140000 (* 6 chỗ cho phần thập phân *)

Bạn cần lưu ý rằng lệnh Write và Writeln có thể viết ra kiểu Boolean :

Var OK : Boolean ;BEGIN OK := 3 < 5 ; Write ( OK : 7 ) ;END.

Kết quả cho ra :

___TRUE

Phép gán(:=) là lệnh cơ bản, đơn giản nhất để gán giá trị cho một biến ỡ trong chương trình. Tuy nhiên để gán giá trị cho một biến thông qua thiết bị vào(bàn phím), ta phải dùng thủ tục Read và Readln(Read Line) với các tham số ở trong ngoặc đơn là các biến(chỉ có thể là các biến mà thôi, không giống như các tham số của thủ tục Write và Writeln).

Read(Biến1, Biến2,..., biếnN) ;Readln(Biến1, Biến2,..., biếnN) ;

và Readln ; (* không có tham số *)

Khi này ta sẽ gõ vào bàn phím giá trị của biến cần đọc và phải ấn thêm nút Enter là nút đặc biệt trên bàn phím có ý nghĩa là " chấm xuống dòng " hoặc còn được gọi là nút Return để báo cho máy thực hiện thủ tục Read và Readln. Các cụm dữ liệu gõ vào bàn phím tương ứng với Biến1, Biến2,..., BiếnN được ngăn cách nhau với các dấu cách với số lượng dấu cách không quan trọng(song ít nhất là cách một lần).

Ví dụ :

Var X, Y : Integer ; A, B : Real ;BEGIN Readln(X, Y, A, B) ; ...END.

Giả sử ta muốn gán cho X giá trị 5, Y giá trị 33, A giá trị 1.25, và B là 85.2 trên cùng một dòng

của màn hình thì ta phải gõ vào bàn phím theo trình tự sau(số lượng dấu cách không quan trọng) :13

Page 14: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

5 33 85.2 33

Giữa các con số là các dấu cách được dùng để ngăn cách các số liệu khi đọc,Trong khi đọc, thủ tục Read và Readln còn kiểm tra xem các dữ liệu gõ vào có tương thích với

kiểu dữ liệu của biến khi khai báo hay không, nếu không máy sẽ báo lỗiThủ tục Readln ; là thủ tục không có tham số, máy tính chờ và chỉ chờ ta ấn phím Enter. Readln

không tham số được sử dụng khi bạn muốn chương trình dừng lại ở một chỗ nào đó(ví dụ để kiểm tra hoạt động của chương trình) cho đến khi bạn ấn phím Enter.

Xét ví dụ sau :

Var I : Integer ;BEGIN I := 1* 2 * 3 * 4 * 5 ; Writeln(I) ;END.

Bạn muốn xem kết quả của phép tính trên ! Dù bạn có ấn Ctrl_F9 từ giờ cho tới sáng cũng không thể thực hiện được điều đó. Vì kết quả của chương trình hiện ra và biến đi rất nhanh nên " mắt thường " của bạn không thể nào thấy được. Tuy nhiên nếu ta chèn thêm dòng lệnh “Readln ;” vào sau “Writeln(I) ;” thì mọi chuyện sẽ đổi khác !

Hai mẫu câu lệnh như sau :

IF <Bieu_thuc_Boolean> THEN <viec_1> ;IF <Bieu_thuc_Boolean> THEN <viec_1> ELSE <viec_2> ;

Theo lệnh này, nếu <Bieu_thuc_Boolean> nhận giá trị True thì máy sẽ thực hiện <viec_1>, còn nếu không thì hoặc kết thúc ( tức không làm gì cả ) đối với mẫu câu thứ nhất, hoặc máy sẽ đi thực hiện lệnh khác tức là <viec_2> trong mẫu câu lệnh thứ 2. Như vậy mẫu thứ nhất thực ra là mẫu thứ hai thu gọn với <viec_2> là rỗng.

Ví dụ1 : để thực hiện phép chia hai số a, b với điều kiện b < > 0, ta viết :

If b < > 0 Then t := a / b Else Writeln (' Mẫu số bằng 0 ! Không chia được ! ') ;

Ví dụ 2 : tìm giá trị min và max của hai số a, b.

If a < b Then Begin Max := b ; Min := a ;EndElse Begin Max := a ; Min := b ;

14

Page 15: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

End ;

Chú yù : trước Else không bao giờ có dấu chấm phẩy.

Trong ví dụ này, ta thấy luôn vai trò của lệnh hợp thành ( lệnh ghép ). Giả sử ta viết một lệnh như sau :

If a < b ThenBegin Max := b ; Min := a ;End ;

Nghĩa là nếu a < b ta phải thực hiện lần lượt hai lệnh là Max := b và Min := a ( được đặt giữa Begin và End ). Nếu không có Begin và End như sau :

If a < b Then Max := b ; Min := a ;

thì ta phải hiểu là lệnh max := b được thực hiện chỉ khi a < b còn lệnh min := a được thực hiện trong mọi trường hợp.

Cũng trong ví dụ này ta thấy cách viết có cấu trúc nhô ra nhô vào để bố trí chương trình Pascal cho đẹp và thể hiện đươcï thuật toán của chương trình. Đây là một tiêu chuẩn cần phải có cho một chương trình viết bằng Pascal. Chữ Begin và End tương ứng bao giờ cũng cùng ở một cột. Tất nhiên ta có thể viết tùy ý như sau nhưng không đẹp:

If a < b Then Begin max := b ; Min := a ; End Else Begin

Max := a ;Min := b ;End ;

Lưu yù : cách viết lệnh If như sau là hoàn toàn đúng :

If <Bieu_thuc_Boolean_1> Then If <Bieu_thuc_Boolean_2> Then <viec_1> Else <viec_2> ;

song rất dễ dẫn đến nhầm lẫn không biết <viec_2> tương ứng với Else của If nào. Vì vậy nên sửa lại cho rõ ràng như sau :

If <Bieu_thuc_Boolean_1 > Then Begin

If < Bieu_thuc_Boolean_2 > Then < viec_1> Else < viec_2 > End ;

Hai mẫu câu lệnh If ở bài trước chỉ thực hiện rẽ hai nhánh tương ứng với 2 giá trị của biểu thức

Boolean. Việc thử và chọn một trong nhiều nhánh sẽ được thực hiện với câu lệnh Case như sau :

Mâ u 1 : Mâ u 2 : 15

Page 16: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Case <Bieu_thuc> Of Case <Bieu_thuc> Of

Gia_tri_1 : <viec_1> ; Gia_tri_1 : < viec_1> ; Gia_tri_2 : <viec_2> ; Gia_tri_2 : < viec_2> ; .................. .................. Gia_tri_n : <viec_n> ; Gia_tri_n : <viec_n> End ; Else <viec_n+1> ;

End ;

Trong đó <Bieu_thuc> không còn chỉ là biểu thức Boolean như trong lệnh If …Nó có thể là có các kiểu vô hướng đếm được (kể cả kiểu liệt kê, kiểu khoảng con sẽ học sau nhưng

không được là kiểu Real ) nên nó có thể có nhiều giá trị khác nhau. Mẫu 2 sẽ thực hiện <viec_n+1> ( được viết sau từ khóa Else ) nếu như < Bieu_thuc> không rơi vào các giá trị 1, giá trị 2,… giá trị n kể trên.

Cần chú ý rằng câu lệnh Case bao giờ cũng kết thúc bằng từ khóa End.

Ví dụ 1: Với I là một biến nguyên

Case I + 1 Of 1 : writeln (' So 1 ') ; 2 : writeln (' So 2 ') ; 3 : writeln (' So 3 ') ; 4 : writeln (' So 4 ') ; End ;

Ví dụ 2: Tính số ngày của một tháng ;

Var so_ngay, thang, nam : integer ; BEGIN Write ('Thang : ') ; readln ( thang) ; Write ('Nam : ') ; readln ( nam) ; Case thang Of 4, 6, 9, 11 : so_ngay := 30 ; 2 : case nam of 0 : so_ngay := 29 ; 1, 2, 3 : songay := 28 ; end Else so_ngay := 31 ; End ; Writeln (' So ngay cua thang ', thang,' nam ', nam,' la ', so_ngay) ;END.

Đến đây các bạn có thể hỏi liệu bài toán Giải phương trình bậc 2 có thể dùng Case cho ba trường hợp của biến Delta không ? Điều này không thể được vì biến Delta thuộc kiểu Real, kiểu không đếm được.

Trước hết chúng ta xét một ví dụ sau.

Ví du 1 : giả sử ta phải viết ra trên màn hình các số từ 0 đến 24, mỗi số chiếm một dòng :  

16

Page 17: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

012......2324

Việc này có thể thực hiện bằng 25 lệnh writeln như sau :  

Writeln (0) ;Writeln (1) ;…………….Writeln (24) ;

Cách viết này rõ ràng và tẻ nhạt trong khi nó có quy luật. Chúng ta có thể thay thế bằng cách dùng một lệnh Writeln ( I ) trong đó I là một biến nguyên bất kỳ nhận giá trị chạy từ 0 đến 24 như sau :

For I := 0 To 24 Do Writeln ( I ) ;

Vòng lặp For này có nghĩa là cho I chạy từ 0 ( giá trị đầu ) tới 24 ( giá trị cuối ), với mỗi giá trị của I, máy sẽ thực hiện công việc viết sau chữ Do, ở đây là viết ra giá trị của I.

Cụ thể hơn, vòng lặp For này được thực hiện từng bước như sau : 1. Đầu tiên I lấy giá trị 0 là giá trị ban đầu. I nhỏ hơn giá trị cuôí là 24 nên lệnh Writeln ( I ) được

thực hiện, viết ra giá trị 0. 2. Sau đó, I nhận giá trị tiếp theo, tức là I := succ ( I ) = I + 1. Lúc này I = 1 và vẫn nhỏ hơn giá

trị cuối là 24 nên lệnh writeln ( I ) được thực hiện : viết ra giá trị của I ( bằng 1 ) ra màn hình. 3. Chương trình lại quay vòng về điểm 2 cho đến khi nào I = 25, lớn hơn giá trị cuối (24) thì dừng.

Mẫu viết tổng quát của ví dụ trên là :

For Bien_dieu_khien := Gia_tri_dau To Gia_tri_cuoi Do <viec> ;

Nếu ta muốn viết các số từ 24 đến 0 ta lại viết như sau :

For I := 24 Downto 0 Do Writeln ( I ) ;

Với mẫu viết tổng quát như sau :

For Bien_dieu_khien := Gia_tri_dau Downto Gia_tri_cuoi Do <viec> ;

Trong mẫu 2, máy tính sẽ làm theo chiều ngược lại, tức là theo chiều giảm của biến điều khiển : đầu tiên biến điều khiển nhận giá trị ban đầu và sau đó thực hiện chu kì lặp như sau : chừng nào biến điều khiển còn lớn hơn hoặc bằng giá trị cuối thì thực hiện <viec>, sau mỗi lần thực hiện, biến điều khiển nhận giá trị trước nó, tức là :

Bien_đieu_khien := Pred (Bien_đieu_khien) ;

Ví d ụ 2: tính tổng các số nguyên từ 50 đến 500 ta viết như sau :

17

Page 18: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Var I : integer ; Sum : real ; BEGIN Sum := 0 ; For I := 50 To 500 Do Sum := Sum + I ; (* hoặc For I := 500 Downto 50 Do Sum := Sum + I ; *) Writeln ( ' Tong = ', Sum ) ;END.

Ví d ụ 3: viết hai dòng các chữ cái hoa và nhỏ từ 'A' đến 'Z' ra màn hình với quy cách mỗi chữ chiếm 2 chỗ

USES CRT ; { đơn vị chương trình CRT để dùng thủ tục Clrscr }Var ch : char ; BEGIN Clrscr ; For ch := 'A' To 'Z' Do Write (ch : 2) ; Writeln ; For ch := 'a' To 'z' Do Write (ch : 2) ; Writeln ;

END.

Kết quả hiện ra màn hình :

A B C D E F G H I J K L M N O P Q R S T U V W X Y ZA b c d e f g h I j k l m n o p q r s t u v w x y z

Ví du 4 : phép thử biến ngày có phải ngày làm việc hay không được viết như sau :

Type ngay = (ChuNhat, Hai, Ba, Tu, Nam, Sau, Bay) ;Var Ngayx, ng : ngay ; BEGIN Ngayx := nam ; For ng := 'hai' To 'bay' Do If ngayx = ngay Then Writeln ( ' Ngay lam viec ' );END.

Cần lưu ý trong <viec> sau Do, không nên thay đổi tùy tiện giá trị của biến điều khiển. Làm như vậy rất nguy hiểm vì ta sẽ không còn chủ động kiểm soát được biến điều khiển. Ví dụ không nên dùng :

For I := 1 To 10 Do I := I + 2 ;

Ví du 5 : các vòng For có thể lồng nhau :

For I := 1 To 5 Do For J := 1 To 8 Do Begin K := I + J ; Writeln (K) ; End ;

18

Page 19: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Bạn hãy tự viết kết quả hiện ra màn hình.

Có hai kiểu thực hiện vòng lặp không xác định :

Repeat While <Bieu_thuc_Boolean> Do <viec> Begin Until <Bieu_thuc_Boolean> ; <viec> ;

End ;

Trong lệnh Repeat... Until..., máy tính sẽ thực hiện <viec> cho đến khi <Bieu_thuc_Boolean> có giá trị True theo chu kì xác định. Giữa Repeat và Until không cần dùng Begin và End. Có thể ví vòng Repeat... Until... với câu "Tiền trảm hậu tấu".

Còn trong vòng lặp While... Do... máy tính sẽ lặp đi lặp lại chu kỳ sau : chừng nào <Bieu_thuc_Boolean> có giá trị True thì đi thực hiện <viec> được đặt giữa Begin và End.

Như vậy sự khác nhau giữa hai loại vòng lặp trên là ở chỗ với vòng lặp Repeat, máy tính sẽ thực hiện <viec> truớc và thử điều kiện của <Bieu_thuc_Boolean> sau. Còn trong vòng While, máy sẽ thử <Bieu_thuc_Boolean> trước rồi thực hiện <viec> sau.

Cả hai vòng lặp đều có số lần lặp không xác định trước. Cần phải lưu ý là trong khi thực hiện <viec> lặp, ta phải có một lệnh làm thay đổi một biến nằm trong <Bieu_thuc_Boolean> để thay đổi giá trị biểu thức nhằm dừng vòng lặp lại vì nếu không như vậy các vòng lặp sẽ chạy mãi không dừng.

Ví du 1: Tính tổng sau :

A = 1 + 1/2 + 1/3 +... + 1/N

Ví dụ này hoàn toàn có thể dùng vòng lặp For song ở đây ta áp dụng vòng lặp không xác định để làm ví dụ minh họa.

Program Tinh_tong ;Var I, N : Integer ; A : Real ; BEGIN Writeln (' N = ') ; Readln ( N ) ;

A := 0 ; I := 1 ; Repeat A := A + 1/ I ; I := I + 1 ; (* thay đổi giá trị biểu thức Boolean *) Until I > N ; Writeln (' Tong = ', a :10 : 8 ) ; END.

Hoặc viết cách khác dưới dạng "đếm lùi" :

Var N : Integer ; A : Real ; BEGIN Writeln (' N = ') ; Readln ( N ) ; A := 0 ; Repeat

19

Page 20: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

A := A + 1/N N := N - 1 ; (* thay đổi giá trị biểu thức Boolean *) Until N = 0 ; Writeln (' Tong = ', A :10 : 8 ) ; END.

Hoặc dùng vòng While :

A := 0 ; I := 1 ; While I <= N Do Begin A := A + 1/ I ; I := I + 1 ; (* thay đổi giá trị biểu thức Boolean *)

End ;

Vòng lặp While luôn luôn đi với cặp từ khoá Begin và End còn trong vòng lặp Repeat không cần sử dụng cặp Begin và End.

Ví du 2:

Chúng ta thường làm các vòng lặp không xác định như sau để quay vòng theo ý muốn :

Var Traloi : Char ; BEGIN Repeat ............... (* thay đổi điều kiện thủ tục *) Writeln (' Co tiep tuc nua khong ? ') ; Readln ( Traloi ) ; Until ( Traloi = 'K' ) or ( Traloi = 'k' ) ;

Lệnh Goto thuộc loại lệnh đơn giản, cho phép chương trình nhẩy vô điều kiện tới một vị trí trong chương trình thông qua tên nhãn. các nhãn là các số nguyên hoặc tên được khai báo trong phần Label của phần khai báo ở đầu chương trình, đặt cách nhau qua dấu phẩy. Trong chương trình, nhãn được đặt vào vị trí thích hợp theo sau là dấu hai chấm.

Ví du 1 :

Program Vi_du_nhan ; Label 1, 2 ; Var X, Y, I : Real ; BEGIN ................ 1 : X := X + 1 ; ................ If X > 5 Then Goto 2 ; ................ 2 : I := X + Y ; If I < 3 Then Goto 1 ; ................

20

Page 21: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

END.

Tuy được trang bị lệnh nhảy Goto song có thể nói Pascal rất ít khi dùng hoặc tuyệt đối không nên dùng lệnh Goto vì Goto sẽ làm mất tính "cấu trúc thuật toán " của ngôn ngữ Pascal. Goto chính là khuyết điểm của ngôn ngữ Fortran. Các lệnh While..., Repeat... Until..., If... đã đủ khả năng cho phép người lập trình tránh dùng Goto. Ngôn ngữ Fortran là loại ngôn ngữ nghèo lệnh : nó chỉ có 3 kiểu lệnh : một kiểu vòng lặp Do tương tự như vòng For của Pascal, lệnh If thì chưa có cấu trúc Else và cuối cùng là Goto.

Sự có mặt của Goto trong chương trình chúng tỏ người lập trình chưa học cách nghĩ theo Pascal như lời của giáo sư Writh, tác giả của Pascal chuẩn, đã viết .

Một điều ràng buộc của lệnh Goto là không được dùng Goto để nhảy vào chương trình con mặc dù có thể từ trong chương trình con nhảy ra ngoài.

I := 1 ; While I <= N Do Begin A := A + 1/ I ; I := I + 1 ; (* thay đổi giá trị biểu thức Boolean *) End ;

Vòng lặp While luôn luôn đi với cặp từ khoá Begin và End còn trong vòng lặp Repeat không cần sử dụng cặp Begin và End.

Ví du 2 : Chúng ta thường làm các vòng lặp không xác định như sau để quay vòng theo ý muốn :

Var Traloi : Char ; BEGIN Repeat ........ (* thay đổi điều kiện thủ tục *) Writeln (' Co tiep tuc nua khong ? ') ; Readln ( Traloi ) ; Until ( Traloi = 'K' ) or ( Traloi = 'k' ) ;

Bài 6: KHÁI NIỆM CHƯƠNG TRÌNH CON. THỦ TỤC VÀ HÀM1. Khái niệm về chương trình con:

Turbo Pascal là ngôn ngữ có cấu trúc cao. Do đó, một chương trình lớn có thể chia thành nhiều chương trình con với hai mục đích :

a) Dễ kiểm tra, dề điều khiển từng phần của chương trình.b) Tránh lặp đi lặp lại những đoạn chương trình dùng nhiều lần. Điều này vừa gây mất thời gian cho người lập trình vừa làm cho chương trình thêm lôi thôi, mất thẩm mĩ.

2. Thủ tục và hàm:Trong Pascal có hai loại chương trình con :

_ Procedure ( thu tuc ) _ Function ( hàm )

21

Page 22: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Sự khác nhau cơ bản và duy nhất của hai loại chương trình con này là : Function trả lại cho một giá trị kết quả vô hướng thông qua tên của Function và do đó nó được sử dụng trong một biểu thức. Còn Procedure không trả lại kết quả thông qua tên của nó nên các Procedure không thể viết trong các biểu thức.

3. Cấu trúc của Procedure và Function:

Procedure Ten_thu_tuc ( Khai báo các tham số hình thức ) ;(* Khai báo : Label, Const, Type, Var, hoặc các Procedure và Function

*) ;Begin ... (* Thân chương trình con *)End ;Function Ten_ham ( khai báo các tham số hình thức ) :

kieu_du_lieu_cua_ham ;(* Khai báo : Label, Const, Type, Var, hoặc các Procedure và Function

*) ;Begin ... (* Thân chuong trình con *)End ;

Thân của chương trình con được đặt giữa hai chữ Begin và End với End kết thúc bằng dấu chấm phẩy (;) chứ không phải dấu chấm (.) như của chương trình chính.

4. Ví dụ về thủ tục và hàm:

Program Vidu ;Uses Crt ; (* Crt là một Unit chứa các chương trình con về màn hình, bàn hình... *) Var A, B, C, D : Integer ; Z : Real ;(* ---------------------------------------------------------------------- *)Procedure Tieu_de ;Begin Writeln (' **************************************** ') ; Writeln (' * MINH HOA CHUONG TRINH CON * ') ; Writeln (' **************************************** ') ;End ;(* ------------------------------------------------------------------- *)Procedure Enter (Var X, Y : Integer ) ;Var OK : Char ;Begin Repeat Write (' Tu so = ') ; Readln (X) ;

Write (' Mau so = ') ; Readln (Y) ; Write (' Co sua so lieu khong (c, k) ? ') ; OK := Readkey ; Writeln ; Until (OK = ' K ') or (OK = ' k ') ;End ;(* ------------------------------------------------------------------- *)

22

Page 23: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Function Chia (X, Y : Integer) : Real ;Begin If Y <> 0 Then Chia := X / Y Else Begin Writeln (#7,' Khong chia duoc cho 0.') ; (* Máy sẽ báo lỗi nếu mẫu số là 0 *) Halt ; (* Thu tuc Halt dung chuong trinh lai *) End ;End ;(* ------------------------------------------------------------------- *)BEGIN Tieu_de ; Enter (A, B) ; Enter (C, D) ; Z := Chia (A, B) * Chia (C, D) ; Writeln (' Ti so (A / B) * (C / D) la : ', Z) ; Writeln (' Hay an Enter de ket thuc ! ') ; Readln ;END.

Chương trình này sẽ đọc từng cặp số nguyên A, B và C, D, sau đó đọc tỉ số của 2 số đó qua Function Chia và cuối cùng là tính tích của 2 tỉ số đó rồi báo ra kết quả. Như vậy, nhìn vào thân chương trình chính ta thấy công việc được hình dung ra một cách rất sáng sủa.

Đầu tiên, chương trình con (CTC) Tieu_de có nhiệm vụ in ra vài dòng tiêu đề, CTC này không cần tham số.

Procedure Enter có nhiệm vụ là vào dữ liệu X, Y, là hai tham số hình thức, cũng đồng thời là kết quả của Procedure. Hai tham số này sẽ được thay thế bằng hai tham số thực sự được khai báo ở chương trình chính là A và B khi ta gọi Procedure bằng câu lệnh Enter (A, B), tức là A sẽ tương ứng với X và B sẽ tương ứng với Y. Lời gọi Enter (A, B) được hiểu là đọc vào hai tham số A và B. Tương tự như vậy, lần gọi thứ hai Enter (C, D) sẽ đọc hai giá trị của hai tham số thực sự là C và D.

Trong CTC, ta cũng có thể có phần khai báo riêng của nó. Trong ví dụ trên, biến OK là biến riêng hay còn thường được gọi là biến địa phương của Procedure Enter để phân biệt với các biến toàn cục được mô tả ở chương trình chính là A, B, Z...

Function Chia có hai tham số hình thức là X và Y. Ta có thể viết lời gọi Function trong biểu thức như việc tính Z ở ví dụ trên. Lời gọi của Procedure không làm đươc như vậy vì tên của Procedure không có giá trị. Khi khai báo Function, ta còn phải khai báo thêm kiểu dữ liệu của Function. Trong ví dụ trên, Function Chia có kiểu là Real, đó cũng là sự khác nhau giữa hai loại CTC.

Giả sử, để tính giá trị của Z = (A / B) / (C / D), ta có thể viết :

Z := Chia (Chia(A, B), Chia(C, D)) ;

Chương trình con có thể được khai báo mà không dùng tham số khi các CTC tính toán trực tiếp với các biến toàn cục hoặc CTC không dùng đến bất cứ biến hay hằng nào như thủ tục Tieu_de mà ta đã xét ở bài trước.

Việc chuyển tham số cho CTC là một cơ cấu thay thế tương ứng, nó cho phép một quá trình được lặp đi lặp lại nhiều lần với các "toán hạng" khác nhau. Thí dụ Enter (A, B) sẽ thay thế A vào vị trí của X, B vào vị trí của Y. Tương tự với Enter (C, D).

23

Page 24: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Chuyển tham số bằng biến : tham số hình thức trong phần tiêu đề của CTC sẽ được đặt sau từ khóa Var. Với tham biến, các tham số thực sự sẽ phải là biến chứ không được là giá trị. Thí dụ lời gọi Enter (3, 7) sẽ không được chấp nhận vì 3 và 7 là hai giá trị chứ không phải là biến. Các tham số thực sự là các tham biến có thể được thay đổi trong CTC và khi ra khỏi CTC nó vẫn giữ các giá trị đã thay đổi đó. Khi khai báo các tham số mà không có từ khóa Var trong một nhóm tham số hình thức thì các tham số của nhóm này là các tham số giá trị (tham trị). Khi đó các tham số thực sự phải là một biểu thức. Tham số hình thức tương ứng sẽ được coi như một biến địa phương của CTC, nó nhận giá trị của tham số thực như là giá trị ban đầu ở vào thời điểm thay vào CTC. Chương trình con sau đó có thể thay đổi giá trị của các tham trị này ở bên trong CTC bằng các phép gán. Song trong mọi trường hợp điều đó không làm thay đổi giá trị của tham số thực. Do vậy, một tham trị không bao giờ là kết quả tính toán của CTC.

Sự khác nhau giữa hai loại tham số này được minh họa bằng ví dụ sau :

Program Tham_so ;Var A, B : Integer ;(* ----------------------------------------------------------- *) Procedure Thidu_Thamso (X : Integer ; Var Y : Integer) ;Begin X := X + 1 ; Y := Y + 1 ; Writeln (X : 6, Y : 6) ;End ;(* ----------------------------------------------------------- *) BEGIN A := 0 ; B := 3 ; Thidu_Thamso (A, B) ; Writeln (A : 6, B : 6) ;END.

Kết quả cho ra :

1 40 4

Trong thí dụ trên, thủ tục Thidu_Thamso có hai loại tham số : tham trị X và tham biến Y. Trước khi gọi thủ tục này với hai tham số thực sự là A và B tương ứng thì A = 0 và B = 3. Trong thủ tục ta có hai lệnh làm thay đổi giá trị của A và B bằng cách tăng thêm 1. Lệnh Writeln (X, Y) cho ra kết quả là 1 và 4 tương ứng. Tuy nhiên sau khi ra khỏi CTC, lệnh Writeln (X, Y) báo cho ta giá trị của B đã bị thay đổi trong CTC vì B là tham biến, còn A vẫn giữ nguyên giá trị trước khi gọi thủ tục, tức A vẫn bằng 0, vì A chỉ là tham trị.

Như vậy, khi chuyển một tham số cho CTC, nếu ta muốn bảo vệ giá trị của tham số đó khỏi bị CTC "vô tình phá" thì tham số đó phải được dùng như là tham trị. Còn một tham số nếu muốn dùng để lấy kết quả do CTC đem lại thì tham số đó phải là tham biến.

Xét ví dụ sau đây :

PROGRAM VI_DUVAR

24

Page 25: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

X : Integer ;(* ----------------------------------------- *)Procedure A ;Var Y : Integer ; Procedure AA ; Var M,N : Integer ; Begin … End ; Procedure AB ; Var M,N : Integer ; Begin ... End ; Begin … End ; (* Procedure A *)(* -------------------------------------------- *)Procedure B ;Var X,Z : Integer ; Procedure BA ; Begin … End ;Begin …End ; (* Procedure B *)(* --------------------------------------------- *) BEGIN …END. (* Chương trình chính *)

Như ta đã biết, các biến được khai báo trong chương trình chính được gọi là biến toàn cục. Các biến này có thể được dùng ở mọi nơi trong chương trình. Các biến được khai báo trong một CTC được gọi là các biến địa phương và nó chỉ có tác dụng trong phạm vi CTC đó hay trong Bloc đó. Khi CTC kết thúc thì các biến này cũng mất tác dụng theo. Để diễn tả tầm tác dụng của các biến, của các khai báo, người ta đưa ra khái niệm mức : chương trình chính có mức 0, các chương trình tiếp theo có mức là 1,2,… tùy theo vị trí khai báo. Trong hình 2, chương trình con A và B có mức là 1, chương trình con AA, AB, BA có mức là 2.

Sau đây là một số quy tắc sử dụng :+ Tầm tác dụng của 1 tên (biến, hằng, kiểu…) được xác định bằng mức Bloc trong đó tên được

khai báo và bằng các mức Bloc khác có mức cao hơn và nằm trong Bloc chứa khai báo.Trong ví dụ vừa rồi, biến Y được khai báo trong CTC A (có mức là 1). Như vậy biến Y có thể

được sử dụng ở trong CTC AA và AB (là 2 CTC có mức cao hơn và nằm trong CTC A). Ngoài ra Y không thể sử dụng ở CTC B, BA, BB vì chúng không phải là CTC của A.

+ Tầm quan trọng của các biến khai báo ở mức 0 (chương trình chính)là toàn bộ chương trình.+ Ở các mức khác nhau của các CTC, ta có thể khai báo 1 biến có cùng tên với biến ở mức khác.

Tên biến này không phải là một biến duy nhất mà là hai biến khác nhau với tầm quan trọng khác nhau. Ví dụ trong hình 2, CTC B có biến địa phương X và trong chương trình chính có biến toàn cụa

25

Page 26: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

cũng có là X. Khi đó trong CTc thì biến X địa phương có tác dụng, còn khi CTC kết thúc thì biến toàn cục lại lấy lại tác dụng của nó. Hãy xét ví dụ cụ thể như sau :

Program Tam_Tac_Dung) ;Var I : Integer ; (* Biến I toàn cục *)(* ------------------------------------------------- *) Procedure Dia_Phuong ; Var I : Integer ; (* Biến I địa phương *) Begin I := 7 ; Writeln (I : 6) ; End ;(* ------------------------------------------------ *)BEGIN I :=5 ; Writeln(I : 6) ; Dia_Phuong ; Writeln(I : 6) ;END.

Kết quả cho ra :

5 (* giá trị của I toàn cục *)7 (* giá trị của I địa phương *)5 (* giá trị của I toàn cục *)

Tên biến I được dùng cho cả biến toàn cục và biến địa phương. Đầu tiên biến I toàn cục nhận giá trị bằng 5. Sau đó thủ tục Dia_Phuong được gọi, vì thủ tục này cũng có biến là I (biến địa phương) nên biến I toàn cục được xem như tạm bị treo không dùng đến. Biến địa phương lấy giá trị bằng 7. Sau khi kết thúc chương trình con, biến I địa phương bị mất và biến I toàn cục lại được khôi phục lại tác dụng. Tất nhiên nó vẫn giữ giá trị bằng 5 là giá trị có được trước khi gọi thủ tục Dia_phuong.

Trong trường hợp trong thủ tục Dia_phuong, ta muốn chiếu đến biến I toàn cục, ta vẫn có thể dùng nó bằng cách chỉ rõ tên chương trình ngoài tên biến : Tam_tac_dung.i. Cách tham chiếu như trên cũng tương tự như khi ta chỉ ra đường dẫn trực tiếp trên DOS.

Trong Procedure và Function có thể có lời gọi của chính nó. Tính chất này dược gọi là tính đệ qui.

Thí dụ tính giai thừa qua định nghĩa :

N! = 1 x 2 x... x ( N - 1 ) x N

hoặc định nghĩa :

1 khi N = 0

N! = N x ( N - 1 )! khi N >= 1

Khi đó, hàm Giai_thua được định nghĩa như sau :

26

Page 27: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Function Giai_thua( N : Integer ) : Integer ;Begin If N = 0 Then Giai_thua := 1 ; Else Giai_thua := N * Giai_thua( N-1 ) ;End ;

Một điều cần lưu ý là ta phải hết sức thận trọng lường trước việc kết thúc của quá trình đệ qui này. Trong thí dụ trên, lệnh gán :

K := Giai_thua( -1 ) ;

sẽ khởi động một quá tình đệ qui rất dài về mặt lý thuyết vì tham số âm bị xử lý sai.

Ở thí dụ trên, ta đã khai báo giai_thua là Integer nên sẽ bị một hạn chế : chỉ có thể tính với N < 8 vì nếu N >= 8, Giai_thua sẽ mang giá trị lớn hơn 32767 là giới hạn trên của số nguyên. Một trong các biện pháp khắc phục là ta khai báo Giai_thua là Real.

Function Giai_thua( N : Integer ) : Real ;

Khi sử dụng Giai_thua là Real, ta phải chú ý sử lý thêm một ít. Ví dụ, để viết giá trị của Giai_thua là số thực sang số nguyên, ta phải sử dụng cách viết có quy cách với phần thập phân bị cắt :

Writeln ( Giai_thua(12) : 0 : 0 ) ;

Thí dụ tính giai thừa ở trên về phương diện ví dụ nó rất đơn giản và dể hiểu. Song về phương diện kĩ thuật lập trình thì đấy là một thí dụ không đẹp lắm vì người ta có thể tính giai thừa một cách tiết kiệm hơn bằng chương trình sau khi sử dụng lệnh lặp While :

Function Giai_thua( N : Integer ) : Integer ;Var I, K :Integer ;Begin I := 0 ; K := 1 ; (* Phải dùng biến địa phươn K để chứa kết quả trung gia *) While I < N Do Begin I := I + 1 ; K := K * I ; End ; Giai_thua := K ; (* Gán kết quả từ biến trung gian K vào tên hàm*) End ;

Trong cách dùng sau, ta chỉ mất hai ô nhớ địa phương tương ứng với hai biến I và K. Còn trong

cách dùng trước, mỗi lần dùng Giai_thua(N), máy lại phải bố trí thêm một ô nhớ chứa kết quả Giai_thua trung gian.

Nói chung nên tránh dùng đệ qui khi mà ta có thể dùng phép lặp để tính toán.

Các CTC còn có thể được gọi ra trước khi có định nghĩa chúng nếu như trước đó có lời khai báo kiểu Forward. Cách thức viết được thể hiện qua ví dụ dưới đây. Lưu ý là danh sách các tham số hình thức cần liệt kê ra trong lời khai báo trước (Forward) còn trong lời khai báo chi tiết thì không có.

27

Page 28: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Program Vi_du_Forward ;Var Alpha : Integer ;(* Khai báo trước Procedure Test2 với từ Forward *)Procedure Test2 ( Var A : Integer ) ; Forward ;(* -------------------------------------------------------- *) Procedure Test1 ( Var A : Integer ) ; Begin A := A - 1 ; (* Dùng Test2 trước khi khai báo chi tiết *) If A > 0 Then Test2(A) ; End ;(* -------------------------------------------------------- *) Procedure Test2 ; Begin A := A Div 2 ; If A > 0 Then Test1(A) ; End ;(* -------------------------------------------------------- *) BEGIN Alpha := 15 ; Test1( Alpha ) ;END.

Ta thấy thủ tục Test1 dùng thủ tục Test2, còn thủ tục Test2 lại dùng thủ tục Test1. Do đó ta thấy ngay trong trường hợp này không thể định nghĩa thủ tục Test1 và Test2 một cách bình thường được mà phải dùng đến Forward.

Bài 7 : CÁC ĐƠN VỊ CHUƠNG TRÌNH CON1. Unit:

Trong Pascal, người ta đã chia nhỏ thư viện CTC thành các thư viện nhỏ hơn, mỗi thư viện nhỏ đó được gọi là một Unit (đơn vị chương trình) như :

CRT là Unit chứa các CTC xử lý màn hình ( như lệnh Gotoxy, ClrScr... ), bàn phím ( như Readkey... ).

PRINTER là Unit chứa các CTC và dữ liệu về thủ tục in như Writeln ( Lst,... ).DOS là Unit chứa các CTC và dữ liệu khai thác các hàm của Dos.SYSTEM là Unit chứa các CTC và dữ liệu hệ thống.( Lưu ý rằng các Unit trên được để trong file TURBO.TPL ( TPL : Turbo Pascal Library ).GRAPH là một Unit về đồ họa, được để trong một file riêng có tên là GRAPH.TPU. Đây là

một Unit chứa tất cả các CTC về đồ họa. Vì vậy khi bạn dùng đồ họa, nhớ phải copy file GRAPH.TPU.

STRING chỉ có trong Turbo 7.0 để sử dụng kiểu xâu kí tự kệt thúc bằng kí tự có mã #0 ( kí tự Null ).

TURBO3 là Unit tạo sự tương thích với các chương trình đã viế bằng Turbo Pascal 3.0, được chứa trong file TURBO3.TPU.

GRAPH3 thực hiện các CTC vẽ theo kiểu con rùa có ở trong Turbo 3.0, chứa trong file GRAPH3.TPU

28

Page 29: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Tuy nhiên, hai Unit cuối có lẽ bạn sẽ không phải dùng đến, bởi vì phiên bản Turbo 3.0 và các chương trình viết bằng phiên bản này đã cũ và "cổ lỗ" lắm rồi, bạn có muốn tìm cũng không ra !

Việc chia nhỏ thư viện này giúp cho chương trình dịch chạy nhanh hơn vì không phải đọc lại tất cả các CTC nếu như không có nhu cầu. Mặt khác, chương trình dịch ra cũng gọn hơn vì không phải chứa những cái không dùng đến

Người ta có thể nhóm một số dữ liệu và các CTC liên quan lại thành các Unit ( đơn vị chương trình ). Các Unit này một khi đã được dịch hoàn chỉnh nếu không có sự sửa đổi thì ta có thể dùng ngay, không cần dịch lại và thậm chí chúng còn có thể được dùng chung cho nhiều chương trình khác nhau. Trong trương hợp có sự thay đổi trong một Unit nào đó thì chỉ có các Unit có liên quan mới bị dịch lại.

2. Cách thức của một Unit:Một Unit do bạn tạo ra sẽ đươc chứa trong một file với một tên nào đó, thí dụ KHOI1.PAS. Cách

thức của một Unit như sau :Unit Khoi1 ; (* Tên Unit thường nên đặt trùng với tên file *) Uses Ten_cac_Unit_khac_can_dung ;Interface (* Khai báo tên các thủ tục và hàm được viết đầy đủ trong phần Implementation dưới

đây. Tên của các thủ tục và hàm khai báo trong phần này là tên các CTC mà các Unit khác cần dùng đến *)

Procedure Thidu1 ( Var X, Y : Real ) ;Function TenF ( I, J : Integer ) : Real ;Implementation (* Khai báo các kiểu dữ liệu, các biến... cùng đầy đủ các thủ tục và hàm của Unit này *)Const PP = 3.5 ;Var X, Y : Real ; (* Khai báo các biến cho Unit này *)(* ------------------------------------------------------------------------- *)Procedure Thi_du1 ( Var X, Y : Real ) ;Begin ...End ;(* ------------------------------------------------------------------------- *)Function TenF ( I, J : Integer ) : Real ; Begin ...End ;END.(* Kết thúc Unit bằng END có dấu chấm. Lưu ý ở phía trên sẽ không có chữ BEGIN

tương ứng với chữ END kết thúc Unit này *) Khi dịch tệp trên bằng cách ấn Alt _ F9, Turbo Pascal sẽ tạo ra file KHOI1.TPU ( TPU : Turbo

Pascal Unit ). Bạn nhớ rằng để dịch đúng một Unit bạn đang soạn thảo, bạn phải ấn Alt _ F9 chứ không phải Ctrl _ F9. 3. Cách gọi các Unit:

Trong chương trình chính hay trong một Unit, nếu ta cần dùng đến một Unit khác, thì ở phần đầu chương trình ta phải viết dòng :

Uses Unit1, Unit2,..., UnitN ; Các thủ tục ClrScr, Readkey... là các thủ tục đã được dịch sẵn và để trong Unit có tên là CRT. Vì vậy, muốn dùng nó, ta phải viết :

Program SD_Unit ;Uses Crt ;

29

Page 30: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Type ...BEGIN Clrscr ;END.

hoặc một chương trình khác trong đó dùng nhiều Unit khác nhau :

Program Vidu_Unit ;Uses Crt, Dos, Graph, Printer ;

Bài 8: KIỂU DỮ LIỆU CÓ CẤU TRÚC1. Khái niệm chung về cấu trúc dữ liệu:

Chúng ta đã làm quen với các kiểu dữ liệu đơn giản là các kiểu vô hướng (Integer, Char, Boolean, Real, kiểu liệt kê) và đoạn con. Trong Pascal tồn tại các kiểu dữ liệu có cấu trúc là các kiểu dữ liệu được tạo ra từ các phần tử có kiểu dữ liệu đơn giản bằng một cách nào đó. Chúng được đặc trưng bằng kiểu dữ liệu của các phần tử và quan trọng hơn cả là phương pháp cấu thành kiểu dữ liệu mới (điều đó cũng có nghĩa là phương pháp truy nhập vào kiểu dữ liệu có cấu trúc). Tính có cấu trúc của dữ liệu là một đặc trưng của ngôn ngữ lập trình có cấu trúc.

Pascal có tất cả 4 kiểu dữ liệu có cấu trúc mà chúng ta sẽ lần lượt ngiên cứu : mảng (Array), tập (Set), bản ghi (Record) và tệp (File).

2. Kiểu dữ liệu có cấu trúc : Mảng (Array) Một mảng dữ liệu gồm một số hữu hạn phần tử có cùng kiểu gọi là kiểu cơ bản. Số phần tử của

mảng được xác định ngay từ khi định nghĩa ra mảng. Mỗi phần tử của mảng đựoc truy nhập trực tiếp thông qua tên mảng cùng với chỉ dẫn truy nhập được để giữa hai ngoặc vuông [ ].

Định nghĩa kiểu mảng T có kiểu các phần tử là KPT, có kiểu chỉ dẫn KCD để hướng dẫn cách tổ chức mảng cũng như cách truy nhập vào các phần tử mảng được viết trong Pascal như sau :

Type Kiểu_mảng T = Array[ Kiểu_chỉ_dẫn KCD ] Of Kiểu_phần_tử KPT ;

hay viết tắt thành :

T = Array[ KCD ] Of KPT ;

Khi đó việc khai báo một biến A có kiểu là Kiểu_mảng có thể được viết như sau :

Var A : Kiểu_mảng T ;

hoặc ta có thể khai báo trực tiếp biến A cùng với kiểu của mảng trong phần khai báo biến khi không có định nghĩa kiểu trong phần Type :

Var A : Array[ KCD ] Of KPT ;

Chúng ta hãy xét một số ví dụ định nghĩa và khai báo sau :

Type

30

Page 31: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

AI = Array[ 1.. 10 ] Of Integer ; AC = Array [ 1.. 10 ] Of Char ; Color = ( Red, Blue, Green, White, Black ) ; Var A, B, C : AI ; X, Y : AC ; M1, M2 : Array[ -3.. 5 ] Of Real ; MC : Array[ 'A'.. 'Z' ] Of Integer ; MM : Array[ Color ] Of Boolean ;

AI, AC là hai kiểu mảng gồm 10 phần tử được đánh số thứ tự từ 1 đến 10 thông qua kiểu chỉ dẫn là một đoạn con các số nguyên 1.. 10. Các phần tử của AI có kiểu là số nguyên còn các phần tử của AC có kiểu là các kí tự. A, B, C là các biến có kiểu là AI.

Còn M1, M2 là hai biến được định nghĩa kiểu luôn khi khai báo. Đây là hai biến mảng gồm 9 phần tử là các số thực, được đánh số từ -3 đến 5.

MC là một biến mảng gồm 26 số nguyên được đánh số qua các chỉ dẫn là các chữ cái từ 'A' đến 'Z'.

MM là một mảng gồm 5 phần tử kiểu Boolean, các phần tử đựoc đánh dấu qua chỉ dẫn là tên của 5 màu sắc.

Một điều lưu ý là khi khai báo mảng, kiểu chỉ dẫn chí có thể là các kiểu đơn giản như sau : kí tự ( như biến MC ), đoạn con ( ví dụ đoạn con Integer như các kiểu AI, AC ), kiểu liệt kê do người sử dụng định nghĩa (như biến MM) và kiểu Boolean. Kiểu chỉ dẫn không được là kiểu Real hoặc Integer. Nghĩa là không được viết :

X : Array[ Integer ] Of Integer ; Y : Array[ Real ] Of Integer ;

Việc truy nhập vào một phần tử nào đó của mảng được thực hiện qua tên biến mảng, theo sau là giá trị chỉ dẫn để trong ngoặc vuông như :

MM[ Red ] := True ; MC[ 'B' ] := 5 ;

Do thời gian truy nhập vào một phần tử của mảng không phụ thuộc vào giá trị của chỉ dẫn nên cấu

trúc mảng thuộc kiểu cấu trúc truy nhập trực tiếp.

Ví du 1 : Gán tất cả 5 giá trị của mảng B ( như đã định nghĩa ở trên ) qua bàn phím, ta sẽ dùng thêm một biến I có kiểu là Integer để làm biến chỉ dẫn :

Writeln (' Vao so lieu cho mang B ' ) ; For I := 1 To 5 Do Begin Write (' B[ ', I, ' ] = ') ; Readln ( B[ I ] ) ; End ;

Kết quả thể hiện ra màn hình với các con số là do người sử dụng gõ vào :

Vao so lieu cho mang B B[1] = 2

31

Page 32: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

B[2] = 12 B[3] = 612 B[4] = 2 B[5] = 34

Nếu bạn muốn vào số liệu của cả một hàng của Array trên cùng một dòng màn hình thì bạn phải ghi rõ tất cả các biến cần đọc ( là các phần tử của mảng ) trong thủ tục Readln. Khi này sẽ không áp dụng vòng For được nữa :

Write (' Vao so lieu hang 1 ') ; Readln ( B[1], B[2], B[3], B[4], B[5] ) ;

Kết quả hiện ra màn hình :

Vao so lieu hang 1 : 2 12 612 2 34

Giữa các số gõ là các dấu cách với số lượng tùy ý nhưng ít nhất phải là 1.

Ví du 2 : Cộng hai mảng C = A + B ( A, B, C với định nghĩa như trên thực ra là các mảng hay ma trận một chiều ) :

For I := 1 To 10 Do C[ I ]:=A[ I ] + B[ I ] ;

Ví du 3: Giả sử ta muốn đếm trong 100 lần gõ kí tự vào qua bàn phím, số lần xuất hiện các kí tự từ 'A' đến 'Z' là bao nhiêu. Biến MC được khai báo dưới đây đóng vai trò là bộ đếm, biến kí tự Ch được dùng như là biến chỉ dẫn

Var I : Integer ; Ch : Char ; MC : Array[ 'A'.. 'Z' ] Of Integer ; BEGIN (* Xóa mảng MC về không *) For Ch := 'A' To 'Z' Do MC[ Ch ] := 0 ; (* Đọc 100 kí tự và đếm *) For I := 1 To 100 Do Begin Readln ( Ch ) ; (* Hàm Upcase biến chữ thường thành chữ hoa, Ví dụ 'a' thành 'A' *) Ch := Upcase ( Ch ) ; (* Đếm số lần xuất hiện từng kí tự *) ; Inc ( MC[ Ch ] ) ; End ; (* Chỉ in ra kết quả trên màn hình các chữ đã xuất hiện *) For Ch := 'A' To 'Z' Do If MC[ Ch ] > 0 Then Writeln ( ' So chu ', Ch,' = ', MC [Ch ] : 4 ) ; END.

32

Page 33: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Kết quả hiện ra trên màn hình có dạng :

So chu A = 2 So chu C = 68 ........................So chu Z = 8

Sắp xếp các phần tử của mảng theo một trật tự tăng hoặc giảm là một ví dụ rất bổ ích cho việc nắm vững các phép xử lí mảng. Sau đây sẽ trình bày một số phương pháp sắp xếp mảng qua các ví dụ.

Giả sử ta có một dãy dữ liệu ( số thực, số nguyên, kí tự ... ) được chứa trong một mảng. Sau đây là một số vì dụ về một số phương pháp xếp mảng các số nguyên. Việc các phần tử mảng là các số nguyên chỉ là một ví dụ, nó có thể là mảng các số thực hoặc mảng các xâu kí tự.

Cách làm:Đầu tiên đem phần tử thứ nhất so sánh với các phần tử tiếp theo, nếu nó lớn hơn thì đem đổi chỗ

giá trị của hai phần tử so sánh. Kết quả sau lượt đầu tiên giữ giá trị nhỏ nhất. Tiếp theo vòng 2, Đem phần tử thứ 2 so sánh với các phần tử tiếp theo.

Program SAP_XEP ; Const N = 5 ; Var MI : Array[ 1.. N ] Of Integer ; T : Integer ; (* T là biến trung gian *) I, J : Integer ; BEGIN (* Đọc các số cần sắp xếp vào mảng MI *) For I := 1 To N Do Begin

Write (' MI[ ', I ,' ] = ') ; Readln ( MI[ I ] ) ; End ; (* Sắp xếp *) For I := 1 To N - 1 Do For J := I + 1 To N Do Begin If MI[ I } > MI[ J ] Then Begin T := MI[ I ] ; MI[ I ] := MI[ J ] ; MI[ J ] := T ; End ; End ; (* In ra kết quả *) Writeln ; Writeln ( ' Sau khi sap xep ' ) ; For I := 1 To N Do Writeln ( MI[ I ] : 6 ) ; END.

33

Page 34: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Kết quả chương trình hiện ra trên màn hình :

M[ 1 ] = - 1 M[ 2 ] = 456 M[ 3 ] = 34 M[4 ] = - 312M[ 5 ] = - 56

Sau khi sắp xếp :

-312 -56 -1 34 456

Kiểu phần tử của mảng không bị hạn chế nhiều như kiểu chỉ dẫn. Nó còn có thể là các kiểu có cấu trúc. Ví dụ sau cho thấy việc khai báo một mảng có các phần tử cũng là mảng.

Ví du :

Type PT = Array [ 1.. 5 ] Of Real ; Color = ( Red, Blue, Green, White, Black ) ; Var MPT : Array [ 1.. 3 ] Of Pt ; Z : Array [ 1.. 3, 'A'.. 'C' ] Of Color ;

hoặc viết một lần như sau :

Var MPT : Array [ 1.. 3 ] Of Array [ 1.. 5 ] Of Real ;

hoặc thường được viết gọn lại :

Var MPT : Array [ 1.. 3, 1.. 5 ] Of Real ;

MPT được định nghĩa như trên chính là ma trận hai chiều 3 hàng và 5 cột.

Việc truy nhập đối với mảng có định nghĩa phức tạp như MPT được tiến hành qua hai lần đóng mở ngoặc vuông. Ví dụ MPT [3] [5] hoặc MPT [ 3, 5 ] biểu diễn phần tử ở hàng 3 và cột 5.

Cách viết MPT[i] [j] và MPT[ i, j ] là tương đương nhau. Mảng được định nghĩa như trên có thể hiểu là ma trận nhiều chiều. Phần tử MPT[ i, j ] sẽ là phần tử ở hàng thứ I, cột thứ J của MPT

Ví du : Chương trình nhân hai ma trận vuông cấp N

C = A * B Phần tử của ma trận tích được tính theo công thức :

Const N = 3 ; Phay = ', ' ; (* Hằng kí tự : Dấu phẩy *) Var

34

Page 35: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

A, B, C : Array[ 1.. N, 1.. N ] Of Integer ; I, J, K : Integer ; BEGIN (* Đọc giá trị của ma trận A *) For I := 1 To N Do For J := 1 To N Do Begin Write ( ' A[ ', I, phay, J, ' ] = ' ) ; Readln ( A[ I, J ] ) ; End ; (* Đọc giá trị của ma trận B *) For I := 1 To N Do For J := 1 To N Do Begin Write ( ' B[ ', I, phay, J, ' ] = ' ) ; Readln ( B[ I, J ] ) ; End ; (* Nhân hai ma trận vuông cấp N C = A * B *) For I := 1 To N Do For J := 1 To N Do Begin C[ I, J ] := 0 ; For K := 1 To N Do C[ I, J ] := C[ I, J ] + A[ I, K ] * B[ K, J ] ; End ; (* In kết quả theo kiểu viết ma trận *) Writeln (' Tich cua hai ma tran = ') ; For I := 1 To N Do Begin For J := 1 To N Do Write ( C[ I, J ] : 5 ) ; Writeln ; End ; END.

Trong chương trình trên, việc đọc ma trận được tiến hành qua từng dòng cho mỗi phần tử của mảng. Bạn có thể sửa lại đọc vào ma trận dưới dạng từng dòng tương ứng với từng hàng của ma trận :

(* Đọc vào giá trị của ma trận A theo từng hàng *) For I := 1 To N Do Begin

Write (' Hang ', I, ' : ' ) ; Readln ( A [ I, 1 ], A [ I, 2 ], A [ I, 3 ] ) ;

End ;

Cách làm này không cho dùng vòng For mà ta phải ghi trực tiếp các phần tử cần đọc vào thủ tục Readln.

Một cách khác lười hơn đỡ phải đọc ma trận trong khi thử, hãy làm một đoạn chương trình tạo số ngẫu nhiên cho các phần tử của ma trận. Bạn cần nhớ lại hoặc tra cứu hàm Random và Randomize.

35

Page 36: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Mảng có thể dùng làm tham số cho chương trình con và mảng không bao giờ dùng làm kết quả của Function . Tuy nhiên cần lưu ý khai báo kiểu của tham số trong vùng khai báo Type chứ không định nghĩa trực tiếp ngay trong phần khai báo tham số của chương trình con.

Ví du: Cộng hai ma trận C = A + B

Type MT = Array [ 1.. 3, 1.. 5 ] Of Real ; Var X, Y, Z : MT ; (* ----------------------------------------------------- *)Procedure Cong_ma_tran ( A, B : MT ; Var C : MT ) ; Var I, J : Integer ; Begin For I := 1 To N Do For J := 1 To N Do C [ I, J ] := A [ I, J ] + B [ I, J ] ; End ; (* -----------------------------------------------------*)BEGIN ................. Cong_ma_tran ( X, Y, Z ) ; ................. END.

Các chương trình dịch Pascal hiện nay đã có một kiểu dữ liệu mới là xâu kí tự để xử lý các chuỗi, các dãy kí tự có độ dài thay đổi... nhằm đáp ứng nhu cầu xử lý văn bản, xử lý từ (ngữ). Một xâu kí tự được định nghĩa bằng từ khóa String theo sau là số kí tự cực đại có thể có của xâu kí tự, được đặt trong ngoặc vuông :

String [ do_dai_cuc_dai ] ;

Ví du 1 :

Var Filename : String[20] ; Line : String[80] ; (* Dòng 80 kí tự là nhiều nhất *)

Ví du 2: Biến Filename khai báo ở trên được gán giá trị :

Filename := 'Vidu.pas' :

khi này độ dài của xâu kí tự Filename là 8 kí tự, mặc dù độ dài cực đại cho phép của Filename là 20.

Hàm chuẩn Length (St) cho ta độ dài của xâu kí tự St. Một xâu chữ có thể là rỗng (không chứa kí tự nào) và khi đó St := '' hay Length (St) = 0.

Truy nhập vào các phần tử của xâu kí tự : ta có thể truy nhập vào từng kí tự một của xâu kí tự với tên biến và chỉ số đặt trong ngoặc vuông như khik truy nhập vào phần tử của mảng. Chỉsố này có thể chạy từ 1 đến độ dài cực đại của xâu kí tự

36

Page 37: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

If filename[3] = 'D' then Writeln (' Chu thu ba cua xau ki tu la D ') ;

Nếu vị trí kí tự đó nằm ngoài độ dài thực của xâu kí tự thì phần tử đó của xâu không có giátrị xác định. Vì vậy, khi truy nhập vào từng phần tử của xâu chữ, ta còn cần phải kiểm tra xem vị trí đó có nằm trong khoảng độ dài thực của xâu hay không.

If 3 < Length(Filename) then Writeln (' Chu thu ba cua Filename la : ', Filename[3]) ;

Bài 9: XÂU KÍ TỰ (STRING)1. Phép cộng xâu:

Xâu kí tự có thể sử dụng như các toán hạng trong các biểu thức để ghép xâu kí tự qua dấu "+".

Ví duï:Filename := ' Vidu.pas ' ;Filename := ' C:\ ' + Filename ;

Cho kết quả của Filename là : ' C:\Vidu.pas ' ; hoặc Filename := ' Ten ' + ' file ' + '.pas ' ;

Cho kết quả của Filename là : ' Tenfile.pas ' ;Rõ ràng với kiểu mảng kí tự , chúng ta không thể thực hiện được phép cộng để ghép hai mảng với

nhau vì độ dài của chúng đã cố định.* Lưu ý: không có phép tính trừ, nhân, chia cho xâu kí tự.

2. Khai báo String làm tham số chương trình con :Tương tự Array , String có thể dùng làm tham số cho chương trình con ,

Ví dụ:Type St20 : String[20] ; St30 : String[30] ;Var Ten20 : String[20] ; Ten30 : String[30] ;Function Vidu1 : St20 ;Procedure Vidu2 ( St : St30 ) ;

Cách viết sau đây là sai :Function Vidusai : String[20] ;Procedure Vidusai (St : String[30]) ;

Khi dùng String làm tham số cho chương trình con , độ dài của tham số thực phải bằng độ dài của tham số hình thức. Vì vậy lời gọi thủ tục sau là đúng hoàn toàn :

Vidu2(Ten30) ;vì Ten30(tham so thuc) có kiểu là St30 trùng với tham số hình thức (St30).

Tuy vậy , bạn có thể chuyển tham số String có độ dài khác vào chương trình con bằng cách hướng dẫn chương trình dịch không kiểm tra tính tương thích về độ dài. Cách làm : định hướng {$V-}sẽ bỏ việc kiểm tra tính tương thích về độ dài của tham số xâu kí tự và {$V+} sẽ làm hoạt động việc kiểm tra trở lại.

37

Page 38: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Ví dụ: Lời gọi Vidu2(Ten20) sẽ gây ra lỗi vì Ten20 có độ dài khác St30. Muốn khắc phục điều này , ta chỉ cần thêm định hướng {$V-} :

{$V-}Vidu2 (Ten20) ;{$V+} *

Bạn có thể đặt {$V-} ngay ở đầu chương trình để bỏ việc kiểm tra String trong toàn bộ chương trình.

3. Viết ra màn hình và đọc:Có thể dùng Write(St) hay Writeln(St) cho một xâu kí tự St.Read(St) hay Readln(St) sẽ đọc các kí tự cho xâu St với độ dài thực là số kí tự gõ vào từ bàn

phím.

4. Các thủ tục và hàm chuẩn xử lý xâu kí tự:

_ Length(St) là hàm cho ta độ dài của xâu St.Ví dụ: với St := 'Filename' ; thì Length(St) có giá trị bằng 8.

_ Delete(St , Pos , Num) là thủ tục xóa đi một số kí tự Num kể từ vị trí Pos trong xâu St.Ví dụ : Sau khi gọi Delete (St , 2 , 3) ; St sẽ còn ' Fname ' vì bị xóa đi 3 kí tự ' ile '. Nếu Pos +

Num > Length (St) thì St sẽ bị xóa toàn bộ kí tự kể từ vị trí Pos.

_ Insert(Obj , St , Pos) là thủ tục xen xâu kí tự Obj vào xâu St tại vị trí Pos.Ví dụ: Sau khi gọn Insert(' 12 ' , St , 4) ; thì St sẽ thành ' Fil12ename '. Nếu Length (Obj) +

Length (St) vượt quá độ dài cực đại cho phép thì chỉ những kí tự nào nằm trong khoảng độ dài cực đại cho phép mới được giữ lại.

_ Str(Value , St) là thủ tục biến đổi giá trị bằng số nguyên hoặc thực Value thành một dãy kí tự biểu diễn số đó

Ví dụ: I là biến kiểu số nguyên , X là biến kiểu số thực :I := 512 ;Str(I : 5 , St) ; sẽ cho ra St là ' 512 ' (* 5 kí tự *) X := 123.4567890 ;Str(X : 12 : 5 , St) ; cho ra St là ' 123.45678 ' (* 12 kí tự *)

_ Val(St , Var1 , Code) là thủ tục biến đổi một xâu kí tự St (biểu diễn một số nguyên hoặc thực) thành một số nguyên hoặc thực chứa trong Var1. Code là số nguyên để phát hiện lỗi.

Ví dụ:St1 := ' 123.45 ' ;St2 := ' 123X ' ;Val (St1 , Var1 , Code1) ; cho ta Var1 = 123.45 và Code1 = 0 ;Val (St2 , Var2 , Code2) ; cho ta Var2 không xác định và Code2 = 4 ;

Lưu ý : Các biến Var1 , Var2 , Code1 , Code2 đều phải được khai báo trước.

_ Copy(St , Pos , Size) nhận Size kí tự trong St từ vị trí Pos.

38

Page 39: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Ví dụ:St := ' 12345678 ' ;St1 := Copy (St , 3 , 2) ; sẽ cho St1 = ' 34 ' ;

Nếu Pos > Length (St) thì Copy sẽ cho một xâu rỗng.Nếu Pos + Size > Length (St) thì Copy sẽ chỉ nhận các kí tự nằm trong xâu St.

_ Concat(St1 , St2 ,... , StN) là hàm ghép nối tất cả các xâu kí tự St1 , St2 ,... , StN thành một xâu kí tự theo thứ tự đã viết. Tất nhiên , nếu tổng chiều dài của tất cả các xâu kí tự lớn hơn 255 thì máy sẽ báo lỗi.

_ Pos(Obj , Target) là hàm cho ta vị trí đầu tiên của xâu Obj gặp trong xâu Target. Nếu không tìm thấy , Pos có giá trị bằng 0.

Ví duï : Nếu St = ' 123454545 ' và Obj = ' 45 ' thì Pos (Obj , St) cho giá trị bằng 4.Pos (' 4X ' , St) cho giá trị bằng 0 vì không tìm thấy.

Bài 10: KIỂU DỮ LIỆU CÓ CẤU TRÚC : KIỂU TẬP HỢP (SET)

1. Kiểu tập hợp: Một tập hợp bao gồm một số các đối tượng nào đó có cùng bản chất. Trong Pascal điều đó có nghĩa

là có cùng một mô tả kiểu, kiểu này được gọi là kiểu cơ bản. Kiểu cơ bản bắt buộc phải là một kiểu vô hướng hay một đoạn con và không được là số thực. Các đối tượng này được gọi là phần tử của tập. Số phần tử cực đại cho phép có thể còn tùy thuộc vào chương trình dịch Pascal của các hãng khác nhau. Ví dụ trong Turbo Pascal và IBM Pascal số này là 256. Khái niệm tập hợp trong ngôn ngữ Pascal gắn liền với khái niệm tập hợp trong toán học.

Để mô tả kiểu và khai báo biến kiểu tập hợp người ta dùng từ khóa SET OF theo sau là kiểu cơ bản T (kiểu của các phần tử của tập hợp).

Ví dụ:

Type Chu_Cai = Set Of Char ; (* Chữ cái *) Chu_So = Set Of 0.. 9 ; (* Chữ số *) Ngay = ( Hai, Ba, Tu, Nam, Sau, Bay, ChuNhat ) ; So_N = 0.. 320 ; Kieu_Xe_Dap = ( ThongNhat, Eska, Mifa, Peugeot ) ; Var A, B, C : Set Of So_N ; Xe : Set Of Kieu_Xe_Dap ; L : Set Of Chu_Cai ; Ch : Char ; (* Char : Tập hợp được định nghĩa trước *) Ngay_trong_tuan : Set Of Ngay ;

2. Xác lập một tập: Một tập hợp được xác lập bằng cách liệt kê các phần tử của tập hợp, chúng cách nhau bằng dấu phẩy và được đặt giữa hai ngoặc vuông. Ví dụ với các biến đã được khai báo ở trên, ta có thể viết các tập :

[ ] ; (* Tập rỗng, không có phần tử *)

39

Page 40: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

[ 3.. 5 ] ; (* Tập các chữ số 3, 4, 5 *)[ 3, 4, 5, 8 ] ; hoặc [ 3.. 5, 8 ] ; [ 'A'.. 'C', 'Y', 'Z' ] ; [ Hai.. Tu, ChuNhat ] ; (* Tập một số ngày trong tuần *0

Bản thân các phần tử của tập hợp cũng có thể cho bằng biến hoặc bằng biểu thức :

[ X + Y, I * J, 3, 4 ]

biểu diễn tập hợp các số nguyên gồm số 3, số 4 và các số nguyên nhận được qua biểu thức X + Y và I * J (với X, Y, I, J là các số nguyên).

Bài 11: CÁC PHÉP TOÁN TRONG TẬP HỢP1. Phép gán:

Các giá trị có được từ các biểu thức xác lập một tập hợp và kiểu cơ bản của chúng đương nhiên phải là giống nhau

Ví dụ : Với mô tả và khai báo ở trên ta có thể viết các câu lệnh :

A := [ 3.. 5 ] ; B := [ 4.. 6, 10, 123 ] ;L := [ 'A', 'B', 'D' ] ;L := [ 'A'.. 'D', 'M', 'P ' ] ; Ngay_trong_tuan := [ Ba, Sau ] ; L := [ ] ;

Tập rỗng có thể đem gán cho mọi biến kiểu tập hợp khác nhau. Chúng ta không thể gán L := [ 3, 5 ]; vì kiểu cơ bản của chúng không tương thích với nhau.

2. Phép hợp:Được kí hiệu bằng dấu +. Hợp của hai tập và một tập có các phần tử thuộc hai tập.

Ví dụ :

A := [ 3.. 5 ] ; B := [4..6, 10, 123] ;C := A + B ; (* Tập C sẽ là [ 3..6, 10, 123] *)

3. Phép giao:Được kí hiệu bằng dấu *. Giao của hai tập là một tập có các phần tử nằm chung của cả hai tập.

Ví dụ :

C := A * B ; (* Tập C sẽ là [ 4,5] *)

4. Phép hiệu: Được kí hiệu bằng dấu -.

40

Page 41: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Hiệu của hai tập là một tập có các phần tử thuộc tập thứ nhất nhưng không thuộc tập thứ hai.

Ví dụ :

C := A - B ; (* Tập C sẽ là [ 3 ] *)C := B - A ; (* Tập C sẽ là [6,10,123] *)

5. Phép thử "thuộc về":Là một phép thử để xem một biến hay một giá trị có thuộc một tập nào đó không. Kết quả của

phép "thuộc về" có kiểu là Boolean. Phép thử này được dùng với từ khóa IN. Ví dụ : Để thử xem biến Ch ( kiểu char ) cónằm trong câu trả lời “Có” bằng tiếng Việt và “Yes”

bằng tiếng Anh hay không, bằng cách thử thông thường ta viết :

Readln (Ch) ;If ( Ch = 'Y' ) or ( Ch = 'y' ) or ( Ch = 'C' ) or ( Ch = 'c' ) Then ...

Song ta có thể viết gọn lại với phép thử In như sau :

If Ch In [ 'Y', 'y ', 'C ', 'c' ] Then...

Hoặc nếu dùng một biến A ( kiểu tập )

A := ['Y ','y ', 'C', 'c' ] ;If Ch In A Then ...

6. Các phép so sánh <>, =, <= và >= :Hai tập được đem ra so sánh bằng các phép toán so sánh này trước hết phải có cùng kiểu cơ bản.

Kết quả của các phép so sánh này là giá trị kiểu Boolean, tức là đúng ( True ) hoặc Sai ( False ). Hai tập là bằng nhau nếu chúng có các phần tử như nhau từng đôi một ( không kể thứ tự sắp xếp

các phần tử trong hai tập ). Ngược lại với phép = là phép so sánh khác nhau <>.

Ví dụ :

A := [ 3, 5, 9 ] ;B := [ 9, 3, 5 ] ;If A = B Then Writeln ('Hai tap A và B bang nhau ') ;If A<>B Then Writeln (' Tap A khac tap B ') ;

Phép so sánh <= sẽ có giá trị là True nếu tất cả các phần tử tập thứ nhất đều thuộc tập thứ hai. Phép so sánh >= sẽ có giá trị là True nếu tất cả các phần tử tập thứ hai đều thuộc tập thứ nhất.

* Cần lưu ý là trong Pascal không tồn tại phép so sánh nhỏ hơn < và lớn hơn >. Muốn so sánh lớn hơn hay nhỏ hơn ta có thể dùng thủ thuật sau :

If ( A<=B ) and ( A<>B ) Then Writeln('A < B') ;

Để thử xem hai tập A và B có phần tử nào chung không ta dùng phép thử :

If A * B = [ ] Then Writeln ('A va B khong co phan tu chung ') ;

7. Tổng kết các phép toán trên cấu trúc dữ liệu kiểu tập:

41

Page 42: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Toán tử Kí hiệu Kiểu kết quảGán := Set Of …Hợp + Set Of …Giao * Set Of …

Hiệu - Set Of …

Thuộc về IN Boolean

Bằng nhau = Boolean

Khác nhau <> Boolean

Bao hàm <=, >= Boolean

Lệnh Read và Write không cho phép đọc và ghi trực tiếp dữ liệu kiểu tập hợp. Song ta có thể lập chương trình thực hiện các thao tác này khi mà kiểu cơ bản của tập hợp là số nguyên, kí tự.

Ví dụ: Đọc vào N kí tự để xây dựng một tập các kí tự Alpha nghĩ a là xáx định xem trong N số kí tự được đưa vào ( không kể số lần gõ ) sau đó in ra kết quả.

Type Chu_Hoa = Set Of 'A'.. 'Z' ; Var

Alpha, Beta : Chu_Hoa ; I, N : integer ; Ch : char ;

BEGIN Alpha := [ ] ; Write (' Enter N : ') ;Readln (N) ;For I := 1 To N Do Begin Readln ( Ch ) ; Ch := Upcase (Ch) ; (* Đổi chữ cái nhỏ thành lớn *) Alpha := Alpha + [Ch] ; End ; (* In ra các phần tử có trong tập Alpha *) Writeln (' Cac chu cai co trong tap Alpha la : ') ;For Ch :='A' To 'Z' Do

If Ch IN Alpha Then Writeln(Ch) ;END.

Kết quả chạy chương trình như sau :

Với N = 4, bạn gõ vào các kí tự theo thứ tự sau : 'a', 'c', 'A', 'a' Enter N : 4 acAa

Cac chu cai co trong tap Alpha la :

42

Page 43: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

A C

Giả sử ta đã biết số phần tử của tập Alpha. Khi này ta có thể in ra các phần tử của tập Alpha một cách có hiệu quả hơn vì nếu chúng ta biết được số phần tử của tập thì sẽ tránh được việc rà soát cả tập từ 'A' đến 'Z' ngay cả khi tập là rỗng hoặc chỉ chứa chữ 'B'.

I := 0 ; ch :='A' ;While I < So_phan_tu Do Begin If Ch IN Alpha Then Begin I := I +1 ; Writeln (Ch) ; End ; Ch := Succ(Ch) ; End ;

Cách thứ hai là dùng vòng lặp While. Tập Beta đựoc dùng để tránh cho tập Alpha không bị phá hủy vì trong vòng lặp ta có dùng phép hiệu :

BEGIN Beta := Alpha ; Ch := 'A' ; While Beta <> [ ] Do Begin If Ch IN Beta Then Writeln (Ch) ; Beta :=Beta - [Ch] ; Ch := Succ(Ch) ; End ;

Bải 12: KIỂU DỮ LIỆU CÓ CẤU TRÚC : KIỀU BẢNG GHI (RECORD)1. Khái niệm và định nghĩa:

Chúng ta đã học về các kiểu cấu trúc dữ liệu như mảng (Array), kiểu tập hợp (Set). Các kiểu cấu trúc dữ liệu này đều được tạo ra bằng một tập hợp các phần tử có cùng (mô tả), kiểu.Ví dụ: các phần tử của một array[1..100] of Integer là các số nguyên (Integer)...

Để tạo ra một kiểu cấu trúc dữ liệu mới với các phần tử dữ liệu có kiểu khác nhau nhưng có liên kết với nhau, người ta định nghĩa ra bản ghi hay còn gọi là The ghi, Phiêu ghi (tiếng Anh là Record). Nói một cách khác, để mô tả các kiểu khác nhau, chúng ta phải dùng cấu trúc kiểu Record. Như vậy Record là một phương tiện linh hoạt nhất để xây dựng các kiểu dữ liệu mới.

Cấu trúc dữ liệu Record được gắn liền với cấu trúc dữ liệu kiểu Tệp (File) (sẽ được trình bày ở chương sau) để lưu trữ dữ liệu. Không giống một số ngôn ngữ bậc cao khác như Fortran , ngôn ngữ Pascal còn cho phép Record có thể được mô tả và sử dụng một cách độc lập với File.

2) Mô tả Record:Mô tả Record được viết bằng chữ Record, theo sau là danh sách mô tả các phần dữ liệu của

Record mà ta gọi là truong. Mỗi một trường có một tên trường và được dùng để chọn các phần tử dữ liệu của Record, tiếp theo là mô tả kiểu trường. Mô tả Record bao giờ cũng được kết thúc bằng chữ End (có dấu chấm phẩy để kết thúc).

43

Page 44: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Để mô tả một kiểu T có cấu trúc Record với danh sách các trường có tên là S1 , S2 ,... , Sn và có các mô tả kiểu trường tương ứng là T1 , T2 ,... , Tn , ta có thể viết tổng quát sau :

Ví dụ 1: Một địa chỉ bao gồm các dữ liệu như số nhà, tên phố, thành phố. Ta mô tả Record Dia_chi như sau :

Type Dia_chi = Record So_nha : Integer ;

Pho : String[20] ; Thanh_pho : String[15] ;

End ;

Như vậy chúng ta có 3 trường là So_nha, Pho và Thanh_pho với kiểu khác nhau (integer, string[20], string[15]) và chúng được liên kết lại với nhau để mô tả địa chỉ.

Ví dụ 2 : Để mô tả thời gian Date, ta có 3 trường : Ngày, Tháng và Năm.

Type Date = Record Ngay : 1.. 31 ; Thang : 1.. 12 ; Nam : integer ; End ;

hoặc theo kiểu tiếng Anh, người ta hay dùng tháng với tên gọi tháng :

Type Date = Record Day : 1.. 31 ; Month : (Jan, Fer, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov ,Dec) ; Year : integer ; End ;

Ví dụ 3: Để miêu tả nhân sự hay phiếu cán bộ của phòng tổ chức, ta phải dùng các trường Họ tên, Ngày sinh, Chỗ ở, Lương... Ở đây ta ví dụ với 5 trường. Giả sử ta đã có mô tảù kiểu Date và Dia_chi như ở trên.

Type Nhan_su = Record Ho_ten : string[30] ; Ngay_sinh : Date ; Gioi_tinh : (Nam, nu) ; O_tai : Dia_chi ; Luong : Reals ;

End ;

Thí dụ 3 cho ta thấy điểm đặc biệt là việc mô tả lồng nhau của cấu trúc dữ liệu. Trong mô tả RECORD của nhân sự, ta có thể mô tả các phần tử (các trường) của Record là một kiểu Record khác như các trường Ngày sinh và chỗ ở. Mức lương được mô tả là Real (số thực) vì có thể đếm hàng xu, hàng hào.

44

Page 45: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Ta cũng có thể viết trực tiếp mô tả trường Ngay_sinh nếu như có mô tả kiểu Date :

Type Nhan_su = Record Ho_ten : String[30] ; Ngay_sinh : Record Ngay : 1.. 31 ; Thang : 1.. 12 ; Nam : integer ;

End ; Gioi_tinh : (Nam , Nu) ;

O_tai : Dia_chi ; Luong : Reals ;

End ;

Để thâm nhập vào môi trường của Record , ta cần phải dùng tên biến kiểu Record, sau đó dấu chấm (.) và tên trường của Record.

Ví dụ 4: Với mô tả kiểu được nêu ở trên, ta tiếp tục khai báo tên biến và thực hiện 1 đoạn chương trình để đọc dữ liệu vào các biến như sau :

Var Nguoi_1, Nguoi_2, Nhan_su ;

Ta thấy muốn thâm nhập vào trường Ho_ten của biến Nguoi_1, ta phải viết Nguoi_1.Ho_ten. Ở đây Nguoi_1 là tên biến kiểu nhân sự và Ho_ten là tên thường. Nguoi_1.Ho_ten là một biến kiểu String[30]. Còn Nguoi_1.O_tai. Pho cho ta thâm nhập vào trường Pho của trường O_tai của biến Nguoi_1. Trong đó O_tai có mô tả kiểu Dia_chi.

Dòng lệnh nguoi_2 := Nguoi_1 cho phép ta copy 2 biến với nhau. Thực chất dòng lệnh này là việc thâm nhập vào cả một biến kiểu Record chứ không phải là việc thâm nhập vào môi trường riêng lẻ nào đó của biến Record đó (là Nguoi_1 và Nguoi_2 ở đây).

Ta có thể dùng phép so sánh :

If Nguoi_1 = Nguoi_2 then writeln ('Cung mot nguoi!) ;

hoặc :

If Nguoi_2.Ho_ten = Nguoi_1.Ho_ten then writeln (hai nguoi trung ten nhau!)

Tuy nhiên cần lưu ý là không thể dùng các thao tác sau :_ Viết ra màn hình hoặc đọc từ bàn phím cả một biến kiểu Record như :_ Readln (Nguoi_1) hoặc Writeln (Nguoi_1) ;_ So sánh các Record bằng các phép toán quan hệ như sau : < , > , <= , >=. Riêng các phép so sánh <> (khác nhau) và = (bằng nhau) thì có thể được dùng với hai biến có cùng một kiểu Record.

_ Tất cả các phép toán số học và logic.

45

Page 46: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Chúng ta cũng có thể kết hợp kiểu Record với các kiểu dữ liệu khác như lập một mảng các Record. Để miêu tả đội ngũ cán bộ của một cơ quan nào đó có số người nhiều nhất là 100 chẳng hạn, ta có thể viết :

Var Canbo : Array[1.. 100] Of Nhan_su ; TG : Nhan_su ; (* Ô nhớ trung gian *)

I , J : integer ;Begin For I := 1 to 99 do For J := I + 1 to 100 do If Canbo[I].Ho_ten > Canbo[J].Ho_ten then Begin

TG := Canbo[I] ; Canbo[I] = Canbo[J] ; Canbo[I] := TG ;

End ;

Qua ví dụ trước ta thấy việc thâm nhập vào các trường của một biến kiểu Record là tương đối phức tạp và có phần tẻ nhạt vì phải dùng nhiều lần tên biến (Nguoi_1 trong ví dụ này) cùng với tên các trường. Để đơn giản cách viết, Pascal đưa ra lệnh WITH... DO... xét cùng với thí dụ 5 trên.

Ví dụ :

With Nguoi_1 DoBegin Write (' Ho va ten nguoi_1 : ') ; Readln(Ho_ten) ; With Ngay_sinh Do Begin Write ('Ngay sinh : ') ; Readln (Ngay) ; Write ('Thang sinh : ') ; Readln (Thang) ; Write ('Nam sinh : ') ; Readln (Nam) ; End ;End ;

Như vậy chúng ta còn có lồng các chỉ thị WITH... DO... vào với nhau để thâm nhập vào các trường ở sâu trong Record phức tạp như biến Nguoi_1. Nó có dạng viết :

WITH A DOWITH B DO...

Với A, B đều được mô tả là Record, song B là một trường của A (ở thí dụ trên B là Ngay_sinh, A là Nguoi_1). Ta có thể ghi gọn lại :

WITH A DO46

Page 47: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

WITH A, B DOWITH B DOBegin ...End ;

Với thí dụ 3, ta có thể thâm nhập vào các trường Ngay_sinh trực tiếp như sau :

With Nguoi_1, Ngay_sinh Do Begin Ngay := 12 ; Thang := 5 ; Nam := 1960 ;End ;

Hoặc với mảng Canbo[50], ta có thể viết :

With Canbo[50] Do Begin Ho_ten := "Le Thi Tam" ; End ;

Các kiểu Record được trình bày ở trên cố định vì số phần tử cũng như cấu trúc của Record là đã cố định. Bên cạnh đó , ngôn ngữ Pascal cho phép thành lập các Record có cấu trúc thay đổi được hay còn gọi là Record thay đổi.

Trước hết , ta xét ví dụ cụ thể sau : Trong mục Nhân_su , nếu ta xét thêm đến Nghe_nghiep , thì ta sẽ thấy có nhiều trường hợp xảy ra như :

_ Cong_nhan : Cần ghi rõ ngành gì , thợ bậc mấy._ Ky_su : Ngành gì , trình độ thực tế._ Bac_sy : Chuyen khoa gì_ Cá biệt : Không ghi gì thêm.Như vậy , lẽ ra ta phải lập một Record có đầy đủ các trường hợp kể trên khi ta giả sử rằng một

người tại một thời điểm nào đấy chỉ có thể có một hoàn cảnh gia đình nhất định. Điều đó hoàn toàn được nhưng Record được lập ra sẽ cồng kềnh và chiếm nhiều ô nhớ. Còn cách thứ hai là lập ra 4 kiểu Record giống nhau phần đầu nhưng chỉ khác nhau phần cuối là Nghe_nghiep sẽ có các trường tương ứng với 4 nghề khác nhau. Điều này cũng làm phức tạp và cồng kềnh chương trình ra vì ta phải dùng tới 4 kiểu Record. Nhôn ngữ Pascal cho phép lập Record có dạng sau để tiết kiệm ô nhớ và cho phép linh hoạt sử dụng :

Type Nghe = (Cong_nhan , Ky_su , Bac_sy , Ca_biet) ; Nganh = (Dien , Co_khi , Hoa) ; Khoa = (Noi , Ngoai , Nhi , Phu) ; Nhan_su = Record Ho_ten : String[30] ; Ngay_sinh : Date ; Gioi_tinh : (Nam , Nu) ; O tai : Dia_chi ; Luong : Real ;

47

Page 48: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Case Nghe_nghiep : Nghe Of Cong_nhan : (NganhCN : Nganh) ; Bac_tho : Byte ; Ky_su : (NganhKS : Nganh) ; TrinhDoTT : (Kem , TB , Kha , Gioi) ; Bac_sy : (Chuyen_Khoa : Khoa) ; Ca_biet : ( ) ; End ; (* Of Record *)Var Nguoi1 , Nguoi2 : Nhan_su ;BEGIN .......... With Nguoi1 Do Begin Ho_ten := ' Nguyen Van A ' ; Nghe_nghiep := Cong_nhan ; NganhCN := Dien ; Bac_tho := 3 ; End ; ........... With Nguoi2 Do Begin Ho_ten := ' Le Thi B ' ; Nghe_nghiep := Ky_su ; NganhKS := Dien ; TrinhDoTT := Kha ; End ;END.

CÁC QUY TẮC SỬ DỤNG RECORD CÓ CẤU TRÚC THAY ĐỔIRecord có cấu trúc thay đổi nói chung sẽ có 2 phần :* Phần cố định : Gồm các trường Ho_ten , Ngay_sinh , O_tai ,... Phần này là đặc điểm chung của mọi người , ai cũng có cả. Cách viết này hoàn toàn như Record bình thường. * Phần thay đổi : Luôn đặt sau phần cố định và chỉ cho phép có một trường thay đổi mà thôi. Nói cách khác phần thay đổi được đặt sau cùng trong danh sách các trường và nó được bắt đầu bằng câu lệnh Case. Tuy nhiên , phần thay đổi có thể lại chứa Record khác có cấu trúc thay đổi , nghĩa là ta lại có trường thay đổi thứ hai khác nằm trong một trường thay đổi. Đó là Record có nhiều mức thay đổi.

Sau đây là một ví dụ về Record có cấu trúc thay đổi ở nhiều mức. Ví dụ này được đưa ra để dành

cho những bạn đọc muốn đi sâu tham khảo thêm sau khi đã nắm vững cách dùng Record thay đổi một mức là loại thường dùng nhất.

Type Khoa = (Dien_tu , Toan , Co_khi) ; Nghe = (Thu_ki , Sinh_vien) ; Diem := 0.. 10 ; Nhan_Cong = Record Ho_ten : String[30] ; Case Cong_Viec : Nghe Of Thu_Ky : (Ngay_sinh : date , Luong : real) ;

48

Page 49: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Sinh_vien : (K : Byte) ; Case SV_Khoa : Khoa Of

Dien_tu : (Mach , Vi_tinh , Anh_van : Diem) ; Toan : (Dai_so , Giai_tich , Hinh_hoc : Diem) ; Co_khi : (Hinh_hoa , Chi_tiet_may : Diem)) ;

End ; (* Of Record *) ;Var N : Nhan_cong ;

Trong Record này có 2 mức biến dạng : Mức 1 là : Case Cong_viec : Nghe Of... Mức 2 là : Case SV_khoa : Khoa of...Mức 2 đương nhiên cũng tuân theo các quy tắc xây dựng Record có cấu trúc thay đổi kể trên , do

đó nó phải là trường cuối cùng của mức 1: trường có nhãn là Sinh_vien. Chính trường này có cấu trúc của một Record thay đổi nằm trong Record thay đổi khác.

Các câu lệnh sau là hợp lệ :

N.Cong_viec := Sinh_vien ;N.Ngày_sinh. Ngay := 8 ;N.Mach := 4 ;N.Dai_so := 4 ;N.SV_Khoa := Dien_tu ;N.K := 18 ;

Têp hay tâp du liêu là một tập hợp các dữ liệu có liên quan với nhau và có cùng kiểu được nhóm lại với nhau tạo thành một dãy. Chúng thường được chứa trong một thiết bị nhớ ngoài của máy tính (ví dụ như đĩa mềm, đĩa cứng, băng từ...) với một cái tên nào đó.

Tệp dữ liệu với dữ liệu được hiểu theo nghĩa rộng : đó có thể là chương trình, có thể là số liệu, có thể là các dữ liệu khác như kí tự, văn bản...

Tệp còn có tệp có định kiểu, tệp văn bản và tệp không định kiểu (sẽ học kĩ ở cuối chương) . Để dễ hình dung ra tệp, chúng ta hãy xem tổ chức tủ phiếu của thư viện. Các dữ liệu cho một cuốn

sách là tên sách, tên tác giả, giá tiền, số trang, nhà xuất bản... Các dữ liệu này được nhóm lại với nhau để tạo thành các tờ phiếu, mỗi tờ phiếu đóng vai trò là một phần tử của tệp dưới dạng một Record (bản ghi) . Đây cũng là lý do gắn liền khái niệm cấu trúc dữ liệu Record với cấu trúc File. Các phần tử của tệp (các Record) có cùng một kiểu dữ liệu (Ví dụ các phiếu thư viện đều giống nhau ở chỗ mỗi cái đều có tên sách, tên tác giả, nhà xuất bản...) . Các phiếu này được xếp lại thành một tệp (phiếu) và được để vào một ô ngăn kéo nào đó với một cái tên (tên tệp) . Ví dụ ngăn chữ A (tên tệp là A) là tệp các cuốn sách có tên bắt đầu bằng chữ A. Các ngăn kéo lại được chứa trong một cái tủ. Trong máy tính, một đĩa cứng hoặc một một đĩa mềm đóng vai trò là chiếc tủ.

File còn được gọi là hồ sơ, là tập tin. Tệp thường được chứa trong một bộ nhớ ngoài như đĩa cứng, đĩa mềm, băng từ. Điều đó cũng có

nghĩa là tệp được lưu trữ để dùng nhiều lần và tồn tại ngay cả khi chương trình kết thúc hoặc mất điện. Khác với các cấu trúc dữ liệu khác mà chúng ta đã học như : mảng, tập hợp, bản ghi, là các cấu trúc dữ liệu được tổ chức trên bộ nhớ trong (RAM) của máy tính nên một khi kết thúc chạy chương trình hoặc mất điện thì các dữ liệu này cũng mất luôn. Vì vậy những dữ liệu nào cần lưu trữ (như hồ sơ cán bộ, vật tư hàng hóa của kho, tín hiệu điện...) thì ta bắt buộc phải dùng đến tệp. Bên cạnh đó một số thiết bị ngoại vi như bàn phím, màn hình, máy in được coi như là một tệp (xem phần tệp văn bản ở sau) . Tệp cũng còn có thể tổ chức trong bộ nhớ trong của máy song đó là những tệp tạm thời, trung gian vì chúng không lưu trữ lại được khi dừng chương trình hoặc mất điện.

49

Page 50: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Tệp là một kiểu dữ liệu có cấu trúc. Định nghĩa của tệp có phần nào giống mảng ở chỗ chúng đều là tập hợp của các phần tử dữ liệu có cùng kiểu. Song mảng được định nghĩa và khai báo trong chương trình với số phần tử đã xác định còn số phần tử của tệp không được xác định khi định nghĩa.

Định nghĩa một kiểu tệp T với các phần tử có kiểu là KPT (Kiểu phần tử) được viết trong phần mô tả kiểu với từ khóa FILE OF như sau :

Type T = File Of KPT ;

Sau đó khai báo một biến tệp (FileVar) trong phần khai báo biến :

Var Biên_têp : Kiêu_têp ;

hoặc khai báo trực tiếp một biến tệp với mô tả kiểu :

Var Biên_têp : File Of Kiêu_phân_tu ;

Ví dụ:

Type FileInteger = File Of Integer ; FileReal = File Of Real ; FileBoolean = File Of Boolean ; NhanSu = Record Ten : String[ 30 ] ; Tuoi : Byte ; Luong : Real ; End ; FileNhanSu = File Of NhanSu ; Var (* khai báo các biến tệp *) F1, F2 : FileInteger ; (* F1, F2 là hai biến tệp có các phần tử là số nguyên *) F3 : FileReal ; (* F3 là tệp các số thực *) FNS : FileNhanSu ; (* FNS là tệp các bản ghi nhân sự *) F5 : File Of Char ; F6 : File Of Array[ 1.. 5 ] Of Integer ;

F6 là biến tệp được khai báo trực tiếp trong phần Var với các phần tử là mảng một chiều, độ dài mảng là 5.

FileInteger là kiểu tệp có các phần tử là số nguyên.FileReal là kiểu tệp có các phần tử là số thực.

Kiểu của phần tử của tệp có thể là bất kỳ kiểu dữ liệu nào (kiểu vô hướng, kiểu có cấu trúc như mảng, tập, bản ghi) , trừ kiểu tệp nghĩa là không có kiểu tệp của tệp.

Các phần tử của một Array hoặc một Record có thể truy nhập được tùy ý (Random Access) thông qua tên biến, chỉ dẫn hoặc tên trường. Các phần tử của tệp không có tên và việc truy nhập không thể tùy tiện được. Các phần tử của tệp được sắp xếp thành một dãy và ở mỗi thời điểm chương trình chỉ

50

Page 51: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

có thể truy nhập vào một phần tử của tệp thông qua giá trị của một biến đệm (Tampon Variance). Biến đệm được dùng để đánh dấu vị trí truy nhập hay còn được gọi là cửa sổ (Window) của tệp.

Có những lệnh sẽ làm dịch chuyển cửa sổ sang vị trí tiếp theo hoặc về vị trí đầu của tệp. Ta có thể hình dung ra tệp như là một cuộn phim chụp ảnh. Mỗi một ảnh là một phần tử và ống kính là cửa sổ để nhìn vào nên tại mỗi thời điểm chỉ nhần thấy một ảnh. Sau mỗi lần chụp, cửa sổ sẽ nhìn vào ảnh ở vị trí tiếp theo.

Mỗi tệp đều được kết thúc bằng một dấu hiệu đặc biệt để báo hết tệp, hay gọi là EOF (End Of File). Pascal có một hàm chuẩn (Function) EOF, kiểu Boolean, với tham số là một biến tệp để thử xem cửa sổ đã đặt vào vị trí kết thúc tệp đó chưa. Nếu cửa sổ còn chưa trỏ vào phần tử cuối tệp thì EOF(F) có giá trị là False.

Việc phân loại tệp dựa trên việc bố trí các phần tử của tệp trong bộ nhớ ngoài và cách truy nhập vào tệp : tệp truy nhập tuần tự(Sequential Access), tệp truy nhập trực tiếp(Direct Access).

Thông dụng nhất là tệp có cấu trúc tuần tự : việc đọc một phần tử bất kỳ của tệp bắt buộc phải tuần tự đi qua các phần tử trước đấy. Còn muốn ghi hay thêm một phần tử vào tệp, ta cần phải đặt cửa sổ vào vị trí cuối tệp. Kiểu truy nhập này là đơn giản nhất trong việc xây dựng tệp cũng như xử lý tệp, song nó kém linh hoạt, Bộ nhớ ngoài điển hình tương ứng với cấu trúc này là băng từ.

Tệp truy nhập trực tiếp (direct access) là tệp có thể đặt cửa sổ vào một phần tử bất kỳ của tệp thông qua chỉ số thứ tự của phần tử trong tệp. Không phải loại bộ nhớ ngoài nào cũng có thể xây dựng tệp truy nhập trực tiếp do cấu tạo bộ nhớ. Ví dụ băng từ là loại chỉ có thể truy nhập tuần tự. Còn đĩa mềm, đĩa cứng là loại bộ nhớ có thể tạo tệp truy nhập trực tiếp do đầu từ ghi đọc có thể được điều khiển đặt vào một chỗ bất kỳ trên đĩa vào mọi thời điểm. Bạn có thể so sánh giữa băng từ ghi nhạc (bắt buộc truy nhập tuần tự) với đĩa hát (có khả năng truy nhập trực tiếp).

Pascal chuẩn chỉ định nghĩa loại tệp tuần tự và dưới đây nếu không nói rõ tệp loại gì thì ta hiểu đó là tệp tuần tự. Sau đó chúng ta sẽ nghiên cứu thêm về tệp truy nhập trực tiếp, được Turbo Pascal cũng như các ngôn ngữ khác đưa vào dùng nhiều.

Chương trình chỉ có thể cất dữ liệu vào một tệp sau khi ta làm thủ tục mở tệp . Việc mở tệp có thể ví như muốn cất các phếu thư viện thì đầu tiên phải đóng ô phiếu mới và gắn tên ô phiếu .

Để mở tệp để ghi, Turbo Pascal dùng 2 cặp thủ tục đi liền nhau theo thứ tự :

Assign ( Biên_têp, Tên_têp ) ; Rewrite ( Biên_têp ) ;

hay bằng tiếng Anh ta có :

Assign ( FileVar, FileName ) ; Rewrite ( FileVar )

Ví dụ:

Assign ( F,'nguyento.dat' ); (* gán tên tệp nguyento.dat cho biến F *) Reset ( F );

Tên tệp (FileName) là tên của tệp đặt trong thiết bị nhớ ngoài được đưa vào dưới dạng một

String. Ta phải đặt tên tệp sao cho nó phản ánh được ý nghĩa hoặc bản chất, nội dung của tệp. Ví dụ biến tệp F chứa các số nguyên tố thì tệp được đặt tên là ‘nguyento.dat’.

Tên tệp theo quy định chung gồm có hai phần cách nhau bằng dấu chấm (.) . Phần thứ nhất là phần tên riêng, có số chữ nhiều nhất là 8 . Phần tên này thể hiện nội dung của tệp đó . Phần thứ hai là phần mở rộng có nhiều nhất là 3 chữ, thông thường nói lên loại tệp .

51

Page 52: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Ví dụ : * . Pas : là tệp chứa chương trình viết bằng Pascal . * . Doc : là tệp chứa văn bản, tài liệu . * . Txt : chứa tệp văn bản .* . Com và * . Exe : là các tệp chứa chương trình dưới dạng mã mà máy có thể chạy ngay được trên máy tính . * . Dat : chứa các dữ liệu cần xử lý ( Data )

Sau khi mở tệp xong, tệp sẽ rỗng vì chưa có phần tử nào, cửa sổ tệp sẽ không có giá trị xác định vì nó trỏ vào cuối tệp (EOF). Đồng thời cần lưu ý khi mở tệp nếu trên bộ nhớ ngoài mà đã có sẵn tệp có tên trùng với tên tệp được mở thì tệp cũ sẽ bị xóa đi .

GHI CÁC GIÁ TRỊ VÀO TỆP VỚI THỦ TỤC WRITE :

Thủ tục WRITE sẽ đặt các giá trị mới vào tệp giống như ta bấm máy chụp ảnh . Mỗi lần chụp xong một ảnh, máy sẽ tự động đưa ống kính sang vị trí tiếp theo .

Cách viết : Write ( FileVar, Item1, Item2, . ., ItemN ) ;

hay Write ( Biên_têp, các giá tri cua têp vào ) ;

Trong đó Item1, Item2, . . . ItemN có thể là các hằng, các biến, các biểu thức, tất nhiên các Item phải có giá trị cùng với kiểu phần tử của tệp.

Hoặc với I, J, K là các biến Integer thì ta hoàn toàn có thể viết :

Write ( F, 3, I + 2 * J, K ) ;

Bước cuối cùng của việc đặt dữ liệu vào tệp là đóng tệp lại bằng thủ tục

Close ( Biên_têp ) ;

Ví dụ đối với tệp F1: Close ( F1 ) ;

Ví dụ 1: Sau đây chúng ta viết một thí dụ hoàn chỉnh : tạo một tệp chứa các số nguyên từ 1 đến 100 với tên tệp là ‘Nguyen . dat’ .

Program TAO_TEP_1 ; Var I : Integer ; F : File Of Integer ; BEGIN Assign ( F, 'Nguyen.dat' ) ; Rewrite ( F ) ; For I :=1 To 100 Do Write ( F, I ) ; Close ( F ) ; END .

Một tệp có thể đựoc dùng làm tham số của chương trình con (Procedure hoặc Function) với lời khai báo bắt buộc phải sau chữ Var tức là tệp được dùng làm tham biến .

52

Page 53: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Ví dụ 2 :

Program TAO_TEP_2 ; Type F1 = File Of Integer ; St30 = String [ 30 ] ; Var MyFile : F1 ; FileName : St30 ; (* ----------------------------------------------------- *) Procedure TaoFile ( Var F : F1 ; Ten : St30 ) ; Var I : Integer ; Begin Assign ( F, Ten ) ; Rewrite ( F ) ; For I := 1 To 100 Do Write ( F, I ) ; Close ( F ) ; End ; (* ----------------------------------------------------- *) BEGIN Write (' Ten tep : ') ; Readln ( FileName ) ; TaoFile ( MyFile, FileName ) ; END .

Ví dụ trên còn gài thủ thuật gài tên rtệp vào khi chương trình chạy thông qua một biến FileName, tương ứng với tham số hình thức là Ten.

Một tệp tuần tự được dùng như là đầu ra để cất dữ liệu thì cùng một lúc không thể làm đầu vào ( nguồn ) dữ liệu được, nghĩa là đối với tệp tuần tự, ta không thể vừa ghi vừa đọc cùng một lúc. Sau khi ghi dữ liệu vào tệp và đóng lại, bạn có thể đọc lại các giá trị dữ liệu trong tệp.

Một chương trình muốn sử dụng các dữ liệu đã được chứa trong một tệp đầu tiên chương trình phải mở tệp đó ra để đọc. Các thủ tục dùng cho công việc này như sau :

MỞ TỆP ĐỂ ĐỌC :

Assign ( Biến_tệp, Tên_tệp ) ; Reset ( Biến_tệp ) ;

hay Assign ( FileVar, FileName ) ; Reset ( FileVar ) ;

Khi chạy, chường trình sẽ đọc phần tử dữ liệu tại vị trí cửa sổ đang trỏ. Sau lệnh Reset, nếu tệp không rỗng thì cửa sổ bao giờ cũng trỏ vào phần tử đầu tiên của tệp và chương trình sẽ copy phần tử của tệp được trỏ sang biến đệm cửa sổ.

ĐỌC DỮ LIỆU TỪ TỆP :Việc đọc các phần tử từ tệp ra sau khi mở tệp đựoc thực hiện bằng thủ tục READ

53

Page 54: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Cách viết : Read ( Biên_têp, các biên ) ;

hoặc Read ( FileVar, Var1, Var2,... VarN ) ;

Thực hiện : đọc các giá trị tại vị trí cửa sổ đang trỏ (nếu có) gán sang biến tương ứng cùng kiểu. Sau đó cửa sổ dịch chuyển sang vị trí tiếp theo và đọc giá trị cho biến khác. Cứ thế đọc cho đến biến VarN.

Một điều cần lưu ý là trong thủ tục Read ta chỉ có thể đọc giá trị của tệp để gán giá trị cho các biến và chỉ cho các biến mà thôi. Không như trong thủ tục ghi vào tệp, các tham số thực là các Item ( hằng, biến, biêu thức ).

Việc đọc một phần tử của tệp còn cần có một điều kiện : phải thử xem tệp có còn phần tử không tức là cửa sổ chưa trỏ đến EOF. Hàm chuẩn EOF sẽ báo cho biết : nếu cửa sổ trỏ vào cuối tệp thì EOF(Biên_têp) = True, còn nếu cửa sổ chưa trỏ vào phần tử cuối của tệp thì EOF(Biên_têp) = False. Do vậy trước khi làm một thao tác gì để đọc tệp gán cho biến X, cần phải thử xem tệp đó đã kết thúc chưa bằng câu lệnh :

If Not Eof ( Biên_têp ) Then Read ( Biên_têp, X ) ;

hoặc nếu muốn đọc các phần tử của tệp :

While Not Eof ( Biến_tệp ) Do Begin Read ( Biên_têp, X ) ; (* Doc các phan tu cua têp *) ................... (* Xu lý biên X, nêu co *) End ;

Nếu cửa sổ đã trỏ đến phần Eof mà chương trình vẫn cố tình đọc thì sẽ gặp sai và máy sẽ báo lỗi, sau đó chương trình dừng lại.

Công việc cuối cùng kết thúc việc đọc tệp là đóng tệp lại với thủ tục giống như khi tạo tệp mới :

Close ( Biên_têp ) ;

Bây giờ chúng ta lấy ví dụ cụ thể. Giả sử tồn tại một tệp có tên là ‘Nguyen.dat’ được tạo ra bằng các thủ tục mở tệp cất dữ liệu như ở trên đã mô tả. Ta phải đọc ra giá trị thứ nhất và thứ ba của tệp và gán cho hai biến A, B tương ứng. Giả sử tệp không rỗng và chứa ít nhất 3 phần tử để ta không phải dùng phép thử Eof.

Ví dụ 3 :

Program DOC_TEP_1 ; Var A, B : Integer ; F : File Of Integer ; BEGIN Assign ( F, 'Nguyen.dat' ) ; Reset ( F ) ; Read ( F, A ) ; (* Đọc phần tử thứ nhất của tệp và chứa vào biến A *) Read ( F, B ) ; (* Đọc phần tử thứ hai của tệp và chứa vào biến B *) Read ( F, B ) ; (* Đọc phần tử thứ ba của tệp và chứa vào biến B,

lúc này B không giữ giá trị của phần tử thứ hai nữa *)

54

Page 55: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Close ( F ) ; END.

Sở dĩ phải đọc cả phần tử thứ hai là vì đây là tệp có cấu trúc tuần tự, muốn đọc phần tử thứ ba thì phải đọc qua phần tử thứ hai.

Ví dụ tiếp theo minh họa việc đọc tất cả các phần tử của một tệp các số nguyên nào đó và ghi ra màn hình giá trị các số nguyên đó và cuối cùng ghi ra cả số phần tử của tệp. Tên tệp sẽ được xác định lúc chạy chương trình chứ không có ngay từ lúc lập trình. Do không biết tệp kết thúc ở đâu nên ta phải dùng phép thử Not Eof.

Ví dụ 4 :

Program DOC_TEP_2 ; Var I : Integer ; SoPhanTu : Integer ; F : File Of Integer ; FileName : String [ 20 ] ; BEGIN Write ( ' Ten tep chua cac so nguyen : ' ) ; Readln ( FileName ) ; Assign ( F, FileName ) ; Reset ( F ) ; SoPhanTu := 0 ; While Not Eof ( F ) Do Begin Read ( F, I ) ; (* Đọc một phần tử tệp ra biến I *) Writeln ( I ) ; SoPhanTu := SoPhanTu + 1 ; (* Đếm số phần tử *) End ; Close ( F ) ; Writeln ( ' So phan tu cua tep ', FileName, ' la ', SoPhanTu ) ; END.

Ví dụ tiếp theo minh họa việc Copy từ một tệp các số nguyên gọi tệp nguồn sang một tệp khác. Chương trình được cho dưới dạng thủ tục.

Ví dụ 5 :

Type F : File Of Integer ; Var FS, FD : F ; (* FS : FileSource ( File nguồn ), FD : File Destination ( File đích ) *) Name1, Name2 : String [ 30 ] ; (* ------------------------------------------------------------- *)Procedure CopyFile ( Var Source, Destination : F ) ; Var I : Integer ; Begin Reset ( Source ) ;

55

Page 56: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Rewrite ( Destination ) ; While Not Eof ( Source ) Do Begin Read ( Source, I ) ; Write ( Destination, I ) ; End ; Close ( Source ) ; Close ( Destination ) ; End ; (* ------------------------------------------------------------- *)BEGIN Write ('Copy form file ') ; Readln ( Name1 ) ; Write (' to file ') ; Readln ( Name2 ) ; Assign ( FS, Name1 ) ; Assign ( FD, Name2 ) ; CopyFile ( FS, FD ) ; Writeln (' Copy successful ') ; END.

* Tệp với các phần tử của tệp là dữ liệu có cấu trúc :Các ví dụ trên mới chỉ đơn cử các chương trìng xử lý các tệp có các phần tử là các dữ liệu đơn

giản như Integer, Real... Tệp cũng có thể dùng mảng hoặc bản ghi như các phần tử của tệp (xem tệp FNS, F6 ở đầu chương).

Ví dụ với FNS, các phần tử của tệp FNS là bản ghi thì để ghi vào tệp ta phải dùng :

Write ( FNS, Nguoi ) ;

chứ không thể ghi riêng rẽ từng phần, từng trường :

Write ( FNS, Nguoi.ten ) ;

Pascal chuẩn chỉ định nghĩa một kiểu tệp : tệp truy nhập tuần tự. Các bộ nhớ ngoài như đĩa mềm, đĩa cứng... cho phép có thể tính toán tọa độ của một phần tử bất kỳ của tệp vì độ dài của các phần tử trong tệp là như nhau. Điều đó cho phép truy nhập trực tiếp vào tệp mặc dù cấu tạo logic của tệp vẫn là dạng tuần tự tức là phần tử nọ xếp sau phần tử kia. Trong Pascal có một thủ tục để truy nhập trực tiếp : SEEK.

* Cách viết : Seek ( FileVar, No );

với No là số thứ tự của phần tử trong tệp. Cần lưu ý là phần tử đầu tiên của tệp được đánh số 0.

Theo thủ tục này, máy sẽ đặt cửa sổ của tệp vào phần tử thứ No. Sau đó ta chỉ việc dùng các thủ tục Read để đọc phần tử đó ra hoặc Write để đặt giá trị mới vào. Như vậy ta có thể cập nhật một tệp một cách dễ dàng.

Ví dụ: Giả sử một tệp đã chứa 100 số nguyên từ 1 đến 100. Ta phải kiểm tra xem phần tử thứ hai (đếm từ 0) của tệp có giá trị bằng 3 không, nếu không bằng 3 thì phải sửa lại :

Var F : File Of Integer ;

56

Page 57: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Ch : Char ; I : Integer ; BEGIN ........... Assign ( F, 'Songuyen.dat' ) ; Reset ( F ) ; Seek ( F, 2 ) ; (* đặt cửa sổ vào vị trí thứ 3 *) Read ( F, I ) ; Writeln ( ' I = ', I ) ; If I <> 3 Then Write ( F, 3 ) ; (* nếu không bằng 3 thì sửa lại *) Close( F ) ; END.

FileSize ( FileVar ) : Hàm cho số phần tử của tệp FileVar. FileSize nhận giá trị 0 khi tệp rỗng, không có phần tử nào.

FilePos ( FileVar ) : Hàm cho vị trí tức thời của con trỏ tệp ( cửa sổ ) của tệp FileVar. Phần tử đầu tiên là phần tử số 0.

Ứng dụng: một tệp đã tồn tại chỉ có thể cho lớn lên tức là thêm số phần tử vào tệp bằng cách đặt thêm phần tử mới vào vị trí cuối cùng của tệp. Vì vậy con trỏ tệp có thể đặt vào vị trí cuối tệp bằng lệnh sau :

Seek ( FileVar, FileSize ( FileVar ) ) ;

Trong ví dụ ở bài trước, nếu muốn thêm số liệu I vào tệp F, ta viết :

Seek ( F, FileSize ( F ) ) ; Write ( F, I ) ;

Mọi sự thay đổi vể tệp chỉ được giữ lại trên đĩa khi thực hiện thủ tục Close( F ).

Erase ( FileVar ) ; Thủ tục xóa file trên đĩa có tên đã được ấn định với FileVar.

Ví dụ : muốn xóa file File.exe trên đĩa, ta viết :

Assign ( F, 'File.exe' ) ; Erase ( F ) ;

Rename ( FileVar, Str ) ; Thủ tục cho phép they đổi tên tệp thành tên chứa trong chuỗi Str. Bạn cần lưu ý là tên mới không được trùng với tên nào trên thư mục đang làm việc.

Ví dụ : muốn đổi tên tệp từ ‘File.old’ sang ‘File.new’, ta viết :

Assign ( F, 'File.old' ) ; Rename ( F, 'File.new' ) ;

57

Page 58: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Trong Turbo Pascal có một kiểu tệp được định nghĩa trước, đó là tệp văn bản được định nghĩa với từ chuẩn Text

Ví dụ : khai báo các biến tệp F1, F2 có kiểu Text :

Var F1, F2 : Text ;

Các phần tử của tệp kiểu text là các kí tự song Text File khác với File Of Char ở chỗ Text File được tổ chức thành từng dòng với độ dài mỗi dòng khác nhau nhờ có thêm các dấu hết dòng (End Of Line) hay dấu chấm xuống dòng. Đó là cặp kí tự điều khiển : CR (Carriage Return : nhảy về đầu dòng, mã ASCII = 13) và LF (Line Feed: nhảy thẳng xuống dòng tiếp theo, mã ASCII = 10). Chúng được nhận dạng để ngăn cách giữa hai dãy kí tự tuơng ứng với hai dòng khác nhau. Dấu CR và LF được màn hình cũng như máy in dùng làm kí tử điều khiển việc xuống đầu dòng tiếp theo.

Ví dụ : đoạn văn bản sau : vi du van ban

1234het

được hiểu là máy sẽ chứa trong tệp văn bản thành một dãy như sau : vi du van ban CR LF 1234 CR LF het EOF

Do tệp văn bản được ghi thành từng dòng nên việc ghi và đọc tệp văn bản cũng có thêm thủ tục ghi và đọc theo dòng là Writeln (Write Line) và Readln (Read Line). Chúng ta sẽ nghiên cứu kĩ thêm dưới đây.

Mặc dù tệp văn bản chứa các kí tự nhưng các thủ tục Read(ln) và Write(ln) có những khả năng đặc biệt để ghi và đọc được cả những số nguyên, số thực, Boolean hoặc String nhờ sự chuyển đổi thích hợp giữa các giá trị này với các dãy kí tự.

A. GHI VÀO TỆP VĂN BẢN: Chúng ta có thể ghi các giá trị kiểu Integer, Real, Boolean, String vào tệp văn bản bằng lệnh Write

hoặc Writeln. Cách ghi này cho phép chuyển các giá trị bằng số sang dạng kí tự tức là dạng đọc được một cách tường minh như trên trang giấy, cho phép viết các bảng dữ liệu... với quy cách mong muốn.

Các cách viết :

Write ( FileVar, Item1, Item2,... ItemN ) ; Writeln ( FileVar, Item1, Item2,... ItemN ) ; Writeln ( FileVar ) ;

_ Thủ tục Write( FileVar, Item1, Item2,... ItemN ) sẽ viết các giá trị của Item, là các biến, các hằng, hoặc biểu thức có kiểu đơn giản như Integer, Real, Char, Boolean, String vào biến tệp FileVar. Các Item không nhất thiết phải cùng kiểu.

Ví dụ :

Var I, J : Integer ; X : Real ; B : Boolean ;

58

Page 59: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

S5 : String [5] ;

Ta có thể viết :

Write ( FileVar, ' Vi du ', I, J, X, B, S5, 6, X + I ) ;

_ Thủ tục Write để ghi vào tệp văn bản sẽ không chấp nhận Item là các biến có cấu trúc ( Array, Set, Record và File ).

Ví dụ không thể viết :

Write ( FileVar, Nguoi ) ; (* Với Nguoi là một Record *)

vì Nguoi là một biến có cấu trúc.

Cách viết này chỉ được chấp nhận khi FileVar không phải biến tệp mà là tệp chứa các bản ghi NhanSu như ta đã thấy ở các phần trước.

_ Thủ tục Writeln( FileVar, Item1, Item2,... ItemN ) ; sẽ thực hiện việc đưa thêm dấu hiệu hết dòng vào tệp sau khi đã viết hết các giá trị các biến. _ Thủ tục Writeln( FileVar ) sẽ chỉ thực hiện việc đưa thêm dấu hiệu hết dòng ( cặp kí tự điều khiển CR và LF ) vào tệp, tức là đưa dấu cách dòng vào tệp.

* Cách viết có quy cách tùy vào từng kiểu dữ liệu mà cách viết có khác nhau đôi chút : _ Nếu VI là biểu thức nguyên : + Write ( FileVar, VI ) ; sẽ viết vào tệp FileVar giá trị nguyên VI với đúng số chữ số cần thiết. + Write ( FileVar, VI : n ) ; sẽ bố trí n chỗ cho giá trị nguyên VI và căn lề bên phải. Giả sử VI có giá trị bằng 12345

Write ( FileVar, VI, VI ); cho ra 1234512345Write ( FileVar, VI : 8, VI : 8 ); cho ra ___12345___12345

_ Nếu VR là một biểu thức thực + Write ( FileVar, VR : n ); cho ra cách biểu diễn số thực dạng có số mũ E tức là dạng viết khoa học của dấu phẩy động, với n chỗ được căn lề bên phải. Số chữ số từ chữ E trở đi luôn luôn là 4 kí tự ( kí tự E rồi đến dấu + hoặc -, cuối cùng là 2 chữ số ). Bên cạnh đó là một chỗ cho dấu chấm và một chữ số trước dấu chấm. Tổng số chỗ bắt buộc phải có là 6. Số còn lại trong quy cách viết này là n - 6 chỗ được dành cho các chữ số sau dấu chấm, còn gọi là các chữ số có nghĩa.

Ví dụ:

VR = 123. 123456 Writeln ( FileVar, VR : 8 ) ; cho ra 1.23E + 02

+ Write( FileVar, VR : n : m ) ; máy sẽ bố trí n chỗ cho số thực trong đó có m chỗ giành cho phần thập phân ( m chữ số sau dấu chấm ) và căn lề bên phải. Nếu m = 0, máy sẽ chỉ đưa ra phần nguyên của VR.

Ví dụ : VR = 123.123456Write ( FileVar, VR : 10 : 2 ) ; cho ra ____123.12

Write ( FileVar, VR : 15 : 9 ) ; cho ra __123.123456000

59

Page 60: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

_ Nếu VC là một kí tự ( Char ) + Write ( FileVar, VC : n ) ; cho ra giá trị của VC với n chỗ được căn lề bên phải. Nếu n > 1, máy sẽ cho ra thêm n - 1 dấu cách vào trước kí tự VC

Ví dụ :CH = 'H' ; Write ( FileVar, VC : 1 ) ; cho ra HWrite ( FileVar, VC : 2 ) ; cho ra _H

_ Nếu VS là một biểu thức kí tự hoặc String + Write ( FileVar, VS : n ) ; cho ra giá trị của VS với n chỗ được căn lề bên phải. Nếu n < độ dài của String thì máy sẽ cắt bớt các chữ cuối của String đi.

Ví dụ : Write ( FileVar, 'Hello' : 1 ) ; cho ra HWrite ( FileVar, 'Hello' : 3 ) ; cho ra Hel

Write ( FileVar, 'Hello' : 10 ) ; cho ra _____Hello

Ví dụ tổng hợp : Var Ketqua : Text ; A : Integer ; B : Real ; C : String [ 20 ] ; D : Boolean ; BEGIN A : = 34 ; B : = 3.14 ; C : = ' END. ' ; D := True ; Assign ( Ketqua,' Ketqua.txt ' ) ; Rewrite ( Ketqua ) ; Write ( Ketqua,' Ket qua la : ' ) ; Writeln ( Ketqua, A : 10, B : 10 : 4, C ) ; Writeln ( ' Dong 2 ' : 10, D ) ; Close ( Ketqua ) ; END.

Kết quả hiện ra trong file Ketqua.txt :

Kết qua la : 34 3.1400 END. Dong 2 True

Mặc dù A là một số nguyên nhưng thủ tục Write sẽ tự động chuyển sang dạng kí tự tức là dạng

đọc được. Máy sẽ dành cho A 10 chỗ, vì A chỉ có 2 chữ số nên 8 chỗ còn lại đều là khoảnh trắng. Tương tự B được viết ra trong khuôn khổ 10 chỗ với 4 chỗ dành cho phần thập phân. Còn D là biến Boolean nên máy sẽ tự động in ra các từ 'TRUE' hoặc 'FALSE' tương ứng.

B) ĐỌC DỮ LIỆU TỪ TỆP VĂN BẢN:

60

Page 61: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Chúng ta có thể đọc không những các kí tự từ tệp văn bản mà còn có thể đọc lại các số nguyên, các số thực, Bolean từ tệp văn bản thông qua thủ tục :

Read ( FileVar, Var1, Var2,... VarN ) ; Readln ( FileVAr, Var1, Var2,... VarN ) ;

Readln ( FileVar ) ;

Trong đó Var1, Var2,... VarN là các biến thuộc kiểu Char, String, Integer, Real, Boolean và muốn đọc cho đúng thì trong tệp văn bản các kí tự tương ứng từ vị trí đọc (vị trí cửa sổ) cũng phải diễn tả đúng các kiểu dữ liệu cần đọc trên.

Thủ tục Readln (FileVar, Var1, Var2,... VarN); sẽ đưa cửa sổ tệp sang đầu dòng tiếp theo sau khi đã lần lượt đọc các biến tương ứng.

Thủ tục Readln (FileVar) sẽ đưa cửa sổ tệp sang đầu dòng đầu tiên mà không đọc gì cả.

Hàm chuẩn kiểu Boolean EOLN( F ) sẽ phát hiện ra dấu hết dòng EOLN(End Of Line) của tệp F, tránh sai sót khi đọc quá dòng. Khi EOF = True thì EOLN cũng bằng True.

Việc đọc văn bản có thể chia làm hai loại : + Xử lý văn bản, các kí tự. + Đọc dữ liệu số nguyên, số thực từ tệp văn bản.

Ví dụ về xử lý văn bản : Hãy lập một chương trình đếm số chữ trong một tệp văn bản F.

Program DEM_CHU ; Var F : Text ; Ch : Char ; I : Integer ; FileName : String [ 30 ] ; BEGIN Write ( ' Ten tep : ' ) ; Readln ( FileName ) ; Assign ( F, FileName ) ; Reset ( F ) ; I : = 0 ; (* I : Biến đếm *) While Not Eof ( F ) Do Begin While Not Eoln ( F ) Do Begin Read ( F, Ch ) ; I := I +1 ; End ; Readln ( F ) ; End ; Writeln (' So chu la : ', I ) ; Close ( F ) ; END.

* Khi đọc dữ liệu số nguyên, số thực từ tệp văn bản, thủ tục Read và Readln sẽ tự động biến đổi một xâu kí tự thích hợp trong tệp văn bản sang các số nguyên và số thực. Dấu cách được xem là dấu ngăn cách giữa các số.

61

Page 62: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Ví dụ: với I là số nguyên và J là số thực thì để đọc giá trị của I, J từ tệp F, ta dùng lệnh : Read ( F, I, J ) ;

* Thủ tục Seek, hàm FileSize, FilePos không áp dụng cho tệp văn bản vì Text được tính theo đơn vị là dòng (kí tự) với độ dài dòng thay đổi, chúng ta không thể tính toán vị trí đặt con trỏ. Tuy nhiên, Turbo Pascal có hai hàm xử lý Text :

SeekEoln ( FileVar ) :

Hàm kiểu Boolean, tương tự như hàm Eoln song trước khi thử Eoln nó nhảy qua các dấu cách Space và Tab.

SeekEof ( FileVar ) :

Hàm kiểu Boolean, tương tự như hàm Eof song trước khi thử Eof nó nhảy qua các dấu cách Space, Tab và các dấu cách dòng.

Như vậy thủ tục Read và Readln đối với tệp văn bản có thể đọc được nhiều kiểu biến khác nhau ghi trong tệp văn bản ( Integer, Real, Boolean, Char, String ).

Ví dụ ứng dụng : Giả sử rằng chúng ta cần lưu trữ và xử lý các tham số là nhiệt độ (số nguyên), áp suất (số thực), độ

ẩm (số nguyên) của nhiều ngày trong tháng (cần ghi rõ cả ngày). Sau đó các dữ liệu này được xử lý bằng một chương trình độc lập khác. Bạn có thể tạo ra một tệp văn bản chứa các dữ liệu với các quy định như sau :

_ Dòng 1 chứa tên _ Dòng 2 chứa đường gạch nét cho đẹp và rõ ràng. _ Từ dòng 3 trở đi cho hết tệp : chứa dữ liệu với thứ tự : ngày của tháng, nhiệt độ, áp suất, độ ẩm.

Chúng ta có thể tổ chức dữ liệu thành tệp các Record như sau :

Type Du_lieu = Record Ngay : byte; Nhietdo : Integer ; ApSuat : Real ; DoAm : Integer ; End ; Var F : File Of Du_lieu ;

Nhược điểm của phương pháp cất dữ liệu dưới dạng văn bản là số ô nhớ chiếm nhiều hơn. Ví dụ khi NhietDo là 1656, nếu dùng mã Integer thì luôn luôn mất 2 byte, nếu dùng mã kí tự thì mất 4 byte chứa các kí tự '1' '6' '5' '6'. Song nhược điểm này chỉ là phụ. Tuy nhiên chúng ta nên dùng tệp văn bản để xử lý. Ưu điểm của việc dùng tệp văn bản chứa dữ liệu là ta có thể dùng các chương trình soạn thảo văn bản ( các Editor như Editor của Turbo Pascal ) và sau đó có thể xem bằng mắt, sửa, cập nhật các dữ liệu một cách dễ dàng. Chắc bạn sẽ thắc mắc thêm : tại sao không đưa dữ liệu vào qua bàn phím lúc chạy chương trình ? Nếu làm như vậy bạn sẽ không mất chỗ trên đĩa từ song có hai nhược điểm lớn sau : nếu số liệu gõ vào sai thì bạn không sửa lại được nữa và nếu chương trình có sai sót nào đó thì bạn sẽ phải sửa chương trình và cho chạy lại chương trình với việc nhập dữ liệu mới ( qua bàn phím ). Điều này thực sự mất rất nhiều thời gian nếu số liệu có nhiều.

62

Page 63: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Sau khi quy định cách viết văn bản chứa dữ liệu, chúng ta phải tuân thủ quy định về dòng để đọc lại dữ liệu khi cần xử lý. Các dữ liệu trong một dòng cách nhau bằng dấu cách (Space) với số lượng khônh hạn chế, chủ yếu là do cách trình bày. Giả sử tệp văn bản có tên là Thang6.dat được tạo ra với nội dung như sau :

Dòng 1 THOI TIET THANG 6 NAM 2002Dòng 2 .......................................................Dòng 3 1 30 298.5 45Dòng 4 2 35 100.8 24 ............. .......................................................

Chương trình dưới đây sẽ đọc lại các dữ liệu của từng ngày để xử lý, với giả thiết 2 dòng đầu (các dòng không chứa dữ liệu chắc chắn tồn tại nên chương trình sẽ không kiểm tra EOLN trước khi đọc). Sau đó chương trình sẽ lần lượt đọc từng dòng số liệu. Với giả thiết số dòng chứa số liệu cũng không biết trước nên ta dùng vòng While. Sau khi xử lý số liệu, chúng ta có thể thông báo số ngày (tương ứng với số dòng chứa số liệu).

Program DOC_DU_LIEU ; Var F : Text ; NhietDo, DoAm : Integer ; Ngay : Byte ; ApSuat : Real ; SoNgay : Byte ; BEGIN Assign ( F, ' Thang6.dat ' ) ; Reset ( F ) ; Readln ( F ) ; (* nhảy qua dòng 1 *) Readln ( F ) ; (* nhảy qua dòng 2 *) SoNgay := 0 ; While Not SeekEoln ( F ) Do Begin (* Đọc số liệu từng ngày một *) Readln ( F, Ngay, NhietDo, ApSuat, DoAm ) ; SoNgay := SoNgay + 1 ; (* Xử lý dữ liệu tùy theo yêu cầu của bài toán *) ... End ; Writeln ( ' Ket qua xu ly cua ', SoNgay,' ngay la : ' ) ; ... Close ( F ) ; END.

Một tệp văn bản có thể nạp vào bộ nhớ trong để xử lý cho nhanh dưới dạng một mảng (Array) các String. Tất nhiên trước khi khai báo mảng chúng ta phải dự phòng xem tệp văn bản có nhiều nhất bao nhiêu dòng (700 trong ví dụ dưới đây), và mỗi dòng sẽ có nhiều nhất bao nhiêu ký tự. Việc khai báo với kích thước dự phòng này sẽ rất phí ô nhớ, nếu không dùng hết. Sau đó mọi xử lý văn bản có thể được xử lý không phải trên tệp nữa mà là trên mảng ô nhớ như đếm số chữ, đếm số từ... Cuối cùng là cất mảng văn bản vào tệp ban đầu nếu muốn.

Var 63

Page 64: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

VanBan : Array [1.. 700] Of String [80] ; F :Text ; I, SoDong : Integer ; Name : String [30] ; BEGIN (* Đọc tệp văn bản vào mảng *) Name := 'Vidu.txt' ; Assign ( F, Name ) ; Reset ( F ) ; I := 1 ; While Not Eof ( F ) Do Begin Readln ( F, VanBan [ I ] ) ; (* Đọc một dòng vào một chuỗi *) I := I + 1 ; End; SoDong := I - 1 ; Close ( F ) ; (* Xử lý văn bản trên mảng VanBan *) ... (* Cất lại vào tệp nếu muốn. Xin giành cho bạn đọc *) ...END.

Lưu ý : số dòng và số chữ của một dòng trong khai báo VanBan ở trên bị hạn chế vì trên máy tính, bộ nhớ cho khai báo các biến bị chặn trên là 64 KB. Muốn mở rộng, bạn cầ tham khảo biến động và con trỏ ở chương sau.

Việc xử lý các dữ liệu ít khi làm thẳng với tệp (không chỉ là tệp văn bản mà cả với tệp kiểu khác nữa) do tốc độ ghi / đọc của đĩa từ chậm hơn tốc độ ghi/ đọc của bộ nhớ trong. Người lập trình nên tổ chức các cấu trúc dữ liệu khác ( mảng, tập... ) là các kiểu dữ liệu nằm trong bộ nhớ trong của máy.

C) KIỂM TRA TỆP KHI MỞ:

Nhiều vấn đề còn nảy sinh ra khi làm việc với tệp như: khi dùng Reset( F ) liệu tệp F đã tồm tại chưa, khi ghi vào tệp F thì liệu trên đĩa có còn đủ chỗ chứa thêm dữ liệu mới của F hay không ? Turbo Pascal cung cấp lời hướng dẫn ( directive ) cho chương trình dịch để đóng/mơû ( bật/tắt ) việc kiểm tra lỗi sai trong quá trình vào ra tệp :

{$I+} mở việc kiểm tra. Khi gặp lỗi vào/ra chương trình sẽ báo lỗi và dừng lại. Đây là chế độ ngầm định (by default), nghĩa là chương trình dịch luôn luôn thực hiện chế độ nếu không được báo rõ.

{$I+} không kiểm tra lỗi vào/ra, chương trình không dừng lại nhưng sẽ treo tất cả các thủ tục vào/ra khác cho đến khi có lời gọi hàm kết quả IOResult (hàm có sẵn của Turbo Pascal, có kiểu là Integer). Khi có lời gọi hàm IOResult thì điều kiện sai bị xóa bỏ và các thủ tục vào/ra khác có thể tiếp tục hoạt động trở lại. Lúc này nhiệm vụ xử lý lỗi là của người lập trình. Hàm IOResult = 0 nếu mọi việc xảy ra tốt đẹp. Sau đây là một ví dụ nhỏ về kiểm tra vào/ra khi mở file để đọc :

Program OpenInputFile ; Var OK : Boolean ; FileName : String ; F : Text ;

64

Page 65: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

BEGIN Repeat Write ( ' Ten tep : ' ) ; Readln ( FileName ) ; Assign ( F, FileName ) ; {$I-} (* chuyển việc kiểm tra vào / ra cho người dùng *) Reset ( F ) ; OK := IOResult = 0 ; {$I+} (* Sau khi dùng IOResult ta có thể chuyển thành $I+ *) If not OK Then Write (' Khong mo tep voi ten nay duoc ') ; Until OK ; END.

Toàn bộ các lỗi sai khi vào ra được liệt kê trong phần phụ lục dưới dạng một thủ tục IOCheck. Mặt khác bạn cũng cần lưu ý {$I-} và IOResult được dùng không chỉ với thủ tục Reset mà còn với các thủ tục khác như Erase, Rename, Write, Read...

Tệp không định kiểu là một kiểu file đặc biệt, được định nghĩa ra trong Turbo Pascal và nó là một công cụ mạnh để bạn có thể khai thác. Đó là tệp mà khi định nghĩa hay khai báo ra, ta không nói rõ nó chứa gì, không nói rõ bản chất của các dữ liệu được ghi trong đó. Vì vậy việc chuyển dữ liệu từ đĩa vào cấu trúc dữ liệu của bạn sẽ được thực hiện ngay lập tức. Đó là lí do vì sao Tệp không định kiểu được sử dụng rộng rãi trong các ứng dụng đòi hỏi tốc độ cao.

Cách khai báo : tên tệp theo sau từ khóa File.

Ví dụ:Program CopyFile ;Uses Crt ;Var SF, DF : File ; (* SF : Source File Tệp nguồn, DF : Destination File Tệp đích *) Buffer : Array[ 1..1000 ] Of Byte ; I : Integer ; Traloi : Char ;BEGIN ClrScr ; If ParamCount <> 2 Then Begin Writeln ( #7,' Copy File [ From File ] [ To File ] ' ) ; Halt ; End ; Assign ( SF, ParamStr(1) ) ; { $I- } (* Tắt chế độ tự kiểm tra lỗi vào ra *) Reset ( SF, 1 ) ; { $I+ } (* Bật chế độ tự kiểm tra lỗi vào ra *) If IOResult <> 0 Then Begin Writeln ( #7,' Khong co tep ', ParamStr(1) ) ; Halt ; (* Kết thúc chương trình *) End ; Assign ( DF, ParamStr(2) ) ;

65

Page 66: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

{ $I- } (* Tắt chế độ tự kiểm tra lỗi vào ra *) Reset ( SF, 1 ) ; { $I+ } (* Bật chế độ tự kiểm tra lỗi vào ra *) If IOResult = 0 Then Begin Writeln ( #7, ParamStr(2),' Da ton tai tren dia ! ' ) ; Write ( #7,' Co ghi de len khong (Y / N ) : ' ) ; Readln ( Traloi ) ; If ( Upcase ( Traloi ) = 'N' ) Or ( Upcase ( Traloi ) = 'K' ) Then Halt ; (* Kết thúc chương trình *) End ; Rewrite ( DF, 1 ) ; Writeln ('. = 1000 bytes copied ') ; BlockRead ( SF, Buffer, SizeOf( Buffer ), I ) ; While I > 0 Do Begin Write('. ') ; BlockWrite ( DF, Buffer, I ) ; BlockRead ( SF, Buffer, SizeOf( Buffer ), I ) ; End ; Close ( SF ) ; Close ( DF ) ;END.

Giả sử chương trình trên được viết vào file Copy1.pas và được dịch thành Copy1.exe. Để copy từ file File1.dat thành File2.dat, bạn phải gõ :

C:\ Copy1 File1.dat File2.dat ( Lưu ý rằng file Copy1.exe phải có sẵn trong thư mục C:\ )

Turbo Pascal đã định nghĩa sẵn biến ParamCount để đếm số tham số của dòng lệnh trên. Nó sẽ đếm các cụm chữ cách nhau bằng các dấu Space nằm sau tên chương trình, tức là ParamCount bằng 2 vì có hai cụm chữ là File1.dat và File2.dat. Hai cụm chữ này đồng thời được gán cho các biến có sẵn là ParamStr(1) và ParamStr(2) tương ứng. Nghĩa là ParamStr(1) sẽ nhận giá trị là File1.dat còn ParamStr(2) sẽ nhận giá trị là File2.dat.

SD, SF ở đây là hai tệp không định kiểu, vì vậy sau chữ File không có thêm kiểu phần tử của File.Không như các tệp văn bản hay tệp có định kiểu, thủ tục Reset và Rewrite đối với tệp không định

kiểu SF, DF còn có thêm một tham số nữa, đó là kích thước của Record. Ví dụ Reset ( SF, 1 ) có nghĩa là chuẩn bị File để đọc và độ dài của Record là bằng 1 byte. Điều này làm cho ta có cảm giác SF như là Array Of Byte. Còn nếu Reset ( SF, 2 ) thì ta có thể coi SF là Array Of Integer. Nếu chỉ ghi Reset ( SF ) thì máy sẽ coi độ dài Record là 128 byte.

Việc ghi và đọc đối với tệp không định kiểu còn dùng đến 2 thủ tục là BlockRead và BlockWrite.

Ví dụ :BlockRead ( SF, Buffer, SizeOf( Buffer ), I ) ;

Thủ tục dùng với 4 tham số : _ Tham số thứ nhất : biến file SF. _ Tham số thứ hai : nơi dữ liệu được đọc vào là Buffer. Để điền hết dữ liệu vào nơi đọc, cần đưa tham số thứ ba là kích thước của Buffer, bằng 1000 trong trường hợp khai báo Buffer ở đây. Tuy nhiên, Turbo Pascal đã cung cấp cho bạn hàm

66

Page 67: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

SizeOf để lấy kích thước của mọi biến. Cách viết như thế này có cái lợi là mỗi khi bạn cần thay đổi độ dài của Buffer thì chỉ cần thay đổi trong phàn khai báo mà không phải thay nó trong mọi thủ tục BlockRead và BlockWrite. Tham só cuối cùng là biến I, kiểu Integer, được dùng để nhận biết có bao nhiêu Record đã được đọc từ đĩa vào Buffer. Nhiều khi file trên đĩa đã hết dữ liệu, không đủ điền hết Buffer. Tham số thứ tư này có giá trị bằng 0 báo rằng hết dữ liệu để đọc.Thủ tục BlockWrite hoạt động tương nhưng chỉ cần 3 tham số. Tham số thứ ba là số Record thực

sự cần ghi vào đĩa chứ không phải là kích thước của Buffer. Đó là giá trị được ghi trong biến I.

Trong ngôn ngữ Pascal, thủ tục chuẩn New được dùng để tạo ra một biến động. Tham số duy nhất cần cho New là biến con trỏ ( kí hiệu là PointerVar ) trỏ tới biến động mà chúng ta muốn lập ra.

New ( PointerVar )

Ví du : Để tạo ra biến động P^ do con trỏ P trỏ tới, ta viết :

New(P) ;

Như vậy New(P) sẽ sắp xếp bộ nhớ cho một biến động có kiểu là Nhan_su.Nếu trong một chương trình ta dùng n lần New(P) liên tục thì cuối cùng ta có n biến độâng kiểu

Nhan_su song con trỏ P sẽ chỉ trỏ vào biến động được tạo ra lần cuối cùng. Ví dụ nếu trong chương trình ta viết hai lần như sau :

New ( P ) ; (* Tạo ra biến động có địa chỉ trong P *)With P^ Do (* Câu lệnh With được phép dùng với biến động *) Begin Ten := ' Mot ' ; Tuoi := 1 ; End ;New ( P ) ;P^. Ten := ' Hai ' ;P^. Tuoi := 2 ;

Như vậy ta đã tạo ra được hai biến động kiểu Nhan_su, song sau lần gọi New(P) lần hai, biến động đầu tiên mặc dù vẫn còn nằm trong ô nhớ của nó nhưng con trỏ P không chứa địa chỉ của nó nữa mà P sẽ trỏ vào biến động vừa được tạo ra (' Hai ', 2).

Nói tóm lại, sau mỗi lần dùng New(P) thì con trỏ P sẽ chứa địa chỉ của biến động P^ vừa được tạo ra, còn các biến động được tạo ra bằng New(P) trước đây sẽ không được P trỏ vào nữa. Muốn truy cập vào các biến động được tạo ra trước đấy, ta phải có các biện pháp lưu trữ địa chỉ của chúng lại ( ta sẽ xét đến ở bài sau ).

Trong ngôn ngữ Pascal, thủ tục chuẩn New được dùng để tạo ra một biến động. Tham số duy nhất cần cho New là biến con trỏ ( kí hiệu là PointerVar ) trỏ tới biến động mà chúng ta muốn lập ra.

New ( PointerVar )

Ví dụ: Để tạo ra biến động P^ do con trỏ P trỏ tới, ta viết :

New ( P ) ;67

Page 68: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Như vậy New ( P ) sẽ sắp xếp bộ nhớ cho một biến động có kiểu là Nhan_su.Nếu trong một chương trình ta dùng n lần New ( P ) liên tục thì cuối cùng ta có n biến độâng

kiểu Nhan_su song con trỏ P sẽ chỉ trỏ vào biến động được tạo ra lần cuối cùng. Ví dụ nếu trong chương trình ta viết hai lần như sau :

New ( P ) ; (* Tạo ra biến động có địa chỉ trong P *)With P^ Do (* Câu lệnh With được phép dùng với biến động *) Begin Ten := ' Mot ' ; Tuoi := 1 ; End ;New ( P ) ;P^. Ten := ' Hai ' ;P^. Tuoi := 2 ;

Như vậy ta đã tạo ra được hai biến động kiểu Nhan_su, song sau lần gọi New ( P ) lần hai, biến động đầu tiên mặc dù vẫn còn nằm trong ô nhớ của nó nhưng con trỏ P không chứa địa chỉ của nó nữa mà P sẽ trỏ vào biến động vừa được tạo ra (' Hai ', 2). Nói tóm lại, sau mỗi lần dùng New ( P ) thì con trỏ P sẽ chứa địa chỉ của biến động P^ vừa được tạo ra, còn các biến động được tạo ra bằng New ( P ) trước đây sẽ không được P trỏ vào nữa. Muốn truy cập vào các biến động được tạo ra trước đấy, ta phải có các biện pháp lưu trữ địa chỉ của chúng lại (ta sẽ xét đến ở bài sau).

Một điều lý thú là khi một biến động không được dùng tới nữa ở trong chương trình, ta có thể thu hồi ô nhớ nó chiếm để dùng vào việc khác nhờ có có chương trình con Dispose. Tham số duy nhất cần cho thủ tục Dispose là biến con trỏ PointerVar trỏ vào biến động cần giải phóng. Có thể nói Dispose là thủ tục ngược lại với New.

Dispose ( PointerVar ) ;

Ví dụ : Dispose(P); sẽ giải phóng ô nhớ của biến động P^.Bên cạnh Dispose được dùng để giải phóng ô nhớ của một biến động, Pascal còn được trang bị

một cặp thủ tục :

Mark(PVar) để đánh dấu và Release(PVar) để giải phóng cả một vùng ô nhớ của nhiều biến động khác nhau.

Mark(PVar) sẽ gán giá trị của con trỏ của Heap ( bộ nhớ cấp phát động ) cho một biến con trỏ PVar nào đó. PVar này được dùng như là để đánh dấu vị trí đầu của vùng ô nhớ cần giải phóng sau này. Sau lệnh Mark, ta có thể dùng một loạt thủ tục New để tạo các biến động khác nhau và chúng sẽ chiếm ô nhớ kể từ vị trí đã được đánh dấu. Sau đó, nếu ta muốn lấy lại toàn bộ vùng biến động đã được đánh dấu, ta chỉ việc dùng Release(PVar). Tất nhiên sau khi dùng Release, ta không còn có thể sử dụng các biến động nằm trong vùng vừa được giải phóng.

Sau đây là ví dụ về việc sử dụng Dispose:

Type Tp = ^Mang ; (* Array *) Mang = Array[ 1.. 100 ] Of Integer ;

68

Page 69: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Var P, Q : Tp ;BEGIN ....... New ( P ) ; (* Tạo ra một biến động *) New ( Q ) ; (* Tạo ra một biến động *) ....... Dispose ( P ) ; (* Giải phóng ô nhớ của biến động P^ *) Dispose ( Q ) ; (* Giải phóng ô nhớ của biến động Q^ *) ....... New ( P ) (* Tạo ra biến động mới *) ....... Dispose ( P ) ; (* Giải phóng ô nhớ của biến động P^ *)END.

Tiếp theo là ví dụ về việc sử dụng Mak và Release:

Var P, Q, R, PMark : Tp ;BEGIN ....... New ( R ) ; (* Tạo một biến động R^ *) Mark ( PMark ) ; New ( P ) ; (* Tạo một biến động P^ *) ....... New ( Q ) ; (* Tạo một biến động Q^ *) ....... Release ( PMark ); (* Giải phóng ô nhớ của 2 biến P^ và Q^ *) (* Lưu ý : Biến động R vẫn còn giá trị *) New ( P ) ; (* Tạo ra biến động mới *) ....... Dispose ( P ) ; (* Giải phómg ô nhớ của P^ *)END.

Riêng đối với kiểu Record có cấu trúc biến đổi, các tham số cho các thủ tục Dispose còn thêm giá trị của trường đánh dấu. Ví dụ nếu :

New ( PointerVar, Nghe_nghiep ) ;

như ở trên thì ta phải ghi :

Dispose ( PointerVar, Nghe_nghiep ) ;

Con trỏ và biến động được sử dụng rộng rãi để tạo ra các cấu trúc dữ liệu động và là một vấn đề hết sức lý thú nếu ta hiểu thấu đáo bản chất của nó. Chúng ta sẽ được đieều này thông qua các ví dụ được trình bày ở bài sau. Tuy nhiên phải nói rằng lập trình với biến con trỏ và biến động khó hơn và trừu tượng hơn.

Các biến động do New tạo ra được Pascal xếp vào một vùng ô nhớ tự do theo kiểu xếp chồng và được gọi là Heap ( bô nho cap phát dông ). Ngôn ngữ Pascal quản lý Heap thông qua một

69

Page 70: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

con trỏ của Heap là HeapPtr. Con trỏ của Heap luôn luôn trỏ vào ô nhớ tự do đầu tiên của vùng ô nhớ tự do của Heap. Mỗi lần gọi New, con trỏ của Heap được dịch chuyển về phía đỉnh của vùng ô nhớ tự do một số byte tương ứng với kích thước của biến động mới được tạo ra.

Ngược lại, mỗi khi giải phóng bộ nhớ biến động, bộ nhớ biến động được thu hồi. Tuy nhiên nếu việc tạo và thu hồi không phải là quá trình liên tục và kế cận thì bản thân của vùng nhớ Heap cũng bị chia nát ra. Nghĩa là có thể có những vùng thu hồi nằm lọt trong vùng các biến động khác vẫn còn đang hoạt động. Turbo Pascal không có cơ chế dồn các biến động đang được sử dụng để gom về những vùng ô nhớ tự do.

Thí dụ khi bạn gọi :

New ( P ) ;New ( Q ) ;New ( R ) :Dispose ( Q ) ;

Nghĩa là có 3 vùng nhớ kế cận nhau dành cho các biến động P^, Q^ và R^. Song đột nhiên vùng nhớ Q^ bị đòi lại làm cho xuất hiện một lỗ thủng do biến Q^ tạo ra. Turbo Pascal vẫn có cơ chế để quản lý vùng nhớ vừa giải phóng để cho các biến động mới được tạo ra có thể được xếp vào những lổ hổng đó nếu vừa kích thước ( bé hơn hoặc bằng ).

Một điều bạn quan tâm là khi tạo biến động, liệu máy có cần bộ nhớ cho nó không. Turbo Pascal cung cấp hai hàm : MemAvail và MaxAvail. Hàm MemAvail giúp bạn xác định kích thước của tất cả các vùng nhớ cấp cho biến động còn tự do, nghĩa là tổng tất cả các khối nhớ tự do, bao gồm cả các khối nhớ lổ hổng nằm xen kẽ nhau trong Heap. Hàm MaxAvail thì báo cho biết kích thước của khối nhớ Heap tự do lớn nhất. Mỗi khi bạn tạo biến động mới, máy luôn luôn cần biết liệu có còn một khối nhớ tự do nào đủ để " nhét " biến mới vào không. Hãy xem thí dụ dưới đây về cách dùng hai hàm này :

Program Get_Heap_Space ;Uses Crt ;Var Tong_Heap, Khoi_lon_nhat : LongInt ;BEGIN Tong_Heap := MemAvail ; Khoi_lon_nhat := MaxAvail ; Writeln (' Tong cac vung tu do cua Heap la ', Tong_Heap,' bytes ') ; Writeln (' Khoi Heap tu do lon nhat la ', Khoi_lon_nhat,' bytes ') ;END.

Kết quả sẽ tùy vào máy của người sử dụng :

Tong cac vung tu do cua Heap la 10200 bytes.Khoi Heap tu do lon nhat la 600 bytes.

Mỗi khi tạo biến động mới bạn cũng nên kiểm tra xem máy có đủ bộ nhớ cấp cho nó không. Hãy sử

dụng hàm SizeOf để xác định kích thước biến nhớ bạn cần tạo ra :

Ví dụ:

Program Check_Heap_Space ;Uses Crt ;Type

70

Page 71: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

RecPtrType = ^RecordType ; RecordType = Record ID : String[ 5 ] ; (* Số CMND *) Ten : String[ 20 ] ; Tuoi : Byte ; End ;Var Ptr : RecPtrType ;BEGIN Ptr := Nil ; Writeln (' Kich thuoc cua ban ghi la ', SizeOf( RecordType ),' bytes ' ) ; Writeln (' Tong cac vung tu do cua Heap la ', MemAvail,' bytes ') ; Writeln (' Khoi Heap tu do lon nhat la ', MaxAvail,' bytes ') ; If MaxAvail < SizeOf( RecPtrType ) Then Writeln (' Khong du bo nho !') ; Else New ( RecPtr ) ; ... Dispose ( RecPtr ) ; RecPtr := Nil ;END.

Khi ta muốn lập một danh sách, ví dụ danh sách Nhan_su, mà biết trước được số người thì ta có thể sử dụng cấu trúc dữ liệu kiểu mảng cho công việc lập trình được đơn giản. Song nhiều khi số phần tử của danh sách lại không được biết trước nên nếu ta sử dụng các mảng thì bao giờ ta cũng phải cho số chiều cực đại có thể dùng tới để khai báo mảng. Đương nhiên khi đó nếu chúng ta dùng không hết thì phí ô nhớ đang thiếu cho việc khác. Nếu chúng ta sử dụng biến động thì cần đến đâu chúng ta sẽ tạo ra đến đấy, tất nhiên lúc này bị chỉ hạn chế bởi kích thước của bộ nhớ trong của máy. Mặt khác nhiều khi ô nhớ bị hạn chế, cho nên ta không thể đồng thời sử dụng nhiều biến tĩnh cùng một lúc(phạm vi ô nhớ dành cho tất cả biến tĩnh trên máy vi tính họ IBM là 64 KB). Một trong các biện pháp khắc phục là dùng biến con trỏ để xây dựng một danh sách các phần tử được móc nối với nhau.

1. Tạo danh sách được ghép nối:

Type PointerN = ^Nhan_su ; Nhan_su = Record Ten : String[ 30 ] ; Tuoi : Integer ; Next : PointerN ; (* Để trỏ vào phần tử bên cạnh *) End ;Var Last, Ptr, P, Q : PointerN ; HeapTop : ^Integer ; (* Con trỏ đánh dấu của Mark *) Name : String[ 30 ] ;BEGIN (* Đọc danh sách vào cho đến khi ấn Return : Name = ' ' *) Last := Nil ; Mark(HeapTop); (* Đánh dấu vị trí *) Repeat

71

Page 72: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Writeln ; Write (' Ho va ten : ') ; Readln(Name); If Name <> ' ' Then Begin New(Ptr); Ptr^.Ten := Name ; Write (' Tuoi : ') ; Readln(Ptr^.Tuoi); Ptr^.Next := Last ; Last := Ptr ; End ; Until Name = ' ' ; (* Đọc lại toàn bộ danh sách *) ; Writeln (' DANH SACH NGUOI : ') ; Ptr := Last ; (* Ptr trỏ vào người cuối cùng trong danh sách *) ; While Ptr <> Nil Do Begin Writeln (' Ho va ten : ', Ptr^.Ten); Writeln (' Tuoi : ', Ptr^.Tuoi); Writeln ; Ptr := Ptr^.Next ; (* Ptr trỏ vào người bên cạnh *) ; End ; Release(HeapTop);END.

HeapTop là biến con trỏ được dùng để đánh dấu vị trí trong các thủ tục Mark và Release. Vì vậy ta chỉ cần định nghĩa sao cho HeapTop là con trỏ, còn trỏ vào kiểu nào thì ta không cần quan tâm

Hoàn toàn có thể được khi ta định nghĩa :

HeapTip : ^Byte ;hoặc HeapTop : ^Nhan_su ;

Last là biến con trỏ luôn luôn trỏ vào phần tử cuối cùng của danh sách (ở đây phần tử là một bản

ghi kiểu Nhan_su). Khi mới vào chương trình, Last được gán gí trị Nil để báo rằng danh sách chưa có ai cả.

Name là một biến trung gian để đọc tên và làm phép thử kết thúc việc vào dữ liệu bằng cách ấn Return khi máy hỏi Ho va ten. Việc vào dữ liệu là một vòng lặp không bị hạn chế số lượng trước nhờ có vòng lặp Repeat.

Nếu Name <> ' ', tức là có thêm một người cần đưa vào danh sách, thủ tục New(Ptr) sẽ tạo ra một biến động. Việc gán tên và đọc tuổi không có gì mới lạ cả. Riêng có một điều là biến động này có một trường là biến con trỏ (Next) và ta muốn rằng trường Next của phần tử mới được tạo ra sẽ luôn luôn trỏ vào phần tử được tạo ra trước nó, việc này được thực hiện nhờ dòng lệnh :

Ptr^.Next := Last ;

Sau mỗi lần dùng thủ tục New(Ptr) thì Ptr lại không trỏ vào các biến động được tạo ra trước đây, tuy nhiên ta không bị mật địa chỉ của chúng nhờ có trường con trỏ Next của Ptr giữ lại. Như vậy các phần tử của danh sách được ghép nối với nhau nên ta gọi đây là danh sách được ghép nối. Dòng lệnh Last := Ptr ; sẽ làm cho Last trỏ vào phần tử cuối cùng của danh sách mà lúc nào Ptr cũng trỏ vào.

Đoạn tiếp theo của chương trình trong ví dụ trên là đọc lại danh sách đã có. Việc đọc danh sách được bắt đầu tiến hành từ phần tử vào cuối cùng. Phần tử này được con trỏ Last trỏ vào. Còn Ptr là

72

Page 73: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

biến con trỏ được sử dụng như là một biến trung gian để nháp, nghĩa là có thể dùng nó làm các việc khác nữa.Việc đọc biến tiến hành qua vòng lặp While để kiểm tra xem Ptr còn trỏ vào phần tử nào không, nếu có thì đọc. Sau khi đọc xong một phần tử, ta phải chuyển sang một phần tử trước đấy bằng dòng lệnh :

Ptr := Ptr^.Next ; (* Ptr trỏ vào người bên cạnh *)

Cuối cùng câu lệnh Release(HeapTop) sẽ giải phóng hết các ô nhớ.

2. Xen vào:Bây giờ ta xét thêm một thao tác nữa với danh sách được ghép nối : xen một phần tử vào một chỗ

mong muốn. Ví dụ xen vào trước phần tử có tên là Hai. Giả thiết rằng ta vẫn dùng các mô tả ở trên và Last là con trỏ trỏ vào phần tử cuối cùng như đã trình bày.

(* To phần tử mới để xen vào *) New(Q);Q^.Ten := ' Ba ' ;Q^.Tuoi := 3 ;(* Tìm vị trí cần xen *) ;Ptr := Last ;While(Ptr <> Nil)and(Ptr.Ten <> ' Hai ') Do Ptr := Ptr^.Next ;(* Ghép nối vào chổ cần thiết *) ;Q.Next := Ptr^.Next ;Ptr^.Next := Q ;

3. Tháo đi:Trái ngược với thao tác xen vào là một phần tử ra khỏi danh sách. Ví dụ tháo đi phần tử có tên là

Ba. Khi này ta phải dùng Q ngay trong lúc tìm kiếm. Khi tìm xong rồi ta phải tháo trong hai trường hợp khác nhau:

(* Tìm kiếm phần tử cần tháo *) P := Last ;While(P <> Nil)and(P^.Ten <> ' Ba ') DoBegin Q := P ; P := P^.Next ;End ;(* Tháo đi *)If P = Last Then Last := P^.Next ;Else Q^.Next := P^.Next ;

4. Chương trình con dùng biến con trỏ :

Biến con trỏ cũng có thể được đưa vào như là tham số của chương trình con. Ví dụ ta có thể lập mốt chương trình con Xen như sau :

Procedure Xen(Var Q : PointerN);Begin ...End ;

73

Page 74: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Nhu ta đã biết, giá trị kết quả của một Function là kiểu vô hướng. Tuy nhiên ta cũng có thể làm chương trình con kiểu Function có kết quả được mô tả kiểu con trỏ. Ví dụ chương trình con sau được dùng để đảo các con trỏ của một danh sách được ghép nối. Tham số của nó là con trỏ trỏ vào phần tử nằm cuối danh sách, tức là trỏ vào phần tử cuối cùng.

Function Dao(Cuoi : Pointern): PointerN ;Var P1, P2 : PointerN ;Begin P1 := Cuoi ; Cuoi := Nil ; Repeat P2 := P1^.Next ; P1^.Next := Cuoi ; Cuoi := P1 ; P1 := P2 ; Until P1 = Nil ; Dao := Cuoi ;End ;

Như tên gọi của nó, đó là con trỏ trỏ tới vùng ô nhớ không định kiểu dữ liệu. Thí dụ trong lập trình đồ họa, chúng ta cần cấp phát bộ nhớ để chứa hình ảnh mà không cần biết kiểu dữ liệu.

Cách khai báo như sau :

Var Ptr : Pointer ;

Do vậy khôngthể dùng New và Dispose để quản lý con trỏ này cùng vùng nhớ do nó trỏ tới. Để cấp ô nhớ cho biến động Ptr^, ta dùng thủ tục :

GetMem ( Ptr, Kich_thuoc_can_cap ) ;

và để giải phóng nó, ta dùng :

FreeMem ( Ptr, Kich_thuoc_can_cap ) ;Ptr := Nil ;

Ví dụ:

Program XFreeMem ;Var P : ^Real ;BEGIN Writeln (' MemAvail truoc khi goi GetMem : ', MemAvail ) ; GetMem ( P, 10 ) ; (* Cấp phát bộ nhớ *) Writeln (' MemAvail sau khi goi GetMem : ', MemAvail ) ; P^ := Pi ; Writeln (' Gia tri tren Heap ', P^ ) ;

74

Page 75: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Writeln (' MemAvail truoc khi goi FreeMem : ', MemAvail ) ; FreeMem ( P, 10 ) ; (* Giải phóng P^ *) Writeln (' MemAvail sau khi goi FreeMem : ', MemAvail ) ; Readln ;END.

Để xử lýmàn hình văn bản, bàn phím và âm thanh, Turbo Pascal viết sẵn một số thủ tục và hàm có chứa trong Unit Crt.

1. Tọa độ màn hình:Màn hình văn bản thường gặp ở chế độ 80 cột, 25 dòng. Mỗi vị trí trên màn hình xác định bởi tọa

độ cột và tọa độ dòng, chỉ chứa được một trong số 256 kí tự chuẩn của bảg mã ASCII.

Ví dụ : _ Điểm (1, 1) nằm ở vị trí góc trên bên trái nhất của màn hình. _ Điểm (20, 2) nằm ở vị trí cột thứ 20, hàng thứ 2 của màn hình.

2. Một số thủ tục xử lý màn hình:

GotoXY(X, Y : Byte); đưa vị trí con trỏ tới tọa độ (X, Y).

Ví dụ sau sẽ viết ra màn hình dòng chữ " Dong 20, Cot 20 " tại tọa độ (20, 20) :

Uses Crt ;BeginGotoXY(20, 20);Write (' Dong 20, Cot 20 ') ;Readln ;End.

WhereX; WhereY; là 2 thủ tục cho ta biết cột, dòng hiện tại của con trỏ. ClrScr; xóa toàn bộ màn hình và đặt con trỏ vào vị trí góc trên, bên trái(cột 1, hàng 1). Để xóa từ

vị trí con trỏ đến hết dòng(không di chuyển con trỏ), ta dùng ClrEoLn. DelLine; xoá một dòng tại vị trí của con trỏ và mọi dòng ở phía dưới sẽ được dịch lên một dòng. InsLine; chèn thêm một dòng trống vào vị trí của con trỏ trên màn hình.

Window(X1, Y1, X2, Y2); thủ tục để vẽ một cửa sổ trên màn hình có tọa độ : _ Góc trên bên trái là cột X1, hàng Y1. _ Góc dưới bên phải là cột X2, hàng Y2.

Bây giờ, ta nhập chương trình sau đây vào máy để xem màu của Pascal nhảy nhót tung tăng trên màn hình.

Uses Crt ;Var X, Y : Byte ;BEGIN TextBackground(Black); (* Xóa màn hình *) ClrScr ; Repeat

75

Page 76: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

X := Succ(Random(80)); (* Vẽ các cửa sổ ngẫu nhiên *) Y := Succ(Random(25)); Window(X, Y, X + Random(10), Y + Random(8)); TextBackground(Random(16)); (* Tạo màu ngẫu nhiên *) ClrScr ; Until KeyPressed ;END.

Trên màn hình màu, mỗi ô chữ có hai loại màu là màu chữ và màu nền. Để thể hiện màu chữ và màu nền, ta dùng 2 thủ tục sau :

TextColor ( Color : Byte ); thủ tục này đặt màu cho chữ, số và các kí hiệu khác.TextBackground ( Color : Byte ); là thủ tục đặt màu nền.Màu của 2 thủ tục này có thể viết nguyên từ tiếng Anh chỉ màu đó, hoặc viết bằng số nguyên thể

hiện màu đó theo bảng dưới đây :

Màu Giá trịBlackBlueGreenCyanRedMagentaBrownLightGrayDarkGrayLightBlueLightGreenLightCyanLightRedLightMangentaYellowWhite

ĐenXanhXanh lá câyXanh cẩm thạchĐỏTíaNâuXám nhẹXám đậmXanh nhạtXanh lá cây nhạtXanh cẩm thạch nhạtHồngTía nhạtVàngTrắng

0123456789101112131415

* Để thể hiện một màu nào đó, ta có thể sử dụng một trong hai cách :TextColor ( Yellow ) ;

hoặc TextColor ( 14 ) ;Những màu văn bản được biểu diễn bằng các số giữa khoảng 0 tới 15, để nhận dạng một cách dễ

dàng, bạn có thể dùng tên các màu này thay cho việc dùng số rất khó nhớ. Trong các chế độ văn bản màu, màu kí tự được chọn là 16 màu, còn màu nền là 8 màu.

* Mầu kí tự có thể cho nhấp nháy bằng cách cộng với hằng Blink, có giá trị là 128.Sau đây là một ví dụ đầy đủ về cách sử dụng màu nền và màu chữ, bạn hãy chạy thử để biết được

khả năng thể hiện màu sắc của Turbo Pascal.

Uses Crt ;BEGIN ClrScr ; (* Kí tự màu xanh lá cây và nền đen *) TextColor ( Green ) ; TextBackground ( Black ) ; WriteLn (' Hey there ! ') ;

76

Page 77: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

(* Kí tự màu đỏ nhạt và sáng lấp láy *) (* Nền xám nhạt *) TextColor ( LightRed + Blink ) ; TextBackground ( LightGray ) ; WriteLn (' Hi there ! ') ; (* Kí tự có màu vàng, nền xanh dương *) TextColor ( 14 ) ; (* Yellow = 14 *) TextBackground ( Blue ) ; Writeln (' Ho there ! ') ; NormVideo ; (* Chế độ sáng thông thường *) WriteLn (' Back to normal... ') ; Readln ;END.

Trong ví dụ trên, bạn thấy có một thủ tục lạ là NormVideo. Đây là thủ tục xác định chế độ màn hình :

LowVideo; bắt đầu chế độ sáng thấp. Sau khi gọi thực hiện thủ tục này thì mọi dữ liệu xuất ra trên màn hình đều có màu với độ sáng thấp.

HighVideo; bắt đầu chế độ sáng cao, các dữ liệu xuất ra trên màn hình sẽ có màu sáng chói hơn. NormVideo; bắt đầu chế độ sáng thông thường sau khi gọi thực hiện.

Để xử lý bàn phím, Turbo Pascal cung cấp cho bạn hai hàm cơ bản :

KeyPressed : Boolean; là hàm trả lại giá trị True nếu một phím được ấn và False nếu không có. Tuy nhiên, hàm KeyPressed không thể xử lý các phím nóng như Shift, Alt, NumLock...

Ví dụ:Uses Crt ;BEGIN(* Điền đầy màn hình bằng kí tự Xxcho đến khi gõ phím *)Repeat Write(' Xx ') ;Until KeyPressed ;END.

ReadKey : Char; đọc kí tự từ bàn phím. Nếu biến KeyPressed là True trước khi gọi tới ReadKey, kí tự được đọc vào ngay lập tức, không chờ ấn Enter. Nếu KeyPressed là False, tức không có một phím nào được ấn, ReadKey sẽ đợi cho đến khi có một phím được ấn và nhận diện phím được ấn đó.

Kí tự được đọc không hiện lên trên màn hình, cho dù các kí tự đó thuộc bảng chữ cái hay là các chữ số từ 0 đến 9.

Khi một phím đặc biệt được ấn, đầu tiên ReadKey trả lại giá trị không ( Nul #0 ), và sau đó trả lại mã quét mở rộng.

Một đoạn chương trình dưới đây đọc kí tự hay mã phím mở rộng vào trong biến Ch và đặt biến Boolean có tên là FuncKey tới giá trị True nếu kí tự là một phím đặc biệt :

Ch := ReadKey ;If Ch <> Then

77

Page 78: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Begin Writeln (' Khong phai phim dac biet ') ; FuncKey := False ;End ElseBegin FuncKey := Key ; Ch := ReadKey ;End ;

Sau đây là một ví dụ ngắn thể hiện cách sử dụng hàm ReadKey :

Uses Crt ;Var Ch: Char ;BEGIN Writeln (' Hien thi cac gia tri ma ki tu ASCII ') ; Writeln (' An Ecs de thoat ') ; Writeln ; Repeat Writeln (' Ki tu ? ') ; Ch := Readkey ; Writeln ( Ch,' : gia tri ma ASCII la ', Ord( Ch ) ); Until Ch = Chr ( 27 ) ;END.

Loa của máy PC (Personal Computer : máy tính cá nhân) làm theo nguyên lý chuyển mạch bật tắt. Trong trường hợp bật sẽ tạo âm thanh ở một tần số nào đó, còn trường hợp chuyển mạch tắt sẽ tắt luôn âm thanh.

Công cụ cơ bản của Turbo Pascal để xử lý loa là các thủ tục Sound, Nosound và Delay. Tất cả các thủ tục này đều là thành phần của unit Crt. Sound nhận một tham biến là tần số của tone cần phát ra. Ví dụ nốt Đô trung có tần số 512 Hertz, trong khi nốt Đô ở quảng tám thấp hơn có tần số 256 Hertz và nốt Đô ở quảng tám cao hơn có tần số 1024 Hertz.

Đi kèm với thủ tục Sound là thủ tục Nosound. Mỗi khi bật tắt loa để phát một tone nào đó, loa sẽ tiếp tục phát tone cho đến khi bạn dùng Nosound. Để ấn định thời khoảng phát tone, bạn dùng thủ tục Delay. Delay nhận một tham biến cho biết thời khoảng trễ (tính bằng mili giây).

Ví dụ sau đây sẽ cho loa phát ra âm thanh có tần số 500 Hertz trong khoảng thời gian 1000 mili giây (1 giây) :

Program Am_thanh ;Uses Crt ;BEGIN Sound ( 500 ) ; Delay ( 1000 ) ; Nosound ;END.

78

Page 79: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Đối với một số ngôn ngữ lập trình hướng đối tượng mạnh như Visual Basic hoặc Visual C++, thì việc quản lý âm thanh như chuyển âm thanh, chuyển nhạc (nhạc MP3, audio) ra Soundcard là không có gì khó. Nhưng đối với Pascal, đó là một công việc phức tạp và mất thời gian.

Ở bài này, tôi chỉ đề cập đến việc tạo hiệu ứng âm thanh trên loa nội bộ của máy PC.

1. Beep (bíp):Tiếng bíp thường dùng để báo lỗi trong các chương trình. Để phát tiếng bíp, bạn dùng tần số xấp

xỉ 150 Hertz trong khoảng thời gian 400 mili giây.

Ví dụ sau đây sẽ phát ra tiếng bip để báo lỗi nếu bạn nhập sai số liệu :

Program Bip ;Uses Crt ;Var MyNum : Integer ;(* ----------------------------------------------------- *)Procedure Beep ;Begin Sound ( 150 ) ; Delay ( 400 ) ; Nosound ;End ;(* ----------------------------------------------------- *)BEGIN Clrscr ; Write (' Cho mot so tu 1 đen 5 : ') ; Readln ( MyNum ) ; If ( MyNum < 1 ) Or ( MyNum > 5 ) Then Begin Beep ; Write (' Ban vao sai roi ! ') ; End Else Write (' So lieu duoc chap nhan ! ') ; Readln ;End.

2. Buzz (tiếng rù rù):Để tạo tiếng rù rù, bạn dùng tần số 100 Hertz và thời khoảng 30 mili giây

Program Ru_ru ;Uses Crt ;Var Counter : Integer ;BEGIN For Counter := 1 To 30 Do Begin Sound ( 100 ) ; Delay ( 30 ) ; Nosound ; Delay ( 30 ) ; End ;

79

Page 80: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

END.

3. Tiếng banh nảy:Để tạo tiếng banh nảy bạn thay đổi giữa 2 tone thấp và cao như quả banh nảy lên rồi lại rơi xuống.

Mỗi lần banh nảy sẽ giảm độ nảy so với lần trước nghĩa là tiếng banh ngày càng gần nhau. Ví dụ sau đây cho thấy điều đó :

Program Ban_nay ;Uses Crt ;Var Hight, Low : Integer ;(* ---------------------------------------------------------- *)Procedure BoucingBall ( Hight, Low : Integer ) ;Var Count : Integer ;Begin Count := 20 ; While Count > 1 Do Begin Sound ( Low - Count * 2 ) ; Delay ( (Count * 500) Div 20 ) ; Nosound ; Sound ( Hight ) ; Delay ( (Count * 500) Div 15 ) ; Nosound ; Delay ( 150 ) ; Count := Count - 2 ; End ;End ;(* ---------------------------------------------------------- *)BEGIN BoucingBall ( 350, 200 ) ;END.

4. Tiếng bỏ bom:Ví dụ sau tạo ra tiếng bỏ bom. Thủ tục BombsAway có 3 tham biến Hight, Low, Altitude. Tham

biến Hight, Low cho tần số cao và thấp, tham biến Altitude kiểm soát thời khoảng của tone :

Program Bo_bom ;Uses Crt ;Var Hight, Low, Altitude : Integer ;(* ------------------------------------------------------------ *) Procedure BombsAway ( Hight, Low, Altitude : Integer ) ;Var Count : Integer ;Begin Count := Low ; While Count <= Hight Do Begin Sound ( Count ) ;

80

Page 81: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Delay ( (Altitude Div Count) * 75 ) ; Count := Count + 10 ; End ; For Count := 1 To 3 Do Begin Nosound ; Sound ( 40 ) ; Delay ( 500 ) ; Nosound ; Delay ( 100 ) ; End ; Sound ( 40 ) ; Delay ( 3000 ) ; Nosound ;End ;(* ------------------------------------------------------------ *) BEGIN BombsAway ( 1200, 200, 500 ) ;END.

5. Tiếng báo động:Ví dụ sau đây sẽ tạo ra tiếng báo động cho đến khi bạn gõ phím bất kì :

Program Bao_dong ;Uses Crt ;(* ----------------------------------------------------------- *) Procedure RedAlert ( Hight, Low : Integer ) ;Var Ch :Char ;Begin Clrscr ; Write(' An phim bât ki de cham dut bao dong ! ') ; Repeat Sound ( Hight ) ; Delay ( 400 ) ; Sound ( Low ) ; Delay ( 400 ) ; Until KeyPressed ; Ch := Readkey ; Nosound ;End ;(* ----------------------------------------------------------- *) BEGIN RedAlert ( 359, 200 ) ;END.

Trên đây, tôi đã trình bày các hiệu ứng của âm thanh được lập trình bởi Pascal. Tuy nhiên do sử dụng kĩ thuật phối âm chưa cao nên âm thanh chưa gây được ấn tượng cho người nghe. Ở phần Ứng dụng, tôi đã trình bày các ví dụ để tạo âm thanh sinh động hơn, bạn có thể tham khảo.

81

Page 82: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Khi chạy chương trình của mình, có lẽ ai cũng muốn chèn vào một đoạn nhạc ngắn và vui tai để chương trình thêm sinh động. Với kiến thức mà chúng ta đang có, điều đó có thể thực hiện được. Bạn có thể dùng thủ tục Sound và các tần số của nốt nhạc để tạo ra các đoạn nhạc theo ý muốn của mình, miễn là ta phải nắm chút ít về nhạc lí.

Ta đã biết, để thể hiện cao độ của nốt nhạc, ta dùng thủ tục Sound, còn đối với trường độ của nốt nhạc, ta dùng thủ tục Delay.

Bảng sau sẽ trình bày cao độ của các nốt nhạc :

STT Nốt nhạc Octave 3 Octave 4 Octave 5 Octave 6

010203040506070809101112

DoDo#ReRe#MiFaFa#SolSol#LaLa#Si

131139147156165175185196208220233247

262277294311330349370392415440466494

523554587622659698740784831880932988

107411091175124513191397148015681661176018651976

Bảng tần số nốt nạc theo quảng Tám ( Octave )

Trường độ của nốt nhạc do ta tự qui định tùy thuộc vào bản nhạc đó nhanh hay chậm. Chẳng hạn ta lấy nốt móc đơn làm mốc và cho nốt này một giá trị trường độ là 1/10 giây, thì

Nốt trắng = 4/10 giây Þ Delay ( 400 ) Nốt đen = 2/10 giây Þ Delay ( 200 )Nốt móc đơn = 1/10 giây Þ Delay ( 100 )Nốt móc đôi = 5/100 giây Þ Delay ( 50 )Nốt móc ba = 25/1000 giây Þ Delay ( 25 )

* ĐỌC VÀ CHƠI NHẠC TỪ TẬP TIN VĂN BẢN :Có một cách để chương trình chơi nhạc của bạn trở nên đơn giản và suôn sẽ hơn. Đó là đọc và

chơi nhạc từ tập tin văn bản. Bạn chỉ việc tạo file chứa các giá trị ấn định mức độ nhanh chậm của bản nhạc theo quy tắc có sẵn do chương trình đặt ra. Sau đó, bạn nhập đường dẫn để chương trình tìm và chơi bản nhạc có chứa trong file đã được chỉ định.

Chương trình sau đây sẽ phát ra giai điệu bài "Cho con” của Phạm Trọng Cầu. Bản nhạc được ghi trong Text file theo mẫu :

5 C D5 C MD5 D MD4 G D5 M D5 D T ...

82

Page 83: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Mỗi nốt nhạc được ghi trên một dòng theo thứ tự : quãng tám, tên nốt ( kí hiệu ) và kí hiệu trường độ phân cách nhau bởi một khoảng trắng.

Với bản nhạc này, ta lấy nốt móc đơn làm mốc và có giá trị trường độ là 250. Chữ T kí hiệu nốt trắng (Duration = 1000 ), chữ D - nốt đen ( Duration = 500 ), chữ MD - móc đơn ( Duration = 250 )...

Sau đây là chương trình Chơi nhạc từ Text file

Program Choi_nhac ; (* Bai hat 'Cho con' cua Pham Trong Cau *)Uses Crt;Const Notes: Array [0..12] Of String = ('L','C','CF','D','DF','E','F','FF','G','GF','A','AF','B') ; A0 = 32.625 ; T=1000 ; D=500 ; MD=250 ;Var f : Text ; S, N : String ; O, Du, Code : Integer ;

Procedure Play ( Octave : Integer ; Note : String ; Duration : Integer) ;Var Fr : real ; I : Integer ;Begin Fr := A0 ; For I := 1 To Octave Do Fr := Fr * 2 ; I := 0 ; While Notes[ i ] <> Note Do Begin Fr := Fr * Exp ( Ln(2) / 12 ) ; Inc ( i ) ; End ; If Note <> 'L' Then Begin Sound ( Round( Fr ) ) ; Delay ( Duration ) ; NoSound ; Delay ( 50 ) ; End Else Begin Nosound ; Delay( Duration + 50 ) ; End ;End ;

BEGIN Assign ( f,'CHOCON.OUT' ) ; Reset ( f ) ; Repeat Read ( f, O) ; Readln ( f, S ) ; While S[ 1 ] = ' ' do Delete( S, 1, 1 ) ; While S[ Length( S ) ] = ' ' Do Delete( S, Length( S ),1 ) ; N := Copy ( S, 1, Pos( ' ', s ) -1 ) ; Delete( S, 1, Pos( ' ', s ) ) ;

83

Page 84: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

While S[1]=' ' Do Delete( S, 1, 1 ) ; If S = 'T' Then Du := T ; If S = 'D' Then Du := D ; If S = 'MD' Then Du := MD ; Play ( O, N, Du ) ; Until EOF ( f ) ; Close ( f ) ;END.

Tập tin CHOCON.OUT đã có sẵn trong thư mục Data, bạn chỉ việc copy nó đến cùng thư mục với chương trình của bạn là được.

Mong bạn sẽ hài lòng với chương trình này !

1. Hằng biểu diễn màu:Mỗi vĩ đồ họa và mỗi chế độ đồ họa đều cho phép vẽ với một số màu khác nhau. Các màu này đã

được Turbo Pascal đặt tên cho dễ nhớ thay vì phải dùng các mã số. Các hằng mô tả màu có giá trị như sau :

Hằng Giá trịBlackBlueGreenCyanRedMagentaBrownLightGrayDarkGrayLightBlueLightGreenLightCyanLightRedLightMangentaYellowWhite

ĐenXanhXanh lá câyXanh cẩm thạchĐỏTíaNâuXám nhẹXám đậmXanh nhạtXanh lá cây nhạtXanh cẩm thạch nhạtHồngTía nhạtVàngTrắng

0123456789101112131415

2. Bảng màu (Palette):Là tập hợp các màu để ta có thể chọn một trong các màu của bảng màu này để vẽ. Bảng màu

chính là khái niệm hộp đựng bột màu vẽ của họa sĩ : đó là các ô chứa màu trong một bảng đựng màu. Ô màu đó có thể thay đổi nội dung, có thể chứa màu vàng, có thể chứa màu đỏ..., nghĩa là có thể thay đổi các màu trong một bảng màu.

3. Các thủ tục thiết lập màu:Để thiết lập màu vẽ và màu nền, ta có 2 thủ tục SetColor và SetBkColor :

SetColor ( Color : Word ); là thủ tục đặt màu vẽ hiện tại trong khi dùng bảng màu cho các thủ tục vẽ. Màu số 0 là màu nền.

SetBkColor ( Color : Word ); là thủ tục xác lập màu nền.

84

Page 85: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

SetBkColor(N) làm cho màu có thứ tự N thành màu nền hiện tại. Chỉ trừ SetBkColor(0) luôn đặt màu nền là đen.

Ví dụ: Vẽ các đường ngang dọc màu đỏ trên nền xanh

Uses Crt, Graph ;Var Gd, Gm : Integer ; Begin Gd := Detect ; InitGraph ( Gd, Gm,' ' ) ; If GraphResult <> GrOk Then Halt( 1 ) ; (* Đặt màu vẽ là đỏ *) SetColor ( Red ) ; (* Đặt màu nền là xanh *) SetBkColor ( Blue ) ; Repeat

Line ( Random( GetMaxX ), Random( GetMaxY ), Random( GetMaxX ), Random( GetMaxY ) ) ; Delay ( 50 ) ; Until KeyPressed ; CloseGraph;End.

Lưu ý: Đoạn chương trình

Gd := Detect ;InitGraph ( Gd, Gm,' ' ) ;If GraphResult <> GrOk Then Halt( 1 ) ;

sẽ yêu cầu máy tự tìm chế độ màn hình thích hợp và khởi động chế độ đồ họa của Turbo Pascal. Nếu bạn muốn khởi động chế độ đồ hoạ, bạn có thể sử dụng đoạn mã trên.

1. Các thủ tục vẽ điểm:

PutPixel ( X, Y : Integer, Color : Word ); vẽ một điểm sáng có màu là Color tại điểm có tọa độ (X, Y).

GetPixel ( X, Y : Integer ) : Word; là hàm cho ta biết màu hiện tại tại điểm (X, Y).Về nguyên tắc, với thủ tục vẽ điểm, thí dụ như PutPixel, ta có thể vẽ bất cứ hình gì. Tuy nhiên

Pascal cũng cung cấp cho người dùng nhiều thủ tục vẽ có sẵn, ta cần khai thác hết.

2. Các thủ tục vẽ đường thẳng:

Line ( x1, y1, x2, y2 : Integer ); là thủ tục vẽ đường thẳng nối liền hai điểm có tọa độ tương ứng là (x1, y1) và (x2, y2). Thủ tục vẽ đường thẳng này không phụ thuộc vào vị trí ban đầu của con trỏ màn hình. Sau khi vẽ song, con trỏ màn hình ở vị trí điểm (x2, y2).

LineTo ( X, Y : Integer ); là thủ tục vẽ từ vị trí con trỏ đồ họa hiện tại tới điểm (X, Y). LineRel ( dX, dY : Integer ); là thủ tục vẽ đường thẳng từ vị trí con trỏ đồ họa hiện tại (X, Y)

tới điểm mới có tọa độ (X + dX,Y + dY). Sau khi vẽ, con trỏ đồ họa rời tới điểm mới (X + dX, Y + dY).

85

Page 86: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

3. Các thủ tục vẽ đường tròn:

Circle ( X, Y : Integer ; R : Word ); là thủ tục vẽ đường tròn có tâm tại điểm ( X, Y ), có bán kính là R.

4. Các thủ tục vẽ hình chữ nhật :

Rectangle ( x1, y1, x2, y2 : Integer ); vẽ hình chữ nhật với (x1, y1) là tọa độ điểm phía trên - bên trái, còn (x2, y2) là tọa độ điểm phía dưới - bên phải.

Bar ( x1, y1, x2, y2 : Integer ); vẽ hình chữ nhật song có thể tô màu đặc ở trong. Do đó bạn có thể dễ dàng vẽ các biểu đồ theo kiểu cột chữ nhật. Một điều đặc biệt khác là cách thức và mẫu tô đặc bên trong hình chữ nhật này có nhiều loại và được xác định bằng thủ tục SetFillStyle ( bài sau ). Thủ tục vẽ hình chữ nhật Bar khác với thủ tục Rectangle ở chỗ Rectangle chỉ vẽ đường viền hình chữ nhật, không có tô bên trong được.

Ngoài các thủ tục để vẽ hình chữ nhật, Turbo Pascal còn cung cấp cho bạn một thủ tục để vẽ các đa giác bất kì như hình tam giác, lục giác.

DrawPoly ( NumPoints : Word ; Var PolyPoints ); vẽ một đường đa giác dùng màu và kiểu đường vẽ hiện thời.

PolyPoints là một tham số không kiểu chứa tọa độ các đỉnh của đa giác. NumPoints chỉ ra số tọa độ trong PolyPoints ( chính là số đỉnh của đa giác ). Một tọa độ bao gồm hai giá trị kiểu Word : một giá trị tọa độ X, một giá trị tọa độ Y.DrawPoly sử dụng kiểu nét vẽ là màu vẽ hiện hành.Chú ý rằng để vẽ một đa giác kín với N cạnh, bạn phải truyền N+1 tọa độ tới DawPoly, và tọa độ thứ N+1 phải trùng với tọa độ đầu tiên của đa giác đó. Bạn có thể thấy được điều này qua ví dụ vẽ hình tam giác sau :

Uses Graph ;Const (* 4 tọa độ của tam giác *) Triangle : Array[ 1.. 4 ] Of PointType = ( (X : 50 ; Y : 100), (X : 100 ; Y :100), (X : 150 ; Y : 150), (X : 50 ; Y : 100) ) ;Var Gd, Gm : Integer ;Begin Gd := Detect ; InitGraph ( Gd, Gm, ' ' ) ; If GraphResult <> GrOk Then Halt( 1 ) ; DrawPoly ( SizeOf( Triangle ) Div SizeOf( PointType ), Triangle) ; Readln ; CloseGraph ;End.

Trong đồ họa, hai thủ tục Write và Writeln sẽ không được phù hợp cho lắm vì chúng dùng đơn vị tọa độ là số kí tự chuẩn trên màn hình. Có 2 thủ tục hiện ăn bản trong màn hình đồ họa một cách chính xác đến từng điểm màn hình và phong phú kiểu chữ hơn.

OutText ( St : String ); cho hiện nội dung của xâu St tại vị trí hiện tại của con trỏ đồ họa.

86

Page 87: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

OutTextXY ( X, Y : Integer ; St : String ); cho hiện nội dung của xâu St nhưng tại tọa độ đồ họa (X, Y).

Như vậy, việc thực hiện lệnh OutTextXY cũngtương đương với việc thực hiện 2 lệnh :MoveTo ( X, Y ) ;OutText ( St ) ;

Kiểu chữ hiện ra trên màn hình nhờ 2 thủ tục trên sẽ có thể thay đổi vì có nhiều kiểu Font được chứa trong các file *.Chr.

SetTextStyle ( Font, Direction, CharSize : Word ); xác lập kiểu chữ với :

Kiểu Font chữ: DefaultFont = 0 Triplex Font = 1 SmallFont = 2 SansSerifFont = 3 GothicFont = 4

Chiều viết ( Direction ): HorizDir = 0 là nằm ngang VertDir = 1 là thẳng đứng

Kích thước chữ ( CharSize ): Nhận giá trị từ 1 đến 10, là kích thước của chữ.

SetTextJustify ( Hort, Vert : Word ); là thủ tục xác định vị trí dòng văn bản viết ra theo hai thủ tục OutText nói ở trên. Tham số Hort có các giá trị như sau : LeftText = 0 văn bản xuất hiện ở bên phải con trỏ đồ họa CenterText = 1 văn bản xuất hiện với tâm là vị trí con trỏ đồ họa RightText = 2 văn bản xuất hiện ở bên phải con trỏ Còn Vert là tham số có thể nhận các giá trị sau : BottomText = 0 văn bản xuất hiện ở phía trên của con trỏ

CenterText = 1 văn bản xuất hiện ở quanh con trỏ TopText = 2 văn bản xuất hiện ở phía dưới của con trỏ

Thí dụ sau sẽ xuất chữ “HELLO World !” ra màn hình với các font chữ, cách căn lề và hướng viết chữ khác nhau :

Uses Graph ;Var Gd, Gm : Integer ;BEGIN Gd := Detect ; InitGraph ( Gd, Gm, ' ' ) ; If GraphResult <> GrOk Then Halt( 1 ) ; (* Viết chữ HELLO theo chiều dọc *) SetTextStyle ( DefaultFont, VertDir, 2 ) ; SetTextJustify ( CenterText, CenterText ) ; OutTextXY ( 50, 50, ' HELLO ' ) ;

(* Viết chữ World ! theo chiều dọc *) SetTextStyle ( GothicFont, HorizDir, 2 ) ;

87

Page 88: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

SetTextJustify ( RightText, CenterText ) ; OutTextXY ( 150, 50, ' World ! ' ) ; Readln ;END.

SetFillStyle ( Pattern : Word ; Color : Word ); trong đó mẫu tô là các hằng số nguyên có tên và giá trị được định nghĩa sẵn.

EmptyFill = 0 ; (* mầu nền đen *)SolidFill = 1 ; (* vùng tô có màu tô *)LineFill = 2 ; (* mẫu tô --- *) ;LtslashFill = 3 ; (* mẫu tô / / / *)SlashFill = 4 ; (* mẫu tô / / / với các nét nhỏ *) BkSlashFill = 5 ; (* mẫu tô \ \ \ với các nét dày *)LtBkSlashFill = 6 ; (* mẫu tô \ \ \ *)HatchFill = 7 ; (* nét chải thưa *)XHatchFill = 8 ; (* nét chải dày *)InterLeaveFill = 9 ; (* các đường xen kẽ *)WideDotFill = 10 ; (* chấm thưa *)CloseDotFill = 11 ; (* chấm dày *)UserFill = 12 ; (* tô theo mẫu của người dùng *)

Thật khó mô tả hết các mẫu vẽ trên giấy, vì vậy khi dùng bạn cần thử thay các giá trị của Patern từ

0 tới 11, thay Color để chọn màu, để nhìn thấy hết các mẫu tô.

Thí dụ sau sẽ cho bạn xem qua về 12 mẫu tô mà bạn có thể sử dụng trong công việc đồ họa :

Uses Graph ;Var Gd, Gm : Integer ; X1, Y1, X2, Y2, i, Color : Integer ;BEGIN Gd := Detect ; InitGraph ( Gd, Gm, ' ' ) ; If GraphResult <> GrOk Then Halt( 1 ) ; X1 := 0 ; Y1 := 0 ; X2 := 50 ; Y2 := 50 ; Color := 8 ; SetBkColor ( 15 ) ; (* Hàng thứ nhất trên màn hình chứa 6 mẫu đầu tiên *) For I := 1 To 6 Do Begin SetFillStyle ( i, Color ) ; Bar ( X1, Y1, X2, Y2 ) ; X1 := X1 + 60 ; X2 := X1 + 50 ;

End ; X1 := 0 ; Y1 := 100 ; X2 := 50 ; Y2 := 150 ; (* Hàng thứ hai trên màn hình chứa 6 mẫu tiếp theo *) For I := 7 To 12 Do Begin

88

Page 89: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

SetFillStyle ( i, Color ) ; Bar ( X1, Y1, X2, Y2 ) ; X1 := X1 + 60 ; X2 := X1 + 50 ;

End ; Readln ; CloseGraph ;END.

Turbo Pascal có cung cấp cho bạn khả năng tự định nghĩa mẫu tô, nhưng lý thuyết về phần này hơi khó hiểu nên tôi không trình bày ở đây, tuy nhiên bạn có thể tham khảo thêm trong một số sách Pascal.

FloodFill ( X, Y : Integer ; Border : Word ); tô đầy một hình có đường bao kín với mẫu tô hiện hành, nghĩa là hình bao kín đó chứa tọa độ của điểm (X, Y), điểm (X, Y) gọi là điểm gieo. Mẫu tô hiện hành được thủ tục SetFillStyle hay SetFillPatern thiết lập, được dùng để làm đầy hình bao kín bởi màu đường biên Border (có giá trị từ 0 đến 15). Nếu điểm được khảo sát (X, Y) nằm trong hình bao, vùng bên trong được tô đầy còn nếu điểm đó nằm ngoài hình bao thì toàn bộ vùng bên ngoài hình bao được tô đầy.

Ví dụ sau sẽ tô đầy hình tròn bởi màu nhận được từ hàm GetMaxColor :

Uses Graph ;Var Gd, Gm : Integer ; Begin Gd := Detect ; InitGraph ( Gd, Gm, ' ' ) ; If GraphResult <> GrOk Then Halt ( 1 ) ; SetColor ( GetMaxColor ) ; Circle ( 50, 50, 20 ) ; FloodFill ( 50, 50, GetMaxColor ) ; Readln ; CloseGraph ;End.

FillPoly ( NumPoints : Word ; Var PolyPoints ); vẽ một hình đa giác có tô màu bên trong.PolyPoints là một tham số không kiểu chứa tọa độ các đỉnh của đa giác. NumPoints chỉ ra số tọa độ trong PolyPoints (chính là số đỉnh của đa giác). Một tọa độ bao gồm hai Word: một giá trị tọa độ X, một giá trị tọa độ Y.FillPoly tính toán tất cả các chỗ cắt ngang và sau đó tô đa giác bằng kiểu tô và màu hiện hành được xác định bởi SetFillStyle hay SetFillPatern. Đường bao ngoài của đa giác được vẽ với kiểu đường và màu hiện hành được thiết lập với SetLineStyle.

Uses Graph;Const Triangle: Array[ 1..3 ] Of PointType = ( (X : 50 ; Y : 100), (X : 100 ; Y : 100), (X : 150 ; Y : 150) ) ;Var Gd, Gm: Integer;Begin Gd := Detect ;

89

Page 90: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

InitGraph ( Gd, Gm, ' ' ) ; If GraphResult <> GrOk Then Halt( 1 ) ; FillPoly ( SizeOf( Triangle ) Div SizeOf( PointType ), Triangle ) ; Readln ; CloseGraph ;End.

y ViewPort ( cửa để nhìn ) là một vùng chữ nhật trên màn hình để bạn có thể thực hiện các thủ tục đồ họa trên đó như là một màn hình nhỏ.

SetViewPort ( x1, y1, x2, y2 : Integer ; Clip : Boolean ); là thủ tục sẽ xác lập một ViewPort trong màn hình với (x1, y1, x2, y2) là tọa độ của ViewPort. Sau khi gọi thủ tục này, tọa độ (0, 0) của tất cả các thủ tục vẽ sẽ là góc trên-bên trái (x1, y1) của ViewPort chứ không phải là góc trên-bên trái của màn hình.

Tham số Clip có thể có giá trị True = ClipOn : cho phép hiện lên các nét vẽ vượt ra ngoài khung ViewPort, còn ClipOff sẽ không cho hiện lên các nét vẽ vượt ra ngoài ViewPort.

Bạn có thể thay đổi ViewPort ở mọi nơi trong chương trình để có được tọa độ vẽ, khung vẽ cho thích hợp.

Thí dụ, bạn muốn vẽ đồ thị hàm số với gốc tọa độ ở giữa màn hình :

SetViewPort ( GetMaxX Div 2, GetMaxY Div 2, GetMaxX, GetMaxY, ClipOn ) ;

ViewPort này sẽ nằm ở góc phần tư dưới phải, với tọa độ được tính qua hàm GetMaxX và GetMaxY. Do tham số Clip có giá trị là True nên bạn có thể vẽ cho toàn màn hình.

Có 3 trình xử lý ImageSize, GetImage, PutImage để chép các điểm ảnh vào biến và về sau trình bày chúng ở bất kì nơi nào trên màn hình.

ImageSize ( x1, y1, x2, y2 : Integer ); trả về số byte cần thiết để lưu trữ hình trong phạm vi hình chữ nhật có góc trên-bên trái là (x1, y1), và góc dưới - bên phải là (x2, y2).

GetImage ( x1, y1, x2, y2 : Integer ; Var Pbitmap ); chép các điểm ảnh và các thông tin về bề

rộng, cao của hình chữ nhật vào biến có kiểu Bitmap.

PutImage ( X, Y : Integer ; Var PBitmap ; CopyMode : Word ); chép ảnh trong biến có kiểu Bitmap ra màn hình tại vị trí ( X, Y ). Tham biến CopyMode chỉ định một trong các hằng :

CopyPut = 0 sao chép đè lên bộ nhớ màn hình. Nghĩa là hình cũ trên màn hình sẽ bị mất đi. XorPut = 1 các điểm ảnh trong PBitmap sẽ kết hợp với các điểm ảnh trên màn hình với

phép toán logic XOR. Dùng phép toán này có lợi là nếu ta lặp lại một lần nữa thì phần nền bị hình đè lên sẽ được khôi phục lại.

OrPut = 2 là các phép toán logic tương ứng AndPut = 3 với các kiểu đặt màu ảnh NotPut = 4 vào màu nền.

Tóm lại, các bước mấu chốt bạn cần nhớ để có thể tạo hình chuyển động là :* Vẽ hình, lưu ảnh vào một biến động không định kiểu.

* Tạo trễ ( Delay ).90

Page 91: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

* Xóa hình đó, khôi phục lại nền cũ với thủ tục PutImage có dùng phép XorPut.* Vẽ hình ở vị trí mới.

CÁC BÀI TẬP PASCAL SAU PHẦN LÝ THUYẾT BÀI TẬP CHƯƠNG 1  

Bài 1 :Nhập 3 số a , b , c bất kì . Hãy kiểm tra xem ba số đó có thể là độ dài ba cạnh của một tam giác hay không ? Thông báo lên màn hình ‘ Thỏa mãn ‘, ‘ Không thỏa mãn trong từng trường hợp tương ứng .

Nhấn để xem bài giải.

Bài 2 :Nhập N số bất kì .Đếm các số lớn hơn 10 và nhỏ hơn 20 và tính tổng của chúng . Sau đó , đưa ra màn hình :

So cac so >10 và <20 la : ( gia tri ) Tong cua chung la : ( gia tri )

Nhấn để xem bài giải.

Bài 3 :Nhập bốn số a , b , c , d . Hãy tìm giá trị lớn nhất của chúng và gán giá trị lớn nhất đó cho biến Max .

Bài 4 :Đọc ngày tháng năm , sau đó viết ra màn hình đó là ngày thứ mấy trong tuần .

Bài 5 :Viết chương trình : Nhâp số báo danh Nhập điểm văn , toán , ngoại ngữ In ra màn hình dưới dạng : _ Phiếu điểm : _ Số báo danh : _ Điểm văn : _ Điểm toán : _ Điểm ngoại ngữ : _ Tổng số điểm : Bạn đã trúng tuyển ( hoặc Bạn đã không trúng tuyển ) với điều kiện Tổng số điểm >= 15 hay ngược lại .

Bài 6 :Viết chương trình nhập hai số thực . Sau đó hỏi phép tính cần thực hiện và in kết quả của phép tính đó . Nếu là “+” , in kết quả của tổng lên màn hình . Nếu là “-” , in kết quả của hiệu lên màn hình . Nếu là “/” , in kết quả của thương lên màn hình . Nếu là “*” , in kết quả của tích lên màn hình . Nếu là “+” , in kết quả của tổng lên màn hình . Nếu là “+” , in kết quả của tổng lên màn hình .

91

Page 92: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Bài 7 :Giải và biện luận phương trình :

x2 + ( m – 2 ) x + 1 = 0 ở đây m là tham số thực tuỳ ý .

Bài 8 :Viết chương trình nhập hai số tự nhiên N, M và thông báo ‘Dung‘ nếu N , M cùng tính chẵn lẽ , trong trường hợp ngược lại thì thông báo ‘Sai‘.

 BÀI TẬP CHƯƠNG 2 

SU dung lênh ForBài 1 :

Lập trình tính tích các số tự nhiên từ 1 tới 10 .Bài 2 :

Viết chương trình đếm số lần xuất hiện của các kí tự thuộc bảng chữ cái trong 50 lần gõ kí tự bằng bàn phím (không phân biệt a với A, b với B …, dùng hàm Upcase để chuyển đổi chữ thường với chữ hoa) .

Bài 3 :Cho số tự nhiên n , hãy lập trình để tính các tổng sau :

a. 1 + 1/22 + 1/32 + … + 1/n2 b. 1 + 1/2! + 1/3! + … + 1/n!

Bài 4 :Tính giá trị của biểu thức sau :

( 1 + 1/12 ) ( 1 + 1/22 ) … ( 1 + 1/n2 ) Su dung lênh While

Bài 5 :Lập trình tính tổng :

A = 1 + 1/2 + 1/3 + … + 1/nở đây n là số tự nhiên được nhập vào từ bàn phím .

Bài 6 :Tính hàm lũy thừa an , ở đây a thực và n tự nhiên được nhập vào từ bàn phím .

Bài 7 :Viết chương trình nhập một dãy số tối đa 100 số , sau đó in ra màn hình các số khác nhau .

Bài 8 :Viết chương trình nhập một dãy số tối đa 100 số , sau đó sắp xếp lại theo thứ tự tăng dần .

Su dung lênh RepeatBài 9 :

Cho một dãy số được nhập từ bàn phím . Hãy viết chương trình nhập một số a rồi liệt kê tất cả các phần tử trong dãy lớn hơn a.

Bài 10 :Viết chương trình nhập một dãy số tối đa 50 số rồi in ra màn hình các số trùng nhau của dãy .

Bài 11 :Bạn có 1000 đ đem gửi ngân hàng với lãi suất 8%/tháng . Sau mỗi tháng tiền lãi được nhập vào để tính lãi suất tháng sau . Bạn muốn để dành cho đến khi số tiền tăng lên là x . Vậy phải để trong bao lâu

Bài 12 :Viết chương trình tìm ƯSCLN của N số được nhập từ bàn phím .

92

Page 93: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

 BÀI TẬP CHƯƠNG 3  

Bài 1 :Dùng thủ tục chuyển một số tự nhiên n cho trước sang hệ cơ số 2 .

Bài 2 :

Dùng thủ tục giải phương trình bậc hai ax2 + bx + c = 0Bài 3 :

Hãy viết lại thủ tục Insert đối với một chuỗi kí tự cho trước tùy ý . Bài 4 :

Viết chương trình thực hiện lần lượt các công việc sau :_ Lập thủ tục nhập ba số thực dương a , b , c từ bàn phím ._ Lập thủ tục kiểm tra xem ba số trên có lập thành ba cạnh của tam giác hay không ? _ Viết thủ tục tính diện tích của tam giác ._ Viết thủ tục tính các trung tuyến của tam giác ._ Viết hoàn thiện chương trình chính .

Bài 5 :Giải phương trình x + y + z = 12 trong phạm vi số nguyên không âm với điều kiện x < 4 .

Bài 6 :Cho trước các số N , a , b , c tự nhiên . Giải phương trình sau trong phạm vi số nguyên không âm x + y + z = N với điều kiện x < a , y < b , z < c .

Bài 7 :Viết thủ tục Compare ( S1 , S2 : String ; Var Kq : String ) thực hiện công việc sau : so sánh hai xâu S1 và S2 , tìm tất cả các kí tự có trong cả hai xâu trên . Xâu Kq sẽ chứa tất cả các kí tự đó , mỗi kí tự chỉ được nhớ một lần .

Bài 8 :Viết hàm tính D (St1 , St2) , với U, V là hai xâu kí tự bất kì , là tổng số các kí tự không giống nhau trong hai xâu trên , mỗi loại kí tự chỉ được nhớ một lần . Ví dụ D (‘aabba’ , ‘bcdd’) = 2 vì chỉ có hai kí tự a và d là không giống nhau trong các xâu trên .

Bài 9 :Viết chương trình hoàn chỉnh thực hiện các công việc của thực đơn sau :

1. Nhập dữ liệu ( nhập số tự nhiên n ) .2. Phân tích ra thừa số nguyên tố ( phân tích n thành tích các số nguyên tố ) .3. Thoát khỏi chương trình .

 BÀI TẬP CHƯƠNG 4  

Bài 1 :Giải hệ phương trình tuyến tính hai ẩn dùng ma trận :

a11x + a12y = c1

a21x + a22y = c2

Bài 2 :Lập phương trình tạo ra một mảng chứa bảng cửu chương .

Bài 3 :

93

Page 94: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Viết chương trình nhập hai số nguyên dương m , n . Sau đó tính trung bình cộng bình phương các số nguyên từ m đến n .

Bài 4 :Viết chương trình nhập từ bàn phím các phần tử của một mảng hai chiều . Kích thước của mảng được nhập trước từ bàn phím .Bài 5 :

Dãy số sau được gọi là dãy Fibonaci :a1 = 1a2 = 1a3 = 2a4 = 3. . .an = an-1 + an-2

Viết chương trình tính 20 số Fibonaci đầu tiên và đưa ra kết quả vào một mảng 20 phần tử .Bài 6 :

Dãy số an được định nghĩa như sau : a1 = 1a2 = 2. . .an = 2an-1 + an-2 ( n > 2 )

Hãy lập chương trình tính và gán giá trị của dãy vào biến mảng .Bài 7 :Nhập số tự nhiên N và viết chương trình tạo mảng bao gồm N số nguyên tố đầu tiên .Bài 8 :

Viết chương trình nhập một bảng số 3 x 3 với điều kiện các số được nhập sẽ hiện trên màn hình đúng tại vị trí của mình trên bảng số .

Bài 9 :a. Viết chương trình nhập dữ liệu từ dãy đối xứng vào mảng một chiều .b. Viết chương trình nhập dữ liệu là ma trận đối xứng vào mảng hai chiều .

 BÀI TẬP CHƯƠNG 5  

Bài 1 :Lập trình đếm số lần xuất hiện ở mỗi loại kí tự thuộc bảng chữ cái tiếng Anh trong một xâu kí tự Str.

Bài 2 :Cho số tự nhiên n và xâu có độ dài n . Hãy biến đổi xâu đã cho bằng cách thay đổi trong đó :a. Tất cả các dấu ! bằng dấu chấm .b. Mỗi một nhóm các dấu chấm liền nhau bằng một dấu chấm .c. Một nhóm các dấu chấm đứng liền nhau bằng dấu ba chấm .

Bài 3 :Cho số tự nhiên n và một dãy các kí tự S1 , S2 , … , Sn . Hãy tìm số tự nhiên I đầu tiên sao cho các kí tự Si , Si+1 đều là chữ cái a . Nếu trong dãy không có những cặp như vậy thì thông báo .

Bài 4 :Cho số tự nhiên n và dãy các kí tự S1 , S2 , … , Sn . Biết rằng trong dãy có ít nhất một dấu phẩy . Hãy tìm số tự nhiên i sao cho :a. Si là dấu phẩy đầu tiên .b. Si là dấu phầy cuối cùng .

94

Page 95: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Bài 5 :

Viết chương trình nhập một xâu kí tự , sau đó chỉ ra xem xâu đó có phải là xâu đối xứng không ( xâu đối xứng là xâu có các kí tự giống nhau và đối xứng nhau qua điểm giữa xâu , ví dụ ‘ABBA’ hoặc ‘ABCBA’ ) .

Bài 6 :Cho một xâu kí tự S . Hãy viết chương trình tính xem trong S có bao nhiêu loại kí tự khác nhau ( phân biệt chữ in hoa với chữ in thường ) . Ví dụ với S là “Pascal” ta có đáp số là 5 .

Bài 7 :Viết chương trình nhập một xâu kí tự và biến đổi chúng thành toàn chữ in hoa .

Bài 8 :Họ tên một học sinh được nhập từ bàn phím . Bạn hãy viết chương trình điều chỉnh lại các kí tự đầu của các từ đơn trong tên của học sinh ấy trở thành chữ in hhoa .

Bài 9 :Viết chương trình nhập xãu kí tự từ bàn phím , sau đó gọt xâu lại bằng cách cách xoá đi các kí tự trống ở hai đầu của xâu . Ví dụ nếu nhập xâu “ Ha noi “ , thì kết quả sẽ là “Ha noi” .

 BÀI TẬP CHƯƠNG 6  

Bài 1 :Bạn hãy viết hàm Card(A) đếm số phần tử của tập hợp A cho trước có kiểu Set Of 0 .. 99 .

Bài 2 :Bạn hãy lập chương trình tạo một tập hợp các số nguyên chẵn kiểu Byte và loại khỏi nó các số chia hết cho 3 . Kết quả thể hiện trên màn hình .

Bài 3 :Xét chương trình sau :

Program B4 ;Var Thoat : Set Of Char = [‘e’ , ’E’] ;

BEGIN Write (‘ Hay go E de ket thuc : ‘) ; Repeat Ch := Readkey ; Until Ch in thoat ;END .

Hãy tìm và sửa lỗi trong chương trình đó .Bài 4 :

Bạn hãy lập chương trình hiển thị một menu dạng sau trên màn hình

1. Xem2. Sua chua3. Loai bo4. Nhap them5. ThoatLua chon cua ban : _

95

Page 96: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Sau đó đợi gõ phím . Chương trình phải đợi cho tới khi phím gõ vào là một trong các chữ số 1 .. 5 hoặc các chữ cái đầu của các tuỳ chọn thì thông báo phím gõ vào hợp lệ và kết thúc chương trình . Trong chương trình phải dùng một tập hợp để kiểm tra việc nhập giá trị cho biến từ bàn phím .

Bài 5 :Hãy lập chương trình nhập vào một xâu nhị phân . Các kí tự nhập vào không hợp lệ bị bỏ qua .

Bài 6 :Hãy lập chương trình nhập vào một xâu kí tự từ bàn phím . Yêu cầu các kí tự nhập vào phải là các chữ cái thuộc bảng chữ cái tiếng Anh , bỏ qua các phím khác .

Bài 7 :Viết chương trình có chức năng thêm phần tử vào tập hợp trực tiếp từ bàn phím và loại bớt phần tử khỏi tập hợp cũng trực tiếp từ bàn phím .

 BÀI TẬP CHƯƠNG 7  

Bài 1 :Thông tin về mỗi học sinh gồm : Họ đệm : một xâu 25 kí tự . Tên : một xâu 10 kí tự . Tuổi : một số nguyên hai chữ số . Lớp : một xâu hai chữ số và một chữ cái viết hoa

Hãy lập chương trình nhập từ bàn phím danh sách một lớp 15 học sinh vào một mảng bản ghi . Sau đó hiển thị danh sách lên màn hình , mỗi người một dòng .

Bài 2 :Thông tin về mỗi học sinh là một bản ghi gồm các trường : Họđệm : một xâu 25 kí tự . Tên : một xâu 10 kí tự . Tuổi : một số nguyên hai chữ số . Lớp : một xâu hai chữ số và một chữ cái viết hoa

Một file bản ghi chứa một danh sách một lớp gồm 20 học sinh . Hãy lập chương trình hiển thị danh sách lên màn hình , mỗi người một dòng .

Bài 3 :Một file bản ghi chứa một danh sách học sinh , thông tin về mỗi học sinh giống như bài trên . Hãy lập chương trình tạo một file bản ghi khác chứa danh sách đó , mỗi bản ghi gồm các trường : Họtên : một xâu 35 kí tự . Tuổi : một số nguyên hai chữ số . Khối : một số nguyên hai chữ số . Lớp : một chữ cái viết hoa

Bài 4 :

Một file bản ghi chứa một danh sách học sinh PTTH , thông tin về mỗi học sinh ngoài các trường Họđệm , Tên , Tuổi , Lớp giống như các bài trên còn có thêm trường Điểm chứa điểm trung bình của học sinh trong năm học . Hãy lập chương trình :a. Hiển thị lên màn hình danh sách những học sinh giỏi nhất của trường là những bạn có điểm trung

bình từ 8.0 trở lên và cao nhất trong khối .b. Lập danh sách học sinh trong năm học mới , biết một học sinh có điểm trung bình từ 5.0 trở lên

thì được lên lớp . Chú ý : lớp 10A lên lớp 11A , lớp 11A lên 12A ... Kết quả chứa trong file .Bài 5 :

96

Page 97: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Cho file bản ghi f chứa dữ liệu về kho sách , dữ liệu về mỗi cuốn sách được chứa trong một bản ghi gồm 3 trường mang thông tin về : Họ tên tác giả : một xâu 26 kí tự . Tên sách : một xâu 40 kí tự . Năm xuất bản : một số nguyên 4 chữ số .

Hăy lập chương trình nhập dữ liệu vào kho sách , sau đó tìm ra : Những cuốn sách của một tác giả cho trước xuất bản vào một năm cho trước . Những cuốn sách có tên cho trước .

Kết quả hiện trên màn hìnhBài 6 :

File bản ghi F chứa danh sách các ngày lễ trong một năm , mỗi bản ghi gồm ngày tháng , tên ngày lễ và số ngày được nghỉ . Hãy lập chương trình nhập danh sách các ngày lễ và tính : Tổng số các ngày lễ và tổng số các ngày nghỉ lễ trong năm . Tổng số các ngày lễ và tổng số các ngày nghỉ lễ trong quí 1 , quí 2 , …

Kết quả thể hiện trên màn hình .

 BÀI TẬP CHƯƠNG 8  

Bài 1 :Hãy lập chương trình tạo một tệp số nguyên chứa các số nguyên tố nhỏ hơn 10000 theo thứ tự tăng dần . 

Bài 2 :Cho f là tệp văn bản chứa các xâu 10 kí tự . Hãy lập chương trình nhập và hiển thị nội dung file đó lên màn hình , mỗi xâu một dòng , đầy trang màn hình thì dừng lại đợi gõ Enter mới hiển thị trang tiếp theo cho tới hết.

Bài 3 :Bạn hãy viết chương trình cho phép đọc dữ liệu từ bàn phím và ghi thêm vào cuối một tệp các bản ghi .

Bài 4 :

Cho một văn bản chứa trong một text file f . Trong văn bản , tính từ trái sang phải , từ trên xuống dưới , kí tự # là kí hiệu xoá đi một từ đứng ngay trước nó nếu có . Ví dụ ‘#Ta#oi di ngu#h###hoc’ có nghĩa là ‘Toi di hoc’ . Bạn hãy viết chương trình sửa lại file f theo quy ước trên .

Bài 5 :

Cho 2 file f và g cùng kiểu ( nhưng không rõ kiểu nào ) . Bạn hãy lập thủ tục gán nội dung của file g cho file f.

Bài 6 :Cho một file text ghi lại một chương trình Pascal của một học sinh . Hãy viết chương trình kiểm tra lỗi của chương trình Pascal trên theo các cách sau đây :Cách 1 : Kiểm tra xem số lượng các dấu ‘ ( dấu mở và dấu đóng ) có bằng nhau không ?Cách 2 : Kiểm tra xem số lượng các từ Begin và End có bằng nhau không ?

Bài 7 :Cho một file text . Hãy viết chương trình đếm xem file text trên chứa bao nhiêu từ .

97

Page 98: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

( Chú ý : theo quy định , các từ cách nhau bởi một hay nhiều dấu cách ) .

Bài 8 :Cho một file text . Viết chương trình loại bỏ các khoảng trống thừa bên trong file text này .

 BÀI TẬP CHƯƠNG 9  

Bài 1 :Bạn hãy lập chương trình cho phép ta nhập từ bàn phím một danh sách được ghép nối . Sau đó gỡ bỏ một record khỏi danh sách .

Bài 2 :Bạn hãy lập chương trình cho phép nhập một danh sách được ghép nối . Sau đó chèn thêm một record vào danh sách .

Bài 3 :Bạn hãy lập chương trình cho phép nhập một danh sách được ghép nối . Sau đó đổi chỗ hai record trong danh sách .

 BÀI TẬP CHƯƠNG 10  

Bài 1 :Vẽ hình chữ nhật có tâm trùng với tâm màn hình , các cạnh song song và tỉ lê với các cạnh màn hình , kích thước lớn dần theo thời gian . 

Bài 2 :Vẽ hình chữ nhật như trên , kích thước điều khiển được . Nếu gõ phím + thì hình lớn lên , gõ phím – thì nhỏ đi , gõ Enter thì dừng chương trình .

 Bài 3 :Một bàn cờ vua hiển thị trên màn hình . Nếu đặt một con hậu ( hình tròn màu đỏ ) vào một ô bằng cách nhập tên ô , chẳng hạn a5 , thì các ô bị con hâu khống chế sẽ được tô màu xanh . Bạn hãy lập chương trình thực hiện các yêu cầu trên .

Bài 4 :Vẽ đồng hồ điện tử hoạt động trên màn hình . 

Bài 5 :Hiển thị một điểm chuyển động đều theo chiều kim đồng hồ trên quỹ đạo tròn , tâm là tâm màn hình , bán kính r = 150 .

Bài 6 :

Hiển thị một hình chữ nhật trên màn hình , vị trí có thể điều khiển được bằng bàn phím . Gõ các phím mũi tên để dịch chuyển hình đó theo các hướng tương ứng .  

98

Page 99: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Bài 7 :Vẽ hình sau với các phông chữ , các màu khác nhau : 

Size 8 

Size 16 

Size 24 

Size 32 

Size 40 

Bài 8 :Vẽ hệ trục toạ độ và đồ thị hàm số y = x2 với đầy đủ chú thích . 

Bài 9 :Vẽ và tô màu cho ngôi nhà sau . Đảm bảo khả năng bật tắt điện cho ngôi nhà . Nếu gõ phím + thì đèn sáng ( cửa sổ có màu trắng ) , gõ phím – thì đèn tắt ( cửa số có màu đen ) .  

 

HƯỚNG DẪN GIẢI BÀI TẬP THEO TỪNG CHƯƠNG NHƯ TRÊNChương 1:bài1: Var a , b , c : Real ;

BEGIN Writeln (' Nhap do dai 3 canh cua tam giac : ') ; Write (' a = ') ; Readln ( a ) ; Write (' b = ') ; Readln ( b ) ; Write (' c = ') ; Readln ( c ) ;

If ( a + b > c ) and ( b + c > a ) and ( c + a > b ) and ( a > 0 ) and ( b > 0 ) and ( c > 0 ) Then Writeln (' Thoa man : Day la 3 canh cua mot tam giac ') Else

99

Page 100: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Writeln (' Khong thoa man ! ') ; Readln ; END .

bài2:

Var Tong , So : Real ; I , N , Dem : Integer ;

BEGIN Write (' Bao nhieu so : ') ; Readln ( N ) ; Tong := 0 ; Dem := 0 ; For I := 1 To N Do Begin Write (' So = ') ; Readln ( So ) ; If ( So > 10 ) and ( So < 20 ) Then Begin Tong := Tong + So ; Dem := Dem + 1 ; End ; End ;

Writeln (' So cac so >10 va <20 la : ', Dem ) ; Writeln (' Tong cua chung la :', Tong ) ; Readln ; END .

bài3:

Var Max , a , b , c , d : Real ;

BEGIN Writeln (' Nhap gia tri cua 4 so : ') ; Write (' a = ') ; Readln ( a ) ; Write (' b = ') ; Readln ( b ) ; Write (' c = ') ; Readln ( c ) ; Write (' d = ') ; Readln ( d ) ;

Max := a ; If Max < b Then Max := b ; If Max < c Then Max := c ; If Max < d Then Max := d ; Writeln (' Gia tri lon nhat la : ', Max ) ; Readln ;

100

Page 101: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

END .

bài4:

Var Thu , Ngay , Thang : Byte ; Nam : Integer ;

BEGIN Write (' Doc Ngay Thang Nam : ') ; Readln ( Ngay , Thang , Nam ) ; Nam := 1900 + ( Nam mod 1900 ) ;

If Thang < 3 Then Begin Thang := Thang + 12 ; Nam := Nam - 1 ; End ; Thu := Abs ( Ngay + Thang * 2 + ( Thang + 1 ) * 3 div 5 + Nam + Nam div 4 ) mod 7 ;

Case Thu Of 0 : Writeln (' Chu Nhat ') ; 1 : Writeln (' Thu Hai ') ; 2 : Writeln (' Thu Ba ') ; 3 : Writeln (' Thu Tu ') ; 4 : Writeln (' Thu Nam ') ; 5 : Writeln (' Thu Sau ') ; 6 : Writeln (' Thu Bay ') ; End ; Readln ; END .

bài5:

Uses Crt ; Var SBD : Integer; Van , Toan , Ngoaingu , Tongdiem : Real ;

BEGIN Clrscr ; Write (' So bao danh : ') ; Readln( SBD ) ; Write (' Diem toan : ') ; Readln( Toan ) ; Write (' Diem ngoai ngu : ') ; Readln( Ngoaingu ) ; Write (' Diem van : ') ; Readln ( Van ) ;

101

Page 102: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Tongdiem := Toan + Van + Ngoaingu ;

Clrscr ; Writeln (' Phieu Bao Diem ') ; Writeln (' So bao danh : ', SBD ) ; Writeln (' Diem van : ', Van ) ; Writeln (' Diem toan : ', Toan ) ; Writeln (' Diem ngoai ngu : ', Ngoaingu) ; Writeln (' Tong diem : ', Tongdiem) ; If Tongdiem >= 15 Then Writeln(' Ban da trung tuyen ') Else Writeln(' Ban khong trung tuyen ') ; Readln ; END .

bài6:

Uses Crt ; Var a , b , T : Real ; Pt : Char ;

BEGIN Clrscr ; Write (' a = ') ; Readln( a ) ; Write (' b = ') ; Readln( b ) ; Write (' Phep tinh thuc hien la (+ - * /) : ') ; Readln( Pt ) ; If Pt = '+’ Then T := a + b ; If Pt = '-’ Then T := a - b ; If Pt = '*’ Then T := a * b ; If Pt = '/’ Then T := a / b ; Write ( a , pt , b , ' = ', T ) ; Readln ; END .

bài7:

Uses Crt; Var m , Delta : Real ; BEGIN Clrscr; Write (' m = ') ; Readln( m ) ;

102

Page 103: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Delta := sqr( m-2 ) - 4 ; If Delta < 0 Then Writeln(' Phuong trinh vo nghiem ') Else Begin If Delta = 0 Then Writeln(' Phuong trinh co nghiem kep X= ', -( m - 2 ) / 2 ) Else Begin Writeln(' Phuong trinh co 2 nghiem : ') ; Writeln (' X1 = ', ( -(m-2) + sqrt(delta) ) / 2 ) ; Writeln (' X2 = ', ( -(m-2) - sqrt(Delta) ) / 2 ) ; End ; End ; Readln ; END .

bài 8:

Uses Crt ; Var N , M : Integer ;

Begin Clrscr ; Write(' N , M = ') ; Readln( N , M ) ; If ( (N + M) mod 2 = 0 ) Then Writeln(' Dung ! ') Else Writeln(' Sai ! ') ; Readln ; END .

Chương 2:Bài 1:

Var i : Byte ; p : word ;

BEGIN p := 1; For i := 1 to 10 Do

(* cho i chay từ1 tới 10 *) p := p * i ;

(* lần lượt nhân i vao p *) Write (' 1 * 2 * ... * 10 = ', p ) ; Readln ;

103

Page 104: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

END .

bài 2:

Uses Crt ; Var a : Array[ 'A'..'Z' ] of integer; ch : char ; i : byte ;

BEGIN Clrscr ; For ch :='A' to 'Z' Do a[ch] := 0 ; Writeln (' Go phim 50 lan ') ; For i := 1 To 50 Do Begin ch :=Readkey ; ch := Upcase(ch) ; a[ch] := a[ch] + 1 ; End; Writeln (' So lan xuat hien cac ki tu la :') ; For ch :='A' to 'Z' do (* Kieåm tra boä ñeám töø 'A' tôùi 'Z' *) If a[ch] > 0 Then (* Neáu Ch coù xuaát hieän *) Writeln (ch , a[ch] : 4 , ' lan . ') ; (* Vieát ra maøn hÓnh kí töï vaø

soá laàn xuaát hieän *) Readln ; END .

bài 3:

a) Var n , i : Word ; S : Real ;

BEGIN Write (' Nhap n : ') ; Readln (n) ; S := 0 ; For i := 1 To n Do S := S + 1 / sqr(i) ; Writeln (' S = ', S:0:2) ; Readln ; END .

b) Var n , i , j , p : Word ;

104

Page 105: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

S : Real ; BEGIN Write (' Nhap n : ') ; Readln(n) ; p := 1 ; s := 0 ; For i :=1 To n Do Begin p := p * i ; (* tính i *) S := S + 1 / p ; End ; Writeln (' S = ', S:0:2) ; Readln ; END .

bài 4:

Var i , n : Byte ; p : Real ;

Begin Write(' Nhap n : ') ; Readln (n) ; p := 1 ; For i := 1 To n Do p := p * ( 1 + 1/sqr(i) ) ; Writeln(' p = ', p:10:5 ) ; Readln ; End .

bài 5:

Uses Crt ; Var i , n : Integer ; tong: Real ;

BEGIN Clrscr ; Write (' Cho so tu nhien n : ') ; Readln (n) ; tong :=0 ; i :=1 ; While i <= n Do Begin tong := tong + 1/i ; i := i + 1 ; End ; Writeln (' Tong can tim la : ', tong:12:6 ) ;

105

Page 106: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Readln ; END .

bài 6:

Uses Crt ; Var i , n : Integer ; a , giatri : Real ;

BEGIN Clrscr ; Write (' Cho so a : ') ; Readln(a) ; Write (' Cho so mu n : ') ; Readln(n) ; i := 1 ; giatri := 1 ; While i <= n Do Begin giatri := giatri * a ; i:= i+1 ; End ; Writeln(' a mu n bang : ', giatri ) ; Readln ; END .

bài7:

Uses Crt; Var A : Array [1..100] Of Integer; i , j , n : Integer ;

BEGIN Clrscr ; Write(' Do dai cua day so N = ') ; Readln (N) ; For I := 1 To N Do Begin Write ('A[', i , ']= ') ; Readln ( A[i] ) ; End ; Writeln (' Cac so khac nhau la : ') ; Writeln ( A[1] ) ; i := 2 ; While i <= N Do Begin j := 1 ; While ( j < i ) and ( A[j] <> A[i] ) Do inc(j) ; If j = i Then Writeln( A[i] ) ; i :=i + 1 ;

106

Page 107: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

End ; Readln ; END .

bài 8:

Uses Crt; Var A : Array [1..100] Of Integer ; i , j , n , T : Integer ;

BEGIN Clrscr ; Write(' Do dai cua day so N = ') ; Readln (N) ; Writeln (' Nhap day so : ') ; For i := 1 To N Do Begin Write('A[', i ,'] = ') ; Readln ( A[i] ) ; End ; i := 1 ; While (i <= n-1) Do Begin j := i+1; While j<=n do Begin If A[j] < A[i] then Begin T := A[j];

A[j ] := A[i]; A[i] := T ;

End ; j := j + 1; End ; i := i + 1; End ; Writeln(' Day sau khi sap xep : ') ; For i := 1 To N Do Write(A[i] : 4) ; Readln ; END .

bài 9:

Uses Crt ; Var b : Array[1..100] Of Real; a : Real ; n , i : Byte ;

107

Page 108: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

BEGIN Clrscr ; Write ('Nhap do dai cua day so : ') ; Readln(n) ; Writeln (' Nhap cac phan tu cua day : ') ; For i := 1 To n Do Begin Write (' b[', i ,'] = ') ; Readln( b[i] ) ; End ; Write (' Nhap so thuc a : ') ; Readln(a) ; Writeln (' Cac phan tu lon hon a cua day : ') ; i:=1; Repeat If ( b[i] > a ) Then Writeln (' b[', i ,'] = ', b[i]:8:2 ) ; inc(i) ; Until i > n ; Readln ; END .

bài 10:

Uses crt ; Var a , b : Array[1..50] Of Integer ; n , m , i , j , k : Byte ; trung : Boolean ;

BEGIN Clrscr ; Write (' Nhap do dai cua day so nguyen : ') ; Readln(n) ; Writeln (' Nhap cac phan tu cua day : ') ; For i := 1 To N do Begin Write (' a[', i ,'] = ') ; Readln( a[i] ) ; End ; i := 1 ; m := 0 ; Repeat trung := false ; j := i + 1; Repeat If ( j <= n ) and ( a[i] = a[j] ) Then trung := true ; inc (j) ; Until trung or ( j > n ) ; If trung Then Begin m := m + 1; b[m] := a[i] ; writeln ( b[m] : 4 ) ; End ;

108

Page 109: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

inc(i) ; Until i > n ; If m > 1 Then Begin i := 1 ; Repeat j := i + 1 ; Repeat trung := false ; If b[i] = b[j] Then trung := true ; If trung Then Begin

If j < m Then For k := j To m - 1 Do b[k] := b[k + 1] ;

m := m - 1 ; dec ( j ) ;

End ; inc ( j ) ; Until j > m ; inc ( i ) ; Until i > m ; End ; If m > 0 Then For k := 1 To m Do Write ( b[k] : 4 ) ; Readln ; END .

bài 11:

uses crt ; var thang : Byte ; tien , lai , x : Real ;

BEGIN clrscr ; writeln (' Chuong trinh tinh thoi gian rut tien lai ') ; write (' So tien lai muon rut ra : ') ; readln(x) ; tien := 1000 ; thang :=1 ; repeat lai := tien * 8 / 100 ; tien := tien + lai ; thang := thang + 1 ; until tien >= x ; writeln (' Ban phai gui tien trong ', thang div 12 , ' nam ',

109

Page 110: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

thang mod 12 ,' thang .') ; writeln (' Khi do so tien ban rut ra duoc la ', tien:12:2 ,' dong .') ; readln ; END .

bài 12:

Uses crt ; Var a : Array [1..100] Of Integer ; n , i : Byte ; d : integer ; BEGIN Clrscr ; Writeln (' Tim USCLN cua N so :') ; Write (' Nhap so N : ') ; Readln(n) ; Writeln ('Nhap ', N ,' so : ') ; For i := 1 To n Do Begin Write(' So thu ', i ,' = ') ; Readln( a[i] ) ; End ; For i := 1 To n-1 Do Repeat d := a[i] ; a[i] := a[ i+1 ] mod a[i] ; a[i+1] := d ; Until a[i] = 0 ; Writeln (' USCLN cua ', N ,' so la : ', a[n] ) ; Readln ; END .

Chương 3:Bài 1:

Procedure Change ( n : integer ; Var St : String ) ; (* thuû tuïc chuyeån soá töï nhieân n cho tröôùc sang heä cô soá 2 vaø ñöôïc löu ôû trong xaâu St *) Type b : Array[0 .. 1] Of Char = ('0' , '1') ; Var du , So : Integer ; S : String ;

Begin S := '' ; (* xaâu roăng *) So := n ;

110

Page 111: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Repeat Du := So mod 2 ; So :=So div 2 ; S := b[du] + s ; Until So = 0 ; St := S ; End.

bài 2:

Uses Crt ; Var a, b, c, x1, x2: real; (*================================*) Procedure Nhapabc(var aa,bb,cc: real); Begin Write('a='); Readln(aa); Write('b='); Readln(bb); Write('c='); Readln(cc); End; (*=================================*) Procedure GPTB2; Var Delta: real; Begin Delta:=sqr(b)-4*a*c; If Delta<0 then Writeln('Phuong trinh vo nghiem.') Else If Delta=0 then Begin Write('Phuong trinh co nghiem kep : '); Write('x1,2=',-b/(2*a):8:2); End Else Begin x1:=(-b+sqrt(Delta))/(2*a); x2:=(-b-sqrt(Delta))/(2*a); Writeln('Phuong trinh co 2 nghiem phan biet la :'); Writeln('X1=',x1:8:2, 'X2=',x2:8:2); End; End; (*================================*) BEGIN (* CT chính *) Clrscr; Writeln(' Giai Phuong Trinh Bac Hai Voi Cac He So :'); Nhapabc(a,b,c); If a<>0 then GPTB2 Else Writeln(' Khong phai phuong trinh bac hai ');

111

Page 112: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Readln ; END .

bài 3:

Procedure Insert ( St1 : String ; Var St2 : String ;Vt : Byte ) ; (* cheøn xaâu St1 vaøo St2 baét ñaàu töø v trí Vt *) Var i : Byte ; S : String ;

Begin If ( Vt > length(St2) Or ( Vt < 1 ) Then Write(' Khong the chen ra ngoai xau ') ; Else Begin S := '' ; (* xaâu roăng *) For i := 1 To (Vt - 1) Do S := S + St2[i] ; S := S + St1 ; For i := Vt To length(St2) Do S := S + St2[i] ; St2 := S ; End ; End.

bài 4:

Uses Crt; Var a, b, c: real ; (*================================*) Procedure Nhap(Var a, b, c: real); Procedure input (Var a: real; tenbien: Char); Begin Repeat Write('Nhap ' + tenbien+' = '); Readln(a); Until (a>=0); End; Begin (* baét ñaàu thuû tuïc nhaäp *) Input(a, 'a'); Input(b, 'b'); Input(c, 'c'); End; (* keát thuùc thuû tuïc nhaäp *) (*================================*) Procedure Kiemtra(a, b, c: Real); Begin If (a<b+c) and (b<a+c) and (c<a+b) then Writeln(a:0:2, ', ', b:0:2, ' va ', c:0:2,

112

Page 113: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

' lap thanh ba canh cua tam giac ') Else Writeln('Khong lap thanh ba canh cua tam giac') ; End; (*===============================*) Procedure Trung_tuyen (a, b, c: Real); Var ma, mb, mc: real; Begin ma:=sqrt((2*sqr(b)+2*sqr(c)-sqr(a))/4); mb:=sqrt((2*sqr(a)+2*sqr(c)-sqr(b))/4); mc:=sqrt((2*sqr(a)+2*sqr(b)-sqr(c))/4); Writeln('Cac trung tuyen cua tam giac la : ') ; Writeln('ma=', ma:0:2, ' mb=', mb:0:2, ' mc=', mc:0:2); End; (*================================*) Procedure Dientich (a, b, c: real); Var p, S: real; Begin p:=(a+b+c)/2; S:=sqrt(p*(p-a)*(p-b)*(p-c)); Writeln('Dien tich =', S:0:2); End; (*================================*) BEGIN (* Chöông trnh chính *) Clrscr; Nhap(a, b, c); Kiemtra(a, b, c); Dientich(a, b, c); Trung_tuyen(a, b, c); Readln; END .

bài 5:

Uses Crt; Var X, Y, Z: byte; Begin Clrscr; Writeln('Giai phuong trinh X+Y+Z=12 trong pham vi ' + 'so nguyen khong am voi dieu kien x<4'); For X:=0 to 3 do For Y:=0 to 12 do For Z:=0 to 12 do If (X+Y+Z=12) then Writeln(' x=',X,' y=',Y, 'z=',Z); Readln; End.

bài 6:113

Page 114: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Uses Crt; Var N, a, b, c, X, Y, Z, i: Integer; Begin Clrscr; Write(' N, a, b, c = '); Readln(N, a, b,c); If (a+b+c-3<N) then Begin Writeln('Phuong trinh vo nghiem'); Readln; Exit; End Else Begin Writeln('Phuong trinh co nghiem la:'); Writeln('x': 10, 'y': 10, 'z':10); i:=4; For X:=0 to (a-1) do For Y:=0 to (b-1) do For Z:=0 to (c-1) do If (X+Y+Z=N) then Begin Writeln(x: 10, y: 10, z: 10); inc(i); If i=24 then Begin Write('Nhan Enter de tiep tuc...'); Readln; i :=0; End; End ; End ; Write('Nhan Enter de ket thuc...'); Readln; End.

bài 7:

Uses Crt; Var xau1,xau2,xau: string; (*==================================*) Procedure compare(s1, s2: string; Var kq: string); Var i: byte; (*===============================*) Function kt(ch: char; st: string): boolean; (* Kieåm tra xem kí töï Ch coù trong xaâu St khoâng . Neáu coù thÓ haøm traû veà giaù tr True . Neáu khoâng thÓ haøm traû veà giaù tr False *)

114

Page 115: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Begin kt:=pos(ch,st)<>0; End; (*================================*) Begin (* Thaân cuûa thuû tuïc Compare*) kq:=''; (* Xaâu roăng *) For i:=1 to length(s1) do If (not kt(s1[i],kq)) and (kt(s1[i],s2)) then kq:=concat(kq,s1[i]); End; (*==============================*) BEGIN Clrscr; Writeln('Nhap 2 xau S1 va S2 :'); Write('S1: '); Readln(xau1); Write('S2: '); Readln(xau2); Compare(xau1, xau2, xau); If xau<>'' then Writeln('Xau chung la: ',xau) Else Writeln('Khong co ki tu nao trong ca hai xau '); Write('Nhan ENTER de ket thuc...'); Readln; END .

bài 8:

Uses Crt; Const M=100; Var S: array[1..M] of string; max, min, i, j, n: byte; (*===============================*) Function D(U,V: string): byte; (*Traû veà toång soá loaïi kí töï khoâng gioáng nhau trong 2 xaâu U vaø V *) Var k, id: byte; s, luu: string; Begin luu:=''; (* Xaâu roăng *) For id:=1 to length(U) do If (pos(U[id],V)=0) and (pos(U[id],luu)=0) then luu:=concat(luu,U[id]); For id:=1 to length(V) do If(pos(V[id],U) = 0) and (pos(V[id],luu)=0) then luu:= concat(luu,V[id]); d:=length(luu); End; (*=================================*)

115

Page 116: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Procedure nhap; Begin Repeat Write('So xau ki tu (>=2):') ; Readln(n); If n<2 then Writeln(#7,'Co ',n,' xau ki tu nen khong the ' + 'so sanh duoc'); Until n>=2; Writeln('Nhap ',n,' xau ki tu :'); For i:=1 to n do Begin Write('S',i,'='); Readln(S[i]); End; End ; (*===============================*) BEGIN (* Chöông trnh chính *) Clrscr; nhap; max:=0; min:=255; For i:=1 to n-1 do For j:=i+1 to n do Begin If max<d(S[i],S[j]) then max:=d(S[i],S[j]); If min>d(S[i],S[j]) then min:=d(S[i],S[j]); End; Write('Max(d(Si,Sj)=',max,' Min(d(Si,Sj)=',min); Readln; END .

bài 9:

Uses Crt; Type uoc_nguyen_to=array[1..50] of longint; Var u, N: longint; i, dem: integer; a: uoc_nguyen_to; (*================================*) Procedure nhap(Var NN:longint); Begin Repeat Write('Nhap N='); Readln(NN); Until NN>=0; End; (*=================================*)

116

Page 117: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Procedure viet; Begin If dem=0 then Writeln('So ',N,' khong the phan tich thanh ' + 'tich cua cac so nguyen to') Else If dem=1 then Writeln(N, '=', a[dem]) Else Begin Write(N,'='); For i:=1 to dem-1 do Write(a[i],'*'); Writeln(a[dem]); End; End; (*================================*) Procedure phantich(N1:longint); Begin If N1>1 then Begin u:=2; dem:=0; Repeat If (N1 mod u=0) then Begin inc(dem); a[dem]:=u; N1:=N1 div u; End Else inc(u); Until N1=1; End Else dem:=0; Viet; End; (*==============================*) BEGIN (* Main Program *) Clrscr; Writeln('Phan tich so N thanh tich cua cac so nguyen to :'); nhap(N); phantich(N); Write('Nhan Enter de ket thuc ...'); Readln; END .

Chương 4:Bài 1:

117

Page 118: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Uses Crt; Var a: array[1..2, 1..2] of real; c: array[1..2] of real; d, dx, dy, x, y: real;

BEGIN Clrscr; Writeln('Giai he phuong tring tuyen tinh hai an:'); Writeln(' a11x+a12y=c1'); Writeln(' a21x+a22y=c2'); Writeln('Nhap cac he so cua he phuong trinh'); Write('a11='); Readln(a[1,1]); Write('a12='); Readln(a[1,2]); Write('c1='); Readln(c[1]); Write('a21='); Readln(a[2,1]); Write('a22='); Readln(a[2,2]); Write('c2='); Readln(c[2]); d:=a[1,1]*a[2,2] - a[2,1] * a[1,2]; dx:=c[1]*a[2,2] - c[2] * a[1,2]; dy:=a[1,1]*c[2] - a[2,1] * c[1]; If d=0 then Writeln(' He vo nghiem hoac vo so nghiem') Else Begin x:=dx/d; y:=dy/d; Writeln('He co nghiem duy nhat :'); Writeln('x=', x:0:2, ' ; y=', y:0:2); End ; Readln; END .

bài 2:

Uses Crt ; Var a : Array[1..10, 2..9] Of Byte ; i, j : Byte ; BEGIN Clrscr ; For i := 1 To 10 Do For j := 2 To 9 Do a[i, j] := i*j ; Writeln(' Bang cuu chuong : ') ; Writeln ; For i := 1 To 10 Do For j := 2 to 9 do Write ( j:4 , 'x' , i:2 , '=' , a[i , j]:2) ; (* heát 80 coät töï ñoäng xuoáng haøng *) Readln ; END .

118

Page 119: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

bài 3:

Var m , n , k , s : Word ; tb : real ; BEGIN Writeln('Nhap 2 so nguyen duong m, n :') ; Write (' m = ') ; Readln(m) ; Write (' n = ') ; Readln(n); If m > n Then (* ñoăi choă ñeå m <= n *) Begin k := m ; m := n ; n := k ; End ; s := 0 ; For k := m To n do s := s + sqr(k) ; tb := s / (n - m + 1) ; Writeln ('Trung binh cong bimh phuong cac so ' + 'nguyen tu m den n la: ', tb:12:2); Readln ; END .

bài 4:

Var m , n , i , j : Byte ; a : Array[1..100, 1..100] Of Real;

BEGIN Write ('Nhap cac kich thuoc cua mang hai chieu : ') ; Write (' So hang m = ') ; Readln(m) ; Write (' So cot n = ') ; Readln(n) ; Writeln (' Nhap cac phan tu cua mang : ') ; For i := 1 To m Do For j := 1 To n Do Begin Write ('a[', i:2, ', ' , j:2 ,']=') ; Readln(a[i, j]) ; End ; Readln ; END .

bài 5:

Var a : Array[1..20] Of Byte ;

119

Page 120: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

i : Byte ;

BEGIN a[1] :=1; a[2] :=1; For i:=3 to 20 do a[i]:=a[i-1]+a[i-2] ; END .

bài 6:

Var a : Array [1..100] Of Word ; i, N : Byte ; S : Real ;

BEGIN Write (' Nhap so N>=2 : ') ; Readln(n) ; a[1] := 1 ; a[2] := 2 ; For i := 3 To N Do a[i] := 2*a[i-1]+a[i-2] ; S := 0 ; For i := 1 to N do S := S+1/sqr(a[i]) ; Writeln (' S = ', S:12:6) ; Readln ; END .

bài 7:

var a:array[1..100,1..100]of byte; n,i,j,k,l,ba:byte; d:boolean;

BEGIN write(' Nhap kich thuoc cua mang hai chieu NxN. N = ');readln(n); for i:=1 to n do for j:=1 to n do begin ba:=0; repeat d:=FALSE; if j>1 then for k:=1 to j-1 do if a[i,k]=ba then d:=true; if i>1 then for k:=1 to i-1 do if a[k,j]=ba then d:=true; ba:=ba+1;

120

Page 121: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

until not d; a[i,j]:=ba-1; end; for i:=1 to n do for j:=1 to n do write(a[i,j]:8); readln; END .

bài 8:

Uses Crt; Var a : array[1..3, 1..3] of integer ; i, j: byte ;

BEGIN Clrscr; Writeln('Nhap mot bang so nguyen kich thuoc 3x3:'); Gotoxy(10, 4); Write(1); Gotoxy(19, 4); Write(2); Gotoxy(28, 4); Write(3); Gotoxy(5, 6); Write(1); Gotoxy(5, 8); Write(2); Gotoxy(5,10); Write(3); For i:=1 to 3 do For j:=1 to 3 do Begin Gotoxy(9*j-1, 2*i+4); Read(a[i, j]); Gotoxy(9*j-1, 2*i+4); ClrEol; Write(a[i, j]:6); End; Readln; END .

bài 9:

a) Var a: array [1..100] of integer; n, i: byte; Begin Write('Nhap so phan tu cua day doi xung:'); Readln(n); Writeln('Nhap cac phan tu cua day:'); For i:=1 to (n+1) div 2 do Begin Write('a[', i:2, ']='); Readln(a[i]);

121

Page 122: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

a[n-i+1] := a[i]; End; Readln ; END ;

b) Var a: array [1..100, 1..100] of integer; n, i, j: integer; BEGIN Write('Nhap kich thuoc cua mang doi xung: '); Readln(n); Write('Nhap cac phan tu cua mang:'); For i:=1 to n do For j:=1 to i do Begin Write('a[', i:2, ',', j:2, ']='); Readln(a[i, j]); a[j,i]:=a[i,j]; End; Readln ; END.

Chương 5:Bài 1:

Var A: array [ 'A'..'Z'] of integer; S: string; ch: char; i: integer; BEGIN Write(' Cho mot xau ki tu : '); Readln(s); For ch:= 'A' to 'Z' do A[ch]:=0; For i:=1 to length(s) do Begin If Upcase(S[i]) in (['A'..'Z']) then Begin S[i]:= Upcase(S[i]); A[S[i]]:= A[S[i]]+1; End; End; For ch:= 'A' to 'Z' do Writeln('So lan xuat hien cua ',ch,' trong xau la: ', A[ch]:4) ; Readln ; END .

bài 2:

122

Page 123: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

a ) Var S: string; i: byte;

BEGIN Write(' Cho mot xau ki tu S = '); Readln(S); For i:=1 to length(S) do If S[i] = '!' then S[i]:= '.'; Write( ' Chuoi sau khi da bien doi la : ', S); Readln; END . b ) Uses crt; Var S : string; i : byte;

BEGIN Clrscr; Write(' Cho mot xau ki tu S = '); Readln(S); i:=1; While i< length(S) do If (S[i]='.')and(S[i+1]='.') then Delete(S,i,1) Else inc(i); Write('Chuoi sau khi da bien doi la: ' ,S); Readln; END . c ) Uses crt; Var S: string; i, j: byte;

BEGIN Clrscr; Write('Nhap xau S='); Readln(S); i:=1; While i<=Length(S) do Begin If S[i]='.' then Begin j:=i; While (S[i]='.')and(i<=length(S)) do inc(i); dec(i); If (i-j)=1 then insert('.',S,i) Else If (i-j)>2 then

123

Page 124: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Begin Delete(S,j+2,i-j-2); i:=j+1; End; End ; Inc(i); End; Write('Chuoi sau khi bien doi la: ',S); Readln; END .

bài 3:

Var S: string; i: integer;

BEGIN Write(' Cho mot xau ki tu : '); Readln(S); i:= pos('aa', S); {t Óm v trí xaâu con 'aa' trong S} If i<>0 then Writeln(' Ton tai "aa" tai vi tri ', i) Else Writeln(' Khong ton tai .') ; Readln; END .

bài 4:

a ) Var S: string; i: integer;

BEGIN Write('Cho mot xau S co dau ",": '); Readln(S); i:= pos(',', S); (* v trí cuûa daáu ',' trong S *) If i<> 0 then Write(' Vi tri thoa man la: ', i); Readln; END .

b ) Var S: string; i: integer;

BEGIN Write('Cho mot xau S co dau ",": '); Readln(S); i:= length(S); While (i>=1)and(S[i] <> ',' ) do i:=i -1; If i>=1 then Write('So thu tu thoa man la: ', i)

124

Page 125: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Else Write('Khong ton tai.'); Readln; END .

bài 5:

Uses Crt; Var St : string; dx : Boolean; i, len: byte;

BEGIN Clrscr; Write(' Nhap xau St = '); Readln(St); dx:= True; i:=1; len:= Length(St); While dx and (i<=(len div 2)) do Begin dx:=(St[i] = St[len - i+1]); inc(i); End; If dx then Write(' St la xau doi xung ') Else Write(' St khong phai la xau doi xung ') ; Readln; END . bài 6:

Var S: string; i, j, dem: integer; t: boolean;

BEGIN Write('Cho mot xau ki tu S: '); Readln(S); dem:=0; For i:=1 to length(S) do Begin t:=false; For j:=1 to i-1 do if (S[j]=S[i]) then t:=true; If not t then dem:= dem+1; End; Write('So ki tu khac nhau cua xau S la: ', Dem); Readln; END .

125

Page 126: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

bài 7:

Var S : string; i : integer;

BEGIN Write('Cho mot xau ky tu: '); Readln(S); For i:=1 to length(S) do If S[i] in ['a' ..'z'] then S[i]:= Upcase(S[i]); Write('Chuoi sau khi da bien doi la: ', S); Readln; END .

bài 8:

Uses crt; Const Chu=['a'..'z']; Var Hoten: string; i,len: byte;

BEGIN Clrscr; Write('Ho ten='); Readln(Hoten); Len:=length(Hoten); If Hoten[1] in Chu then Hoten[1]:=Upcase(Hoten[1]); For i:=2 to len do If (Hoten[i-1]=#32)and(Hoten[i] in Chu) then Hoten[i]:=Upcase(Hoten[i]); Write('Ho ten sau khi dieu chinh la: ', Hoten); Readln; END .

bài 9:

Var S: String;

BEGIN Write('Cho mot xau ky tu: '); Readln(S); While S[1] = #32 do Delete(S,1,1); While (S[length(S)] = #32) do Delete(S,length(S),1); Write('Chuoi sau khi da bien doi la: ', S); Readln; END .

126

Page 127: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Chương 6:Bài 1:

(* haøm ñeám soá phaàn töû cuûa taäp hôïp *) Uses Crt; Type Tap=set of 0..99; Const inp='Number.dat'; Var S : Tap; i : byte;

Procedure Nhap; Var a: byte; f: text; Begin S:=[]; Assign(f,inp); Reset(f); While not SeekEoF(f) do begin Readln(f,a); If (a>=0)and(a<=99) then S:=S+[a]; End; Close(f); End;

Function Card(S: Tap): byte; Var i,n: byte; Begin n:=0; For i:=0 to 99 do If i in S then Inc(n); Card:=n; End;

BEGIN Nhap; Clrscr; Write('Tap S co ',Card(S),' phan tu.'); Readln; END.

bài 2:

Uses Crt; Const n=5; Type Danhsach=record holot: string[25];

127

Page 128: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

ten: string[10]; tuoi: 0..99; lop: string[3]; End ; Var ds: array [1..20] of Danhsach; i,j: byte; f: file of Danhsach;

Procedure Doi(i,j: byte); Var tg: Danhsach; Begin tg:=ds[i]; ds[i]:=ds[j]; ds[j]:=tg; End;

BEGIN ClrScr; Writeln('Nhap danh sach hoc sinh tu file data.dat : '); Writeln; Assign(f,'data.dat'); Reset(f); For i:=1 to n do Read(f,ds[i]); Close(f); For i:=1 to n-1 do For j:=i+1 to n do begin If (ds[i].ten>ds[j].ten) then Doi(i,j) Else If (ds[i].ten=ds[j].ten)and(ds[i].holot>ds[j].holot) then Doi(i,j); end; Writeln('Danh sach hoc sinh:'); For i:=1 to n do With ds[i] do Writeln(holot:20,ten:11,tuoi:4,lop:5); Writeln; Write('Bam Enter de ket thuc...'); Readln; END.

bài 3:

Uses Crt; Const thoat: set of char=['e','E']; Var ch: char;

128

Page 129: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

BEGIN Write('Hay go E de thoat khoi chuong trinh: '); Repeat ch:=readkey; Until ch in thoat; END .

bài 4:

(* Hieån th menu *) Uses Crt; Const menu: set of char = ['1'..'5','X','S','L','N','T']; Var ch: char;

BEGIN Clrscr; Writeln(' 1. Xem '); Writeln(' 2. Sua chua '); Writeln(' 3. Loai bo '); Writeln(' 4. Nhap them'); Writeln(' 5. Thoat '); Write('Lua chon cua ban: '); Repeat ch:=readkey; ch:=Upcase(ch); Until ch in menu; Writeln; Write('Ban da chon:'); Case ch of '1','X': Writeln(' 1. Xem '); '2','S': Writeln(' 2. Sua chua '); '3','L': Writeln(' 3. Loai bo '); '4','N': Writeln(' 4. Nhap them'); '5','T': Writeln(' 5. Thoat '); End; Readln; END.

bài 5:

(* nhaäp moät xaâu nh phaân *) Uses Crt; Const bit : set of char= ['0','1']; Var ch: char;

129

Page 130: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

st: string;

BEGIN Clrscr; st:=''; Write('Nhap vao mot xau nhi phan : '); Repeat ch:= Readkey; If ch in bit then begin st:=st+ch; Write(ch); end Else If ch<>#13 then Write(#7); Until ch=#13; Readln; END.

bài 6:

(* Nhaäp moät xaâu toaøn caùc chöơ caùi *) Uses Crt; Const A:set of char=['a'..'z','A'..'Z']; Var ch: char; st: string;

BEGIN Clrscr; st:=''; Writeln('Nhap vao mot xau toan cac chu cai:'); Repeat ch:=Readkey; If ch in A then begin st:=st+ch; write(ch); End Else if ch<>#13 then Write(#7); If ch=#0 then ch:=Readkey; Until ch = #13; END .

bài 7 :

(* loai bo cac phan tu khoi tap hop *) Uses Crt; Var tap: set of char;

130

Page 131: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

ch: char;

BEGIN tap:=[]; Writeln('Nhap cac phan tu cho mot tap hop cac ki tu: '); Repeat ch:=ReadKey; tap:=tap+[ch]; Writeln(ch); Until not(ch in ['a'..'z']); Writeln('Cac phan tu cua tap hop la:'); For ch:='a' to 'z' do If ch in tap then Write(ch,' '); Writeln; Writeln('Ban muon bo cac phan tu nao khoi tap hop:'); Repeat ch:=ReadKey; tap:=tap-[ch]; Writeln(ch); Until not(ch in ['a'..'z']); Writeln('Cac phan tu con lai cua tap hop la:'); For ch:='a' to 'z' do If ch in tap then Write(ch,' '); Readln; END .

Chương 7:Bài 1:

(* Nhaäp danh saùch hoïc sinh töø baøn phím *) Uses Crt; Const n=15; Type Danhsach=record

holot: string[25]; ten: string[10]; tuoi: 0..99; lop: string[3];

End; Var ds: array [1..n] of Danhsach; i : byte;

BEGIN ClrScr; Writeln('Hay nhap danh sach hoc sinh : '); Writeln; For i:=1 to n do

131

Page 132: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Begin Writeln('Thong tin hoc sinh thu ',i); Write('Cho ho lot : '); Readln(ds[i].holot); Write('Cho ten : '); Readln(ds[i].ten); Write('Cho tuoi : '); Readln(ds[i].tuoi); Write('Cho lop : '); Readln(ds[i].lop); Writeln; End; Writeln('Danh sach hoc sinh :'); For i:=1 to n do With ds[i] do Writeln(holot:20,ten:10,tuoi:4,lop:5); Writeln; Write('Bam Enter de ket thuc...'); Readln; END.

bài 2:

(* Doc tu mot file ban ghi *) Uses Crt; Const n=5; Type Danhsach=record holot: string[25]; ten: string[10]; tuoi: 0..99; lop: string[3]; end; Var ds: Danhsach; i: byte; f: file of Danhsach;

BEGIN ClrScr; Writeln('Danh sach hoc sinh tu file bai2.dat'); Writeln; Assign(f,'bai2.dat'); Reset(f); For i:=1 to n do Begin Read(f,ds); With ds do Writeln(holot:20,ten:11,tuoi:4,lop:5); End; Close(f); Writeln; Write('Bam Enter de ket thuc...'); Readln; END .

132

Page 133: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

bài 3:

(* Doi kieu ban ghi *) Uses Crt; Type Danhsach1=record holot: string[25]; ten: string[10]; tuoi: 0..99; lop: string[3]; End; Danhsach2=record hoten: string[35]; tuoi: byte; khoi: byte; lop: char; End;

Var ds1 : Danhsach1; ds2 : Danhsach2; f1 : file of Danhsach1; f2 : file of Danhsach2; c : integer;

BEGIN ClrScr; Writeln('Ghi tu file bai3.dat sang bai3n.dat:'); Writeln; Assign(f1,'bai3.dat'); Reset(f1); Assign(f2,'bai3n.dat'); Rewrite(f2); While not Eof(f1) do Begin Read(f1,ds1); With ds1 do Begin ds2.hoten:=holot+ten; val(copy(lop,1,2),ds2.khoi,c); ds2.tuoi:=tuoi; ds2.lop:=UpCase(lop[3]); Write(f2,ds2); End; End; Close(f1); Close(f2); Writeln; Writeln('Bam Enter de ket thuc!'); Readln;

133

Page 134: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

END .

bài 4:

(* Khen thuong va len lop *) Uses Crt; Type Danhsach=record holot: string[25]; ten: string[10]; tuoi: 0..99; lop: string[3]; diem: real; End;

Var ds: array [1..100] of Danhsach; f: file of Danhsach; n: integer;

Procedure Nhap; Begin Assign(f,'bai4.dat'); Reset(f); n:=0; While not Eof(f) do Begin n:=n+1; Read(f,ds[n]); End; Close(f); End;

Procedure Timgioi; Var i: integer; max10,max11,max12: real; l: string; Begin max10:=0; max11:=0; max12:=0; For i:=1 to n do With ds[i] do Begin l:=copy(lop,1,2); If (l='10')and(diem>max10)and(diem>8.0) then max10:=diem Else If (l='11')and(diem>max11)and(diem>8.0) then max11:=diem Else If (l='12')and(diem>max12)and(diem>8.0) then max12:=diem; End; Writeln('Hoc sinh gioi nhat khoi 10 : '); For i:=1 to n do With ds[i] do If (copy(lop,1,2)='10')and(diem>=max10) then Writeln(holot:20,ten:10,tuoi:4,lop:5,diem:5:1);

134

Page 135: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Writeln('Hoc sinh gioi nhat khoi 11 : '); For i:=1 to n do With ds[i] do If (copy(lop,1,2)='11')and(diem>=max11) then Writeln(holot:20,ten:10,tuoi:4,lop:5,diem:5:1); Writeln('Hoc sinh gioi nhat khoi 12 : '); For i:=1 to n do With ds[i] do If (copy(lop,1,2)='12')and(diem>=max12) then Writeln(holot:20,ten:10,tuoi:4,lop:5,diem:5:1); End;

Procedure Lenlop; Var i: integer; l: string; f: file of Danhsach; Begin For i:=1 to n do With ds[i] do Begin l:=copy(lop,1,2); If (l='10')and(diem>=5.0) then lop:='11'+lop[3] Else If (l='11')and(diem>=5.0) then lop:='12'+lop[3] Else If (l='12')and(diem>=5.0) then lop:='DTN'; End; Assign(f,'bai4n.dat'); Rewrite(f); For i:=1 to n do With ds[i] do If lop<>'DTN' then Write(f,ds[i]); Close(f); End;

BEGIN ClrScr; Nhap; Timgioi; Lenlop; Write('Bam ENTER de ket thuc...'); Readln; END .

bài 5:

(* Tim kiem tren ban ghi *) Uses Crt; Type Danhsach=record Tacgia: string[26]; Tensach: string[40]; NamXB: integer; End;

135

Page 136: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Var ds: array [1..100] of Danhsach; n : integer; f : file of Danhsach; M: Danhsach;

Procedure Nhap; Begin n:=0; Assign(f,'bai5.dat'); Reset(f); While not Eof(f) do Begin Inc(n); Read(f,ds[n]); End; Close(f); End;

Procedure TheoTG; Var tacgia: string; namXB: integer; i: integer; Begin Write('Cho ten tac gia : '); Readln(M.tacgia); Write('Cho nam xuat ban : '); Readln(M.NamXB); i:=1; While (i<=n)and((ds[i].tacgia<>tacgia)or(ds[i].namXB<>namXB)) do i:=i+1; If (i>n) then Writeln('Khong tim duoc') Else Writeln(ds[i].tacgia:28,ds[i].tensach:42,ds[i].namXB:6); End;

Procedure TheoTS; Var ten: string; i: integer; Begin Write('Cho ten sach : '); Readln(ten); i:=1; While (i<=n)and(ds[i].tensach<>ten) do i:=i+1; If (i>n) then Writeln('Khong tim duoc') Else Writeln(ds[i].tacgia:28,ds[i].tensach:42,ds[i].namXB:6); End;

Procedure Timkiem; Var c:char; Begin Writeln('1. Tim kiem theo tac gia va nam xuat ban.'); Writeln('2. Tim kiem theo ten sach'); Writeln; Write('Ban chon [1/2] : ');

136

Page 137: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Repeat c:=Readkey; Until pos(c,'12')>0; Writeln(c); If c='1' then TheoTG Else TheoTS; End;

BEGIN ClrScr; Nhap; Timkiem; Write('Ban Enter de ket thuc...'); Readln; END.

bài 6:

(* Tinh so ngay le va ngay nghi trong nam ,qui *) Uses Crt; Type Danhsach=record ngay: byte; thang: byte; ten: string[15]; songay: integer; end; Var ds: array [1..100] of Danhsach; n: integer; f: file of Danhsach; snn,snnq1,snnq2,snnq3,snnq4: integer; tsq1,tsq2,tsq3,tsq4: integer;

Procedure Nhap; Begin n:=0; Assign(f,'bai6.dat'); Reset(f); While not Eof(f) do Begin Inc(n); Read(f,ds[n]); End; Close(f); End;

Procedure Tinh_ngay_nghi; Var i: integer; Begin snn:=0;

137

Page 138: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

snnq1:=0; tsq1:=0; snnq2:=0; tsq2:=0; snnq3:=0; tsq3:=0; snnq4:=0; tsq4:=0; For i:=1 to n do With ds[i] do Begin Inc(snn,songay); If (thang<3) then Begin Inc(snnq1,songay); Inc(tsq1); End Else If (thang<6) then Begin Inc(snnq2,songay); Inc(tsq2); End; If (thang<9) then Begin Inc(snnq3,songay); Inc(tsq3); End ; If (thang<12) then Begin Inc(snnq4,songay); Inc(tsq4); End; End; End;

Procedure Inkq; Var i: integer; Begin Writeln('So ngay le trong nam : ',n); Writeln('Tong so ngay nghi le trong nam : ',snn); Writeln; Writeln('So ngay le trong qui 1 : ',tsq1); Writeln('Tong so ngay nghi le trong qui 1 : ',snnq1); Writeln('So ngay le trong qui 2 : ',tsq2); Writeln('Tong so ngay nghi le trong qui 2 : ',snnq2); Writeln('So ngay le trong qui 3 : ',tsq3); Writeln('Tong so ngay nghi le trong qui 3 : ',snnq3); Writeln('So ngay le trong qui 4 : ',tsq4); Writeln('Tong so ngay nghi le trong qui 4 : ',snnq4); Writeln; End;

BEGIN Clrscr; Nhap; Tinh_ngay_nghi;

138

Page 139: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Inkq; Write('Ban Enter de ket thuc...'); Readln; END.

Chương 8:Bài 1:

(* Tạo một file gồm các số nguyên tố nhỏ hơn 10000 *) Uses Crt; Const N=10000; Var i , j : Integer; f: File of Integer; a: Array[2..N] of boolean;

BEGIN For i:=2 to N do a[i]:=true; i:=2; Repeat For j:=2 to (N div i) do a[i*j]:=false; Repeat Inc(i) Until a[i] or (i>N); Until i>N; Assign(F,'C:\SoNT.dat'); Rewrite(F); For i:=1 to N do If a[i] then Write(F,i); Close(F); clrscr; Write(' Viet ra file "C:\SoNT" cac so nguyen to nho hon 10000 '); Readln; END .

bài 2:

(* Ghi vaø ñoïc file of String *) Uses Crt; Const INP='FoString.dat'; Type String10 = String[10];

Procedure Ghi; Var f: file of String10; S: String10; Begin Assign(f,INP); Rewrite(f); Writeln('Nhap vao f. Thoi nhap khi S='''' (go Enter)!'); Readln(S); While (S<>'') do Begin

139

Page 140: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Write(f,S); Readln(S); End; Close(f); End;

Procedure Doc; Var f: file of String10; S: String10; Begin Clrscr; Assign(f,INP); Reset(f); While Not Eof(f) Do Begin Read(f,S); Writeln(S); If WhereY=25 then Begin Write('Press Enter to continue..'); Readln; Clrscr; End; End; Close(f); Readln; End;

BEGIN Ghi; Doc; END.

bài 3:

(* Doc vaø ghi vaøo cuoái teäp caùc baûn ghi *) Uses Crt; Const inp='Hocsinh.dat'; Type Hocsinh=Record Ten : String[30]; Tuoi: Byte; End; Var F : file of Hocsinh; Hs: Hocsinh;

BEGIN Assign(f,inp); Reset(f); Write('Ho va ten: '); Readln(Hs.Ten); Write('Tuoi : '); Readln(Hs.Tuoi);

140

Page 141: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Seek(f,Filesize(F)); Write(f,Hs); Close(f); END .

bài 4:

Uses Crt; Const fi='vanban.txt'; Var f: text; s: string; ch: char;

Procedure docfile ( fi : String ); Var f : text ; Begin Assign(f,fi); Reset(f); while not eof(f) do Begin Read(f,ch); Write(ch); End; close(f) ; writeln ; End ;

BEGIN Writeln(' Van ban ban dau doc tu file "vanban.txt" :') ; docfile(fi) ;

assign(f,fi) ; reset(f) ; s:=''; Repeat Read(f,ch); If (ch='#')then Delete(s,length(s),1) Else s:=s+ch; Until Eof(f); Close(f); Assign(f,fi); Rewrite(f); Writeln(f,s); Close(f);

Writeln(' Van ban sau khi sua chua :') ; docfile(fi) ; Readln; END .

141

Page 142: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

bài 5:

(* Gan hai file *) Uses Crt; Const f1='calc.ex'; f2='C:\calc.exe';

Procedure Copyfile(fi1,fi2: string); Var nread,nbuf: word; buf: array [1..1024] of byte; f1,f2: file; Begin Assign(f1,fi1); Reset(f1,1); Assign(f2,fi2); Rewrite(f2,1); nbuf:=1024; Repeat Blockread(f1,buf,nbuf,nread); Blockwrite(f2,buf,nread); Until nread<>nbuf; Close(f1); Close(f2); End;

BEGIN Copyfile(f1,f2); END.

bài 6:

(* Dem (') vaø 'Begin' , 'End' *) Uses Crt; Const fi='C8_6.txt';

Function Dem(c: string): integer; Var n,l: integer; f: text; S: string; Begin l:=Length(c); n:=0; Assign(f,fi); Reset(f); While not Eof(f) do Begin Readln(f,S); While pos(c,s)<>0 do Begin Inc(n); Delete(s,pos(c,s),l); End;

142

Page 143: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

End; Close(f); Dem:=n; End;

BEGIN Clrscr; Write(' So luong cac dau ( va ) '); If Dem('(')<>Dem(')') then Writeln('khong bang nhau.') Else Writeln('bang nhau.'); Write(' So luong cac tu Begin va End '); If Dem('End')<>Dem('Begin') then Writeln('khong bang nhau.') Else Writeln('bang nhau.'); Readln; END .

bài 7:

Uses Crt; Const fi = 'hoten.txt'; Var f: text; s: string; dem: word;

BEGIN Clrscr; dem:=0; Assign(f,fi); Reset(f); While not Eof(f) do Begin Readln(f,s); While s[1]=' ' do Delete(s,1,1); While length(s)>0 do Begin Case s[1] of ' ': While (s[1]=' ')and(length(s)>0) do Delete(s,1,1); Else Begin inc(dem); While (s[1]<>' ') and (length(s)>0) do Delete(s,1,1); End; End; End; End; Close(f); Write(' So tu co trong file hoten.txt la: ',dem);

143

Page 144: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Readln; END.

bài 8:

(* Cat khoang trong thua *) Uses Crt; Const fi = 'file.inp'; fo = 'C:\file.out'; Var inp,out: text; s: string;

BEGIN Assign(inp,fi); Reset(inp); Assign(out,fo); Rewrite(out); While not Eof(inp) do Begin Readln(inp,s); While (s[1]=' ')and(Length(s)>0) do Delete(s,1,1); While (s[Length(s)]=' ')and(Length(s)>0) do Delete(s,Length(s),1); While (Length(s)>0)and(pos(' ',s)<>0) do Delete(s,pos(' ',s),1); Writeln(out,s); End; Close(out); Close(inp); END.

Chương 9:Bài 1:

Uses Crt; Type ptr=^rec; rec=record name: string[20]; next: ptr; End; Var k : integer; p,l : ptr;

Procedure Nhap; Begin ClrScr; New(p); l:=p; Write('Ten: '); Readln(p^.name); Repeat New(p^.next);

144

Page 145: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

p:=p^.next; Write('Ten: '); Readln(p^.name); Until p^.name=''; p^.next:=nil; Write('Vi tri ban ghi can go bo: '); Readln(k); End;

Procedure Gobo; Var i: integer; q: Ptr; Begin p:=l; For i:=1 to k do p:=p^.next; (* TÓm v trí cuoái *) q:=p; p:=l; For i:=3 to k do p:=p^.next; (* TÓm v trí ñaàu *) If k=1 then l:=q Else p^.next:=q; End;

Procedure In_kq; Begin While (l^.next<>nil) do Begin Writeln(l^.name); l:=l^.next; End; Readln; End;

BEGIN Nhap; Gobo; In_kq; END.bài 2:

(* Chọn thêm bảng ghi vào danh sách *) Uses Crt; Const inp='C9_2.inp'; Type ptr=^rec; rec=record name: string[20]; next: ptr; End; Var f: text; k: integer; p,s,l: ptr;

Procedure Nhap;145

Page 146: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Begin Assign(f,inp); Reset(f); New(p); l:=p; While not EoF(f) do Begin Readln(f,p^.name); New(p^.next); p:=p^.next; End; p^.next:=nil; Close(f);

New(s); Clrscr; Writeln('Nhap ban ghi can chen: '); Write('Ten: '); Readln(s^.name); Write('Vi tri can chen: '); Readln(k); End;

Procedure Chen_rec; Var i: integer; Procedure Cat(Var L: ptr); Begin s^.next:=l; l:=s; End; Begin p:=l; For i:=3 to k do p:=p^.next; (* Tim vi tri *) If k>1 then Cat(p^.next) Else Cat(l); {Cat - Noi} End;

Procedure In_kq; Begin While (l^.next<>nil) do Begin Writeln(l^.name); l:=l^.next; End; Readln; End;

BEGIN Nhap; Chen_rec; In_kq; END.

bài 3:

146

Page 147: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

(* Chèn hai bảng ghi cho nhau *) Uses Crt; Const inp='C9_3.txt'; Type ptr=^rec; rec=record name: string[20]; next: ptr; End; Var f: text; j,k: integer; p,l: ptr; tenj,tenk: string;

Procedure Nhap; Begin Assign(f,inp); Reset(f); New(p); l:=p; While not EoF(f) do Begin Readln(f,p^.name); New(p^.next); p:=p^.next; End; p^.next:=nil; Close(f); Clrscr; Write('Nhap vi tri 2 ban ghi can doi cho: '); Readln(j,k); End;

Procedure Doicho; Var i: integer; Begin p:=l; For i:=2 to k do p:=p^.next; tenk:=p^.name; p:=l; For i:=2 to j do p:=p^.next; tenj:=p^.name; p:=l; For i:=2 to k do p:=p^.next; p^.name:=tenj; p:=l; For i:=2 to j do p:=p^.next; p^.name:=tenk; End;

Procedure In_kq; Begin While (l^.next<>nil) do Begin Writeln(l^.name); l:=l^.next; End; Readln; End;

147

Page 148: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

BEGIN Nhap; Doicho; In_kq; END.

bài 4:

(* Sắp xếp bảng ghi danh sách theo Name *) Uses Crt; Const inp='C9_4.txt'; Type ptr=^rec; rec=record name: string[20]; next: ptr; End; Var f: text; n,i,j: integer; p,l: ptr; teni,tenj: string;

Procedure Nhap; Begin Assign(f,inp); Reset(f); New(p); l:=p; n:=0; While not EoF(f) do Begin Readln(f,p^.name); New(p^.next); p:=p^.next; Inc(n); End; p^.next:=nil; Close(f); End;

Procedure Doicho(i,j: integer); Var k: integer; Begin p:=l; For k:=2 to i do p:=p^.next; p^.name:=tenj; p:=l; For k:=2 to j do p:=p^.next; p^.name:=teni; End;

Procedure Sapxep; Var k: integer;

148

Page 149: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Begin For i:=1 to n-1 do For j:=i+1 to n do Begin p:=l; For k:=2 to i do p:=p^.next; teni:=p^.name; p:=l; For k:=2 to j do p:=p^.next; tenj:=p^.name; If teni>tenj then Doicho(i,j); End; End;

Procedure In_kq; Begin While (l^.next<>nil) do Begin Writeln(l^.name); l:=l^.next; End; Readln; End;

BEGIN Clrscr; Nhap; Sapxep; In_kq; END.

bài 5:

Uses Crt ; Type P_TW = ^T_W; T_W = Record W : Word ; TiepTheo : P_TW; End ; Var HienTai , TamThoi : P_TW ; DauTien : Pointer ;

Procedure KhoiDongList ; Begin DauTien := Nil ; End ;

Procedure NhapLieu ;149

Page 150: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Var i : word ; Begin Writeln ('*** Nhap so 0 neu muon cham dut ***') ; i := 0 ; Repeat New(TamThoi); Inc(i); Write(' Nhap so thu ',i ,' : ') ; Readln(TamThoi^.W) ; TamThoi^.TiepTheo := Nil ; If TamThoi^.W <> 0 Then If DauTien = Nil Then Begin DauTien := TamThoi ; HienTai := TamThoi ; (* Hieän taïi ôû cuoái list *) End Else Begin HienTai^.TiepTheo := TamThoi ; HienTai := TamThoi ; (* Hieän taïi ôû cuoái list *) End ; Until TamThoi^.W = 0 ; End ;

Procedure VietDuLieu ; Begin Writeln(' Cac so da nhap : ') ; HienTai := DauTien ; While HienTai <> Nil Do Begin Write(HienTai^.W:8 ) ; HienTai := HienTai^.TiepTheo ; End ; End ;

Procedure KetThucList ; Begin If DauTien <> Nil Then Release(DauTien) ; End ;

BEGIN Clrscr ; KhoiDongList ; NhapLieu ; VietDuLieu ; KetThucList ; Readln ;

150

Page 151: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

END .

Chương 10:Bài 1:

(* Hình chữ nhật thay đổi kích thước *) Uses Crt,Graph; Var Gd,Gm,x,y: Integer; tl: real;

BEGIN Gd:=Detect; InitGraph(Gd,Gm,''); If GraphResult <> GrOk Then Halt ; tl:=GetMaxY/GetMaxX; SetFillStyle(1,4); For x:=1 to GetMaxX do Begin y:=round(x*tl); Bar((GetMaxX-x) div 2,(GetMaxY-y) div 2, (GetMaxX+x) div 2,(GetMaxY+y) div 2); Delay(10); End; CloseGraph; END.

bài 2:

(* Hình chữ nhật có kích thước điều khiển được*) Uses Crt, Graph; Var Gd,Gm,x,y: Integer; tl: real; c: char;

BEGIN Gd:=Detect; InitGraph(Gd,Gm,''); tl:=GetMaxY/GetMaxX; x:=GetMaxX div 2; y:=round(x*tl); SetFillStyle(1,4); Bar((GetMaxX-x) div 2,(GetMaxY-y) div 2, (GetMaxX+x) div 2,(GetMaxY+y) div 2); Repeat OutTextXY(0,0,'Press Esc to Exit...');

151

Page 152: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Repeat c:=ReadKey; Until c in [#27,'+','-']; SetFillStyle(1,0); Bar((GetMaxX-x) div 2,(GetMaxY-y) div 2, (GetMaxX+x) div 2,(GetMaxY+y) div 2); If (c='+')and(x<GetMaxX) then Inc(x) Else If (c='-')and(y>0) then Dec(x); y:=round(x*tl); SetFillStyle(1,4); Bar((GetMaxX-x) div 2,(GetMaxY-y) div 2, (GetMaxX+x) div 2,(GetMaxY+y) div 2); Until c=#27; CloseGraph; END.

bài 3:

(* Phạm vi kiểm soát của con Hậu *)Uses Crt,Graph;Const N=8; W=40; X=150; Y=400;Var Gd,Gm,i,Hi: Integer; j,Hj,H: char; S: String; Pattern : FillPatternType;

BEGIN Gd:=Detect; InitGraph(Gd,Gm,''); OutTextXY(270,430,'Ban co vua'); For i:=1 to N do For j:='a' to chr(Ord('a')+N-1) do Begin If Odd(i+Ord(j)) then SetFillStyle(SolidFill,14) Else SetFillStyle(SolidFill,15); Bar(X+(i-1)*W,Y-(Ord(j)-Ord('a'))*W,X+i*W,Y-(Ord(j)-Ord('a')+1)*W); End; OutTextXY(200,20,'Nhap vi tri con hau:'); Hj:=ReadKey; OutTextXY(370,20,Hj); H:=ReadKey; Hi:=Ord(H)-Ord('0'); OutTextXY(380,20,H); SetColor(4); Circle(X+(Hi-1)*W+W div 2,Y-(Ord(Hj)-Ord('a'))*W-W div 2,W div 2-5); GetFillPattern(Pattern); SetFillPattern(Pattern,4); FloodFill(X+(Hi-1)*W+W div 2,Y-(Ord(Hj)-Ord('a'))*W-W div 2,4); SetFillStyle(SolidFill,13);

152

Page 153: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

For i:=1 to N do For j:='a' to chr(Ord('a')+N-1) do If ((i<>Hi)or(j<>Hj)) and((Abs(i-Hi)=Abs(Ord(j)-Ord(Hj)))or(i=Hi)or(j=Hj)) then Bar(X+(i-1)*W,Y-(Ord(j)-Ord('a'))*W,X+i*W,Y-(Ord(j)-Ord('a')+1)*W); Readln; CloseGraph; END.

bài 4:

Uses Crt,Dos,Graph; Var h,m,s,hund: Word; GD,GM: Integer; St: String;

Function LeadingZero(w: Word): String; Var s: String; Begin Str(w:0,s); if Length(s)=1 then s:='0'+s; LeadingZero:=s; End;

BEGIN GD:=Detect; InitGraph(GD,GM,' '); SetTextStyle(DefaultFont,HorizDir,5); Repeat GetTime(h,m,s,hund); St:=LeadingZero(h)+':'+LeadingZero(m)+':'+LeadingZero(s); SetColor(15); OutTextXY(150,200,St); Delay(1000); SetColor(0); OutTextXY(150,200,St); Until KeyPressed; CloseGraph; END.

bài 4:

Uses Crt, Graph; Const r=150; v=5;

153

Page 154: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Var Gd,Gm,x0,y0,x,y: Integer; a: real; (* goùc *)

BEGIN Gd:=Detect; InitGraph(Gd,Gm,' '); x0:=GetMaxX div 2; y0:=GetMaxY div 2; PutPixel(x0,y0,4); a:=0; Repeat x:=x0+Round(r*cos(a)); y:=y0+Round(r*sin(a)); PutPixel(x,y,15); Delay(v); PutPixel(x,y,0); a:=a+0.01; Until KeyPressed; CloseGraph; END.

bài 6:

(* dieu khien vi tri cua hinh vuong *) Uses Crt, Graph; Var Gd,Gm,x,y,v: Integer; Pa,Pb: Pointer; Size: Word; c: char;

BEGIN Gd:=Detect; InitGraph(Gd,Gm,' '); Size:=ImageSize(0,0,20,20); GetMem(Pb,Size); GetImage(0,0,20,20,Pb^); GetMem(Pa,Size); Bar(0,0,20,20); GetImage(0,0,20,20,Pa^); ClearDevice; x:=300; y:=200; v:=10; c:=#77; Repeat PutImage(x,y,Pa^,NormalPut); Repeat Until KeyPressed; c:=ReadKey; If c=#0 then c:=ReadKey; PutImage(x,y,Pb^,NormalPut); Case c of

154

Page 155: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

#72: Dec(y); #75: Dec(x); #77: Inc(x); #80: Inc(y); End; If x>600 then x:=0; If x<0 then x:=600; If y>440 then y:=0; If y<0 then y:=440; Until (c=#27) or (c=#13); CloseGraph; END.

bài 7:

(* Các dạng phông chữ *) Uses Graph; Const K=3; Var Gd,Gm,Font,Color,Size,i: Integer; S: String;

BEGIN Gd:=Detect; InitGraph(Gd,Gm,' '); Color:=0; For Font:=0 to 11 do Begin ClearDevice; For i:=1 to 4 do Begin Size:=(i-1)*K+1; Inc(Color); Color:=Color mod 15+1; SetColor(Color); SetTextStyle(Font,HorizDir,Size); Str(Size,S); S:='Size '+S; OutTextXY(100,i*80,S) ; End; Readln; End; CloseGraph; END.

bài 8:

(* Vẽ đồ thị y = x *)155

Page 156: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Uses Graph; Const X0=320;Y0=300;E=50; Var Gd,Gm,i,j,k: Integer; x,y: real; S: String;

BEGIN Gd:=Detect; InitGraph(Gd,Gm,' '); Line(100,Y0,550,Y0); {Truc Ox} OutTextXY(540,Y0+10,'x'); For k:=-3 to 3 do Begin i:=k*E+X0; j:=Y0; Str(k,S); OutTextXY(i-10,j+8,S); Bar(i-1,j-1,i+1,j+1); End; Line(X0,50,X0,370); {Truc Oy} OutTextXY(X0-20,50,'y'); For k:=-1 to 4 do Begin i:=X0; j:=-k*E+Y0; Str(k,S); If k<>0 then OutTextXY(i-20,j,S); Bar(i-1,j-1,i+1,j+1); End; For i:=X0-2*E to X0+2*E do {Do thi} Begin x:=(i-X0)/E; y:=Sqr(x); j:=Round(-y*E+Y0); PutPixel(i,j,10); End; SetTextStyle(1,0,2); OutTextXY(100,400,'Do thi ham so y = Sqr(x):'); Readln; CloseGraph; END.

bài 9:

(* To mau Ngoi nha *) Uses Crt,Graph; Var Gd,Gm: Integer; Pattern : FillPatternType; c: Char;

156

Page 157: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

BEGIN Gd:=Detect; InitGraph(Gd,Gm,' '); GetFillPattern(Pattern); OutTextXY(120,50,'To mau Ngoi nha:'); Rectangle(220,200,420,330); Rectangle(250,230,300,330); Rectangle(330,230,390,280); MoveTo(220,200); Lineto(180,200); Lineto(220,140); Lineto(420,140); Lineto(460,200); Lineto(420,200); SetFillPattern(Pattern,Blue); Floodfill(0,0,White); SetFillPattern(Pattern,4); Floodfill(320,190,White); SetFillPattern(Pattern,8); Floodfill(320,220,White); Repeat Repeat c:=ReadKey; Until c in [#27,'+','-']; If (c='+') then SetFillPattern(Pattern,14) Else If (c='-') then SetFillPattern(Pattern,0);; Floodfill(270,300,White); Floodfill(370,270,White); Until c=#27; CloseGraph; END. (*******************************************************************)

Cú pháp { $A+ } hoặc { $A- }

M ặ c đị nh { $A+ } bật chế độ bố trí theo word để chạy nhanh .

Ki ể u Global : có ảnh hưởng tới toàn bộ quá trình dịch .

Ghi chú Định hướng $A chọn một trong hai cách bố trí các biến và các hằng định kiểu với đơn vị theo byte hoặc theo word

Trong tr Trong trạạng thái { $A+ } , tng thái { $A+ } , tấất ct cảả bi biếến và hn và hằằng ng địđịnh kinh kiểểu có kích thu có kích thướước lc lớớn hn hơơn mn mộột byte t byte đềđều u đượđược bc bốố trí theo m trí theo mộột t đơđơn vn vịị word . N word . Nếếu cu cầần , nhn , nhữững byte vô ích sng byte vô ích sẽẽ đượđược chèn vào c chèn vào gigiữữa bia biếến n đểđể th thựực hic hiệện vin việệc bc bốố trí . trí . ĐĐiiềều này cu này cũũng có nghng có nghĩĩa là ta ta là ta tốốn mn mộột ít bt ít bộộ nh nhớớ đểđể làm làm viviệệc chèn thêm byte vô ích này . c chèn thêm byte vô ích này . ĐịĐịnh hnh hướướng { $A+ } không ng { $A+ } không ảảnh hnh hưởưởng tng tớới các bii các biếến có kích n có kích ththướước tính theo byte cc tính theo byte cũũng nhng nhưư không không ảảnh hnh hưởưởng tng tớới các tri các trườường cng củủa ba bảản ghi và các phn ghi và các phầần tn tửử

157

Page 158: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

ccủủa ma mảảng . Mng . Mộột trt trườường trong bng trong bảản ghi sn ghi sẽẽ đượđược bc bốố trí theo word ch trí theo word chỉỉ n nếếu kích thu kích thướước tc tổổng ng ccộộng cng củủa ta tấất ct cảả các tr các trườường trng trướước c đđó là chó là chẵẵn . n . ĐốĐối vi vớới mi mỗỗi phi phầần tn tửử c củủa ma mảảng ng đểđể b bốố trí trí theo word kích ththeo word kích thướước cc củủa ma mỗỗi hi hầần tn tửử c cũũng phng phảải là chi là chẵẵn .n .

Trong trạng thái { $A- } , không có một biện pháp bố trí nào được dùng . Các biến và hằng định kiểu được thay thế một cách đơn giản tại các địa chỉ một cách liên tục bất chấp kích thước của chúng .

B Bấất cht chấấp trp trạạng thái ng thái địđịnh hunh huớớng cng củủa $A , ma $A , mỗỗi phi phầần khai báo Var hon khai báo Var hoặặc Const toàn cc Const toàn cụục c đềđều u luôn bluôn bắắt t đầđầu u ởở địđịa cha chỉỉ tính theo word . T tính theo word . Tươương tng tựự , ch , chươương trình dng trình dịịch luôn gich luôn giữữ con tr con trỏỏ Stack Stack theo theo đơđơn vn vịị word b word bằằng cách bng cách bốố trí thêm m trí thêm mộột byte không st byte không sửử d dụụng trong mng trong mộột khuôn Stack ct khuôn Stack củủa a các thcác thủủ t tụục nc nếếu có yêu cu có yêu cầầu . u .

BOOLEAN EVALUATION SWITCH

Cú pháp { $B+ } hoặc { $B- }

M ặ c đị nh { $B+ } tính biểu thức Boolean một cách đầy đủ .

Ki ể u Local Ghi chú Định hướng $B chuyển trạng thái bật/tắt giữa hai mô hình khác nhau của

bộ mã sinh mã đối với các toán tử AND và OR . Trong trạng thái { $B+ } , chương trình tạo ra mã để tính toán biểu thức Boolean một cách đầy đủ . Điều này có nghĩa là mọi toán hạng của biểu thức Boolean của phép toán AND và OR sẽ được bảo đảm là tính hết , thậm chí khi kết quả của toàn bộ biểu thức đã được biết , đã được tính xong . Thí dụ với biểu thức :

( 0 AND X ) AND Y

luôn luôn bluôn luôn bằằng 0 vng 0 vớới mi mọọi X và Y . Song vi X và Y . Song vớới { $B+ } , máy tính si { $B+ } , máy tính sẽẽ tính h tính hếết mt mọọi phép toán i phép toán trên , không ntrên , không nềề hà lãng phí th hà lãng phí thờời gian .i gian .

Trong trạng thái { $B- } , chương trình dịch tạo ra mã để tính nhanh biểu thức Boolean , nghĩa là quá trình tính biểu thức Boolean sẽ dừng lại ngay sau khi kết quả của biểu thức Boolean đã trở nên hiển nhiên , không cần phải tính thêm nữa .

DEBUG IMFORMATION SWITCH

Cú pháp { $D+ } hoặc { $D- }

M ặ c đị nh { $D+ } lập các thông tin gỡ rối .

Ki ể u Global

158

Page 159: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Ghi chú Định hướng dịch $D có thể thiết lập hoặc không thiết lập các thông tin gỡ rối ( debug ) . Thông tin này bao gồm bảng dòng đánh số cho mỗi thủ tục , nó ánh xạ địa chỉ mã với các số của dòng văn bản nguồn . Đối với các Unit , thông tin gỡ rối ( debug ) được ghi ở trong tệp TPU cùng với các mã OBJ của unit . Thông tin gỡ rối làm tăng nhanh kích thước của các tệp TPU và bố trí thêm cả những chỗ khi dịch các chương trình có dùng unit , song nó không làm ảnh hưởng tới kích thước cũng như tốc độ của chương trình đã được dịch ra để chạy . Khi một chương trình hay một unit được dịch với { SD+ } , bộ gỡ rối nằm trong môi trường khép kín IDE cho phép bạn chạy chương trình từng bước một ( step by step ) và thiết lập điểm dừng trong modun đó . Các lựa chọn Debug đứng một mình ( Option | Debugger ) và tệp bản đồ ( Option | Linker ) tạo ra các thông tin về dòng một cách đầy đủ đối với một modun đã cho chỉ khi bạn đã dịch modun đó với { $D+ ) . Định hướng $D thường được sử dụng để liên kết với định hướng $L là định hướng cho phép hoặc không cho phép việc tạo ra các thông tin về kí hiệu cục bộ để gỡ rối . Nếu bạn muốn sử dụng Turbo Debuger để gỡ rối chương trình của bạn, hãy thiết lập Compiler | Destination to Disk , sau đó chọn Option | Debugger và lựa chọn Standalone .

DEFINE DIRECTIVE CONDITIONAL COMPILATION

Cú pháp { $DEFINE Name }

Ghi chú Định nghĩa một kí hiệu điều kiện với một tên . Kí hiệu tên này được nhận biết cho phần dịch còn lại của modun và được định nghĩa cho đến khi xuất hiện định hướng { $UNDEF Name } .

Ví d ụ Ví dụ này chung cho cả các định hướng { $ELSE } , { $IFDEF } ,

{ $ENDIF } .

{ $DEFINE Hoi_Dap } (* Định nghĩa tên Hoi_Dap *)

. . .

{ $IFDEF Hoi_Dap }(* Nếu có định nghĩa Hoi_Dap thì chương trình dịch sẽ dịch phần mã nguồn tiếp theo đây cho đến khi có { $ELSE } hoặc { $ENDIF Hoi_Dap } *)

Write(‘ Cho X = ‘) ;Readln ( X ) ;. . .

159

Page 160: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

{ $ELSE }(* Chương trình dịch sẽ dịch phần mã nguồn tiếp theo đây cho đến { $ENDIF Hoi_Dap } nếu không có định nghĩa Hpi_Dap , tức là bỏ hoặc đổi tên trong định hướng { $DEFINE } ở trên *)

Readln ( X ) ;. . .

{ $ENDIF } (* Kết thúc điều kiện dịch với định nghĩa DEFINE*)

ELSE DIRECTIVE CONDITIONAL COMPILATION

Cú pháp { $ELSE }

Ghi chú Bật tắt giữa việc dịch hay bỏ qua văn bản nguồn ngăn cách bởi các định hướng { $IF xxx } và định hướng kế tiếp { $ENDIF } .

Ví d ụ Xem ở mục DEFINE ở trên .

EMULATION SWITCH

Cú pháp { $E+ } hoặc { $E- }

M ặ c đị nh { $E+ }

Ki ể u Global

Ghi chú Định hướng dịch $E thiết lập hay không việc kết nối với thư viện thời gian thực và phỏng tạo bộ đồng sử lý số học 80 x 87 nếu như bộ đồng sử lý này không có trong máy . Khi bạn dịch một chương trình với { $N+, E+ } , Turbo Pascal sẽ liên kết với một bộ phỏng tạo 80 x 87 đầy đủ . Tệp EXE nhận được có thể được dùng trên mọi máy bất kể có bộ đồng xử lý trên máy hay không . Nếu thấy co 80 x 87 , Turbo Pascal sẽ sử dụng bộ đồng xử lý , còn nếu không thì thư viện thực sẽ phỏng tạo nó để chạy ( lấy phần mềm thay cho phần cúng ) . Trong trạng thái { $N+, E- } , Turbo Pascal tạo ra một chương trình chỉ có thể chạy được nếu như có bộ đồng xử lý số học . Chuyển mạch bật/tắt bộ phỏng tạo cho 80 x 87 không đem lại kết quả nếu nó được sử dụng trong unit , nghĩa là nó chỉ được áp dụng cho việc dịch của một chương trình chính . Thêm nữa nếu chương trình và tất cả các unit của chương trình được dịch với trạng thái { $N- } thì thư viện thời gian thực cho 80 x 87 không được yêu cầu và việc chuyển mạch cho bộ phỏng tạo 80 x 87 sẽ bị bỏ qua .

160

Page 161: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

ENDIF DIRECTIVE CONDITIONAL COMPILATION

Cú pháp { $ENDIF }

Ghi chú Kết thúc phần dịch có điều kiện được viết tắt bởi { IF xxx ) . Ví d ụ Xem ở mục DEFINE ở trên .

EXTENDED SYNTAX SWITCH

Cú pháp { $X+ } hoặc { $X- }

M ặ c đị nh { $X+ }

Ki ể u Global

Ghi chú Định hướng dịch $X chuyển bật / tắt giữa cú pháp mở rộng của Turbo Pascal .

Các câu lệnh hàm . Trong chế độ { $X+ } , các lời gọi hàm có thể được thực hiện như một thủ tục , nghĩa là kết quả của một lời gọi hàm có thể được hủy bỏ . Nói chung các tính toán được thực hiện bằng một hàm có thể được biểu diễn qua kết quả của nó , vì vậy việc hủy bỏ kết quả là một điều nhạy cảm nhỏ . Tuy nhiên trong một số trường hợp , một hàm có thể thực hiện nhiều thao tác căn cứ vào tham số của nó , và một số trường hợp này lại không tạo ra những kết quả hữu ích . Trong các trường hợp như thế , sự mở rộng { $X+ } cho phép hàm được xử lý như là một thủ tục . Các xâu kết thúc bằng kí tự Null . Một định hướng dịch { $A+ } cho phép sự hổ trợ sử dụng các xâu Null bằng cách kích hoạt các quy tắc đặc biệt để áp dụng cho kiểu Pchar

FORCE FAR CALLS SWITCH

Cú pháp { $F+ } hoặc { $F- }

M ặ c đị nh { $F- } tự động chọn cách gọi xa – gần .

Ki ể u Local

Ghi chú Định hướng dịch $F xác định kiểu gọi thủ tục và hàm sẽ được áp dụng . Các thủ tục và hàm được dịch trong trạng thái { $F+ } luôn luôn sử dụng cách gọi xa ( Far Call ). Trong trạng thái { $F- } ,Turbo Pascal tự động chọn các mô hình thích hợp , nghĩa là gọi xa nếu thủ tục và hàm được khai báo trong phần Interface của một Unit , các trường hợp còn lại máy sẽ chọn cách gọi gần ( Near Call ) .

161

Page 162: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

GENERATE 80286 CODE SWITCH

Cú pháp { $G+ } hoặc { $G- }

M ặ c đị nh { $G- }

Ki ể u Global

Ghi chú Định hướng $G chuyển trạng thái cho việc tạo hay không tạo mã cho 80266 . Trong trạng thái { $G- } , chỉ có các lệnh cho 8086 được tạo ra và chương trình được dịch ra trong trường hợp này có thể chạy trên mọi họ máy 80 x 86 . Bạn có thể viết chỉ dẫn { $G- } ở bất kì chỗ trống nào trong chương trình của bạn .

Trong trạng thái { $G+ } , chương trình dịch dùng thêm các cấu trúc lệnh của 80286 để cải thiện việc tạo mã lệnh , song chương trình được dịch ra trong trạng thái này sẽ không thể chạy với các bộ vi xử lý 8088 và 8086 . Các lệnh bổ sung thêm được sử dụng trong trạng thái { $G+ } bao gồm : Enter , Push , Leave tức thời , IMUL mở rộng và SHR , SHL mở rộng .

IFDEF DIRECTIVE CONDITIONAL COMPILATION

Cú pháp { $IFDEF Name }

Ghi chú Dịch văn bản nguồn theo sau nó nếu có Name được định nghĩa qua { $DEFINE }

Ví d ụ : Xem ở mục DEFINE ở trên .

IFNDEF DIRECTIVE CONDITIONAL COMPILATION

Cú pháp { $IFNDEF Name }

Ghi chú Dịch văn bản nguồn theo sau nó nếu không có Name được định nghĩa . Đây là trường hợp ngược lại với cách viết { $IFDEF } .

Ví d ụ : Xem ở mục DEFINE ở trên .

IFOPT DIRECTIVE CONDITIONAL COMPILATION

Cú pháp { $IFOPT Switch }

162

Page 163: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Ghi chú Dịch văn bản nguồn theo sau nó nếu Switch name trong trạng thái được nêu ra . Switch bao gồm tên của chuyển mạch bật/tắt và theo sau là dấu – hay dấu + . Ví dụ cấu trúc :

{ $IFOPT N+ } Type Real = Extended ;{ $ENDIF }

sẽ dịch khai báo kiểu $N đang hoạt động .

INCLUDE FILE PARAMETER

Cú pháp { $I FileName }

Ki ể u Local

Ghi chú Định hướng tham số $I chỉ dẫn cho chương trình dịch gộp lấy tệp FileName nằm ở bên ngoài chương trình nguồn đang dịch vào trong quá trình dịch . Phần mở rộng ngầm định cho tệp FileName là đuôi .Pas . Nếu FileName không chỉ rõ đường dẫn thư mục thì nó sẽ tìm trong thư mục hiện hành , sau đó Turbo Pascal sẽ tìm trong thư mục được nêu ra trong hộp thoại

Option | Directories | Include Directories Có một hạn chế trong việc sử dụng tệp gộp vào : một tệp được gộp

không thể được đặt ở giữa phần câu lệnh . Trên thực tế tất cả các câu lệnh nằm giữa Begin và End phải tồn tại trong cùng một tệp nguồn .

INPUT / OUTPUT CHECKING WITCH

Cú pháp { $I+ } hoặc { $I- }

M ặ c đị nh { $I+}

Ki ể u Local

Ghi chú Định hướng chuyển mạch bật / tắt cho phép tạo hoặc không việc tạo mã tự động để kiểm tra kết quả một lời gọi thủ tục vào / ra . Nếu thủ tục vào ra trả lại kết quả IOResult là khác 0 trong trạng thái { $I+ } , chương trình sẽ tự động dừng lại với thông báo Runtime Error . Trong trạng thái { $I- } , tức chuyển mạch này sang tắt ( off ) , thì máy sẽ không thông báo lỗi và bạn phải tự kiểm tra lỗi vào / ra bằng lời gọi IOResult .

163

Page 164: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

LINK OBJECT FILE SWITCH

Cú pháp { $L FileName }

Ki ể u Local

Ghi chú Định hướng tham số $L chỉ dẫn cho chương trình dịch liên kết tệp FileName với chương trình hoặc Unit đang được dịch . Định hướng $L được dùng để liên kết mã chương trình được viết bằng hợp ngữ cho chương trình con được miêu tả External . Tệp được đặt tên phải là moat tệp .OBJ . Nếu FileName không chỉ rõ đường dẫn thì nó sẽ tìm kiếm trong thư mục hiện hành , sau đó là trong thư mục được chỉ rõ trong hộp thoại Options | Directories | Object Directories .

LOCAL SYMBO INFORMATION SWITCH

Cú pháp { $L+ } hay { $L- }

M ặ c đị nh { $L+ }

Ki ể u Local

Ghi chú Kí hiệu $L dùng để bật / tắt việc tạo ra thông tin kí hiệu cục bộ . Thông tin này bao gồm các tên và kiểu của tất cả các biến và hằng trong modun , nghĩa là các kí hiệu trong phần Implementation của modun đó , và các kí hiệu bên trong các thủ tục và hàm của modun đó .

V Vớới Unit , thông tin hii Unit , thông tin hiệệu cu cụục bc bộộ đượđược ghi vào tc ghi vào tệệp .TPU vp .TPU vớới mã i mã đốđối ti tượượng ng ccủủa Unit . Thông tin kí hia Unit . Thông tin kí hiệệu cu cụục bc bộộ làm t làm tăăng kích thng kích thướước tc tệệp .TPU và tp .TPU và tạạo thêm cho thêm chỗỗ trtrốống khi dng khi dịịch chch chươương trình dùng Unit ng trình dùng Unit đđó , song nó không ó , song nó không ảảnh hnh hưởưởng tng tớới kích i kích ththướước cc cũũng nhng nhưư t tốốc c độđộ c củủa cha chươương trình chng trình chạạy cuy cuốối cùng . i cùng .

Khi moat chương trình hay Unit được dịch với { $L+ } , chương trình gỡ rối nằm trong Turbo Pascal cho phép bạn xem , kiểm tra và thay đổi các biến cục bộ của modun . Thêm nữa , có thể kiểm tra lời gọi những thủ tục và hàm của modun qua View | Call Stack . Việc gỡ rối độc lập ( Option | Debugger ) và lựa chọn tệp bản đồ ( Map File ) với Option | Linker sẽ tạo ra thông tin kí hiệu địa phương cho modun chỉ nếu nó được dịch trong trạng thái { $L+ } .

Định hướng $L thường được dùng với định hướng $D là định hướng thiết lập hay không thiết lập việc tạo ra bảng đánh số dòng để gở rối .Định hướng $L bị bỏ qua nếu chương trình dịch đang trong trạng thái { $D- } .

164

Page 165: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

MEMORY ALLOCATION PARAMETER

Cú pháp { $M StackSize , HeapMin , HeapMax } }

M ặ c đị nh { $M 16384 , 0 , 655360 }

Ki ể u Local

Ghi chú Định hướng $M chỉ rõ các tham số bố trí bộ nhớ của chương trình ứng dụng . Kích thước Stack phải nằm trong khoảng 1024 và 65520 , đó là kích thước Segmen của Stack . HeapMin , HeapMax chỉ ra giá trị cực đại và cực tiểu tương ứng của bộ nhớ biến động ( Heap ) . HeapMin phải nằm giữa khoảng 0 và 655360 còn HeapMax nằm giữa HeapMin cho tới 655360 .

Định hướng $M không có kết quả nếu nó được sử dụng trong Unit .

NUMERIC COPROCESSOR SWITCH

Cú pháp { $N+ } hoặc { $N- }

M ặ c đị nh { $N- } Ki ể u Local

Ghi chú Định hướng $N bật / tắt giữa hai chế độ khác nhau của việc sinh mã dấu chấm động của Turbo Pascal . Trong trạng thái { SN- } , mã được tạo ra để thực hiện mọi tính toán bằng số thực trong phần mềm bằng cách gọi tới thư viện thời gian thực . Còn trong trạng thái { $N+ } , mã được tạo ra để tính toán mọi kiểu số thực bằng bộ đồng xử lý toán học 80 x 87 .

OPEN STRING PARAMETER SWITCH

Cú pháp { $P+ } hoặc { $P- }

M ặ c đị nh { $P- } Ki ể u Local

Ghi chú Định hướng $P điều khiển ý nghĩa của tham biến được khai báo với từ khóa String . Trong trạng thái { $P- } , các tham biến được khai báo dùng từ khoá String là các tham biến bình thường nhưng trong trạng thái { $P+ } , chúng là tham số String mở . Không liên quan gì đến trạng thái thiết lập của $P , tên OpenString luôn luôn được sử dụng để khai báo các tham số mở .

165

Page 166: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

OVERFLOW CHECKING SWITCH

Cú pháp { $Q+ } hoặc { $Q- }

M ặ c đị nh { $Q- } Ki ể u Local

Ghi chú Định hướng $Q điều khiển việc tạo mã để kiểm tra tràn . Trong trạng thái { $Q+ } , một số lệnh toán học với số nguyên ( + , - , * , / , Abs , Sqr , Succ , Pred ) được kiểm tra xem có tràn không . Mã của mỗi lệnh số nguyên được thêm một phần để kiểm tra xem kết quả có nằm trong khoảng giá trị cho phép . Nếu gặp hiện tượng tràn nó sẽ dừng chương trình và báo lỗi { $Q+ } không ảnh hưởng tới thủ tục chuẩn Dec và Inc . Những thủ tục này không bao giờ được kiểm tra tràn . Chuyển mạch $Q thường được dùng với chuyển mạch $R là chuyển mạch thiết lập hoặc không thiết lập việc tạo ra mã kiểm tra khoảng giá trị . Việc kiểm tra tràn sẽ làm cho chương trình của bạn chạy chậm hơn và kích thước chương trình lớn hơn một chút . Do đó chỉ nên dùng { $Q+ } cho việc gỡ rối .

OVERLAY CODE GENERATION SWITCH

Cú pháp { $O+ } hoặc { $O- }

M ặ c đị nh { $O- } Ki ể u Local

Ghi chú Định hướng $O dùng để bật / tắt việc tạo mã phủ . Turbo Pascal cho phép một Unit chỉ được phủ nếu nó đã được dịch với { $P+ } . Trong trạng thái này , bộ phận tạo mã có một số biện pháp ngăn ngừa đặc biệt khi chuyển tham số String và hằng tập từ một thủ tục hay hàm được phủ tới một thủ tục / hàm khác . Sử dụng { $O+ } trong một Unit không bắt buộc bạn phải phủ Unit đó . Nó chỉ hướng dẫn Turbo Pascal bảo đảm chắc rằng Unit đó có thể được phủ nếu bạn muốn . Nếu bạn muốn phát triển các Unit để sau này cho các ứng dụng có phủ cũng như không phủ , việc dịch chúng với $O+ sẽ đảm bảo với bạn là bạn có thể tạo ra cả 2 phiên bản trong cùng một chương trình nguồn . Định hướng chương trình dịch { $O+ } thường được dùng với định hướng { $F+ } để thỏa mãn việc quản lý bao phủ cho những yêu cầu gọi xa .

166

Page 167: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

OVERLAY UNIT NAME PARAMETER

Cú pháp { $O UnitName } Ki ể u Local

Ghi chú Định hướng tên đơn vị phủ ( Overlay Unit Name ) bật một Unit vào trong một chương trình phủ Định hướng { $O UnitName ) không có tác dụng nếu nó được sử dụng trong một Unit . Khi dịch một chương trình , nó chỉ ra Unit nào được chương trình sử dụng phải được đặt trong tệp .OVR thay vì trong tệp .EXE . Các định hướng { $O UnitName } phải được đặt sau phần Uses của chương trình . Pascal sẽ thông báo lỗi nếu bạn cố tình phủ một Unit không được dịch với { $O+ } .

RANGE CHECKING SWITCH

Cú pháp { $R+ } hoặc { $R- }

M ặ c đị nh { $R- } Ki ể u Local

Ghi chú Định hướng $R dùng để bật / tắt việc tạo mã kiểm tra dải giá trị , nghĩa là xem giá trị đó có nằm trong khoảng cho phép hay không . Trong trạng thái { $R+ } , tất cả các biểu thức mảng và chỉ số chuỗi đều được thẩm tra dải giá trị và tất cả các phép gán cho các biến vô hướng và biến khoảng con cũng đều được kiểm tra dải giá trị . Nếu việc kiểm tra thấy sai , nó sẽ ngừng chương trình lại và thông báo lỗi . Nếu $R được bất , mọi lời gọi tới các hành vi ảo đều được kiểm tra đối với tình trạng khởi tạo của cá thể gọi . Nếu cá thể gọi không được khởi tạo bằng Contructor của nó , máy sẽ báo lỗi kiểm tra giá trị . Bật kiểm tra dải giá trị và kiểm tra lời gọi hành vi ảo sẽ làm chậm chương trình của bạn và làm tăng kích thước của chương trình , vì vậy chỉ dùng { $R+ } để gỡ rối .

STACK-OVERFLOW CHECKING SWITCH

Cú pháp { $S+ } hoặc { $S- }

M ặ c đị nh { $S+ }

167

Page 168: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Ki ể u Local

Ghi chú Định hướng $S thiết lập hay không thiết lập việc tạo ra mã kiểm tra tràn của Stack . Trong trạng thái { $S+ } , chương trình tạo ra mã ở đầu mỗi thủ tục hay hàm để kiểm tra xem không gian Stack có đủ để lưu trữ biến địa phương và các việc lưu trữ tạm thời khác . Khi không đủ không gian Stack thì một lời gọi tới hàm hay thủ tục được dịch với { $S+ } sẽ dẫn đến dừng chương trình và xuất hiện thông báo lỗi . Trong trạng thái { $S- } , một lời gọi như vậy sẽ làm cho hệ thống bị hỏng .

SYMBO REFERENCE SWITCH

Cú pháp { $Y+ } hoặc { $Y- }

M ặ c đị nh { $Y+ } Ki ể u Local

Ghi chú Định hướng $Y dùng để bật / tắt việc tạo ra thông tin tham khảo các kí hiệu . Thông tin này bao gồm những bảng cung cấp số dòng của tất cả các khai báo , các kí hiệu và các tham khảo tới những kí hiệu trong một modun .

Đối với Unit , thông tin tham khảo kí hiệu được ghi trong tệp .TPU với mã đối tượng của Unit. Thông tin tham khảo kí hiệu làm tăng kích thước của tệp .TPU nhưng không ảnh hưởng tới tốc độ và kích thước của chương trình được dịch ra để chạy . Khi một chương trình hay một Unit được dịch với { $Y+ } , bộ xem và duyệt của Turbo Pascal có thể hiển thị định nghĩa kí hiệu và thông tin tham khảo cho modun đó . $Y thường được dùng cùng với $D và$L , là các định hướng điều khiển việc tạo ra các thông tin gỡ rối và thông tin kí hiệu cục bộ . Định hướng $Y không có tác dụng trừ khi cả hai $D và $L được thiết lập .

TYPE-CHECKING POINTERS SWITCH

Cú pháp { $T+ } hoặc { $T- }

M ặ c đị nh { $T- } Ki ể u Global

Ghi chú Định hướng $T điều khiển các kiểu dữ liệu con trỏ được tạo ra từ toán tử @ . Trong trạng thái { $T- } , kết quả của toán tử @ luôn là con trỏ . Nói cách khác kết quả là kiểu con trỏ không định kiểu sẽ tương thích với mọi kiểu con trỏ khác .Khi @ được áp dụng cho một biến trong trạng thái { $T+

168

Page 169: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

} , kiểu của kết quả là ^T trong đó T là kiểu của biến . Nói cách khác , kết quả là một kiểu chỉ tương thích với các con trỏ khác trỏ tới kiểu của biến .

UNDEF DIRECTIVE CONDITIONAL COMPILATION

Cú pháp { $UNDEF Name }

Ghi chú Không định nghĩa hay làm mất tác dụng một kí hiệu điều kiện đã được định nghĩa trước đây . Kí hiệu sẽ bị bỏ quên với phần còn lại của quá trình dịch hoặc cho tới tận khi nào xuất hiện trở lại trong địng hướng { $DEFINE Name } . Định hướng { UNDEF Name } không có ảnh hưởng gì nếu Name chưa được định nghĩa .

VAR-STRING CHECKING SWITCH

Cú pháp { $V+ } hoặc { $V- }

M ặ c đị nh { $V+ } Ki ể u Local

Ghi chú Định hướng $V điều khiển việc kiểm tra kiểu trên String được chuyển qua thủ tục / hàm như là tham số . Trong trạng thái { $V+ } , việc kiểm tra kiểu chính xác hoàn toàn được thực hiện , nghĩa là giữa tham số hình thức và tham số thực sự phải đồng nhất giống nhau về kiểu .

Trong trạng thái { $V- } , còn được gọi là trạng thái buông lỏng , bất kì biến kiểu String nào cũng đều được phép chuyển qua như một tham số String thực sự ngay cả khi nếu chiều dài cực đại được khai báo không giống với tham số hình thức .

Trạng thái { $V- } chủ yếu cung cấp một phiên bản không an toàn của những tham số String mở . Mặc dầu { $V- } vẫn còn được ủng hộ , bạn hãy dùng những tham số chuỗi mở . (*************************************************************)

 

 

169

Page 170: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Các kí tự được mã hoá bằng một byte, vì vậy bảng mã kí tự có thể mã hóa tới 256 kí tự. Tuy vậy số kí tự cơ bản nhất có thể gói gọn lại trong 128 kí tự đầu và được chuẩn hoá. Còn 128 kí tự sau (các kí tự có số thứ tự từ 128 đến 255) trên máy vi tính được gọi là phần mã mở rộng và được dùng để mã hóa các kí tự riêng của một số ngôn ngữ, các kí tự toán học, các kí tự đồ họa... Có nhiều bảng mã khác nhau ở phần mở rộng, ở đây chúng ta quan tâm chủ yếu tới phần 128 kí tự đầu của bảng mã ACSII là phần chuẩn để xây dựng bộ kí tự cho ngôn ngữ lập trình.

  Bảng 1.2: Bảng mã ASCII với 128 kí tự đầu

 Trong bảng mã ASCII, các kí tự từ 0 đến 31 là các kí tự điều khiển, không in ra được, dùng để

điều khiển các thiết bị ngoại vi, điều khiển các thủ tục trao đổi thông tin. Ví dụ khi thiết bị nhận kí tự số 7 (Bel), máy sẽ ra một tiếng chuông. Kí tự số 27 (Esc) cũng thường dùng để thoát khỏi các tình huống, để nhận biết các mã đặc biệt khác như điều khiển máy in bằng dãy kí tự bắt đầu là Esc...

Phần còn lại trong bảng mã ACSII bố trí toàn bộ các chữ cái A, B, C..., các chữ số từ 0 đến 9, các dấu chấm câu, các kí tự đặc biệt... Ví dụ khi nhận kí tự số 50 máy sẽ hiện lên màn hình chữ số 2.

170

Page 171: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

Riêng kí tự 127 (Del) lại được dùng làm kí tự điều khiển xóa. Nếu bạn dùng Editor, phím Del trên màn hình chính là phím tạo ra mã số 127 để xóa một kí tự trên màn hình.

Bạn có thể tham khảo thêm 128 kí tự sau của bảng mã ASCII được đề cập tới trong trong bảng 1.2.

 

Bảng 1.2: Bảng mã ASCII với 128 kí tự đầu  

171

Page 172: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

  

   

1. Bảng các hằng biểu diễn màu: Mỗi vĩ đồ họa và mỗi chế độ đồ họa đều cho phép vẽ với một số màu khác nhau. Các màu này đã được Turbo Pascal đặt tên cho dễ nhớ thay vì phải dùng các mã số. Các hằng mô tả màu và giá trị tương ứng của nó được liệt kê trong bảng sau :  

Hằng Giá trị

Black Đen 0

Blue Xanh 1

Green Xanh lá cây 2

Cyan Xanh cẩm thạch 3

Red Đỏ 4

Magenta Tía 5

Brown Nâu 6

LightGray Xám nhẹ 7

DarkGray Xám đậm 8

LightBlue Xanh nhạt 9

LightGreen Xanh lá cây nhạt 10

LightCyan Xanh cẩm thạch nhạt 11

LightRed Hồng 12

LightMagenta Tía nhạt 13

Yelow Vàng 14

White Trắng 15

Bảng 2.1 Bảng các hằng biểu diễn màu    2.  Bảng các hằng biểu diễn mẫu tô:

 

Hằng Giá trị EmptyFill Màu nền 0

SolidFill Tô màu đặc 1

LineFill Mẫu tô --- 2

LtSlashFill Mẫu tô /// 3

SlashFill Mẫu tô /// (nét nhỏ) 4

BkSlashFill Mẫu tô \\\ (nét dày) 5

LtBkSlashFill Mẫu tô \\\ 6

172

Page 173: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

HatchFill Nét chải thưa 7

XHatchFill Nét chải dày 8

InterLeaveFill Các đường xen kẽ 9

WideDotFill Chấm thưa 10

CloseDotFill Chấm dày 11

UserFill Tô theo mẫu người dùng 12

Bảng 2.2 Bảng các hằng biểu diễn mẫu tô   

    Ngoài các phím kí tự bình thường ra (chữ cái, chữ số), bàn phím máy vi tính còn có rất nhiều phím mở rộng khác như các phím chức năng F1,..., F10, các phím dịch chuyển con trỏ, các tổ hợp phím... Bạn cần khai thác hết sự phong phú của những phím mở rộng này. Bản chất của vấn đề là khi đọc một phím mở rộng, máy sẽ nhận hai mã, và mã thứ nhất luôn có giá trị là #0. Khi này ta phải đọc thêm mã thứ hai để biết rõ các phím mở rộng nào được nhấn bằng cách dùng hàm Readkey.

  Mã thứ hai Phím ấn

3 15

16 – 25 30 – 38 44 – 50 59 – 68

71 72 73 75 77 79 80 81 82 83

84 – 93 94 – 103 104 – 113

114 115 116 117 118 119

120 - 131 132 133 134 135

NUL (Nul Character) Shift – Tab Alt – Q/W/E/R/T/Y/U/I/O/P Alt – A/S/D/F/G/H/J/K/L Alt – Z/X/C/V/B/N/M Phím chức năng F1 – F10 Home Up Arrow ( ) PgUp Left Arrow (¬) Right Arrow ( ® ) End Down Arrow ( ¯ ) PgDn Ins Del Từ Shift–F1 tới Shift–F20 Từ Ctrl–F1 tới Ctrl–F20 Từ Alt–F1 tới Alt–F20 Ctrl – PtrScr Ctrl – Left Arrow Ctrl – RightArrow Ctrl – End Ctrl – PgDn Ctrl – Home Alt – 1/2/3/4/5/6/7/8/9/0/-/= Ctrl – PgUp F11 F12 Shift - F11

173

Page 174: Huong Dan Hoc PasCal

Mai Xuaân Vieät - Tröôøng THPT Soá II Moä Ñöùc - Lôùp 11A - Chöông trinh hoïc Pascal

136 137 138 139 140

Shift - F12 Ctrl - F11 Ctrl – F12 Alt – F11 Alt – F12

Bảng 3 : Bảng mã phím mở rộng     

---------------------------------------------------------------------------------------------------------------------(Nếu có thắc mắc gì xin liên hệ qua số ĐT : 01678336358 hoặc qua email : [email protected].)

174