Giáo trình Lập trình cấu trúc Pascal

pdf 91 trang Gia Huy 17/05/2022 2170
Bạn đang xem 20 trang mẫu của tài liệu "Giáo trình Lập trình cấu trúc Pascal", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfgiao_trinh_lap_trinh_cau_truc_pascal.pdf

Nội dung text: Giáo trình Lập trình cấu trúc Pascal

  1. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Lời nói đầu! Ngôn ngữ Pascal do giáo sư N. Wirth đưa ra năm 1970, là một ngôn ngữ có cấu trúc, thường dùng để giảng dạy cho Sinh viên và Học sinh khi mới bước vào lĩnh vực học lập trình. Chúng ta học Pascal bởi 3 lý do sau: · Ngôn ngữ Pascal hiện ở Việt nam vẫn đang phổ biến · Tạo cho người học một tác phong "kỷ luật lập tr ình" cấu trúc · Làm quen với một số dữ liệu, đặc biệt là dữ liệu có cấu trúc giúp cho người học tiếp tục tìm hiểu tiếp C ++, Visual Basic và Java ở những giáo trình sau. Đây là phần cơ bản nhất, giáo trình không được vào phần cấp phát động và hướng đối tượng bởi vì: thứ nhất số trình về học phần này không nhiều; thứ 2 là trong C ++ và Java sẽ được dạy ở những học kỳ sau có chứa đựng 2 nội dung đó; thứ ba là vì tác giả muốn nhấn mạnh tư tưởng “Lập trình cấu trúc” nên không muốn làm “loãng” ra. Giáo trình này chạy trên các phiên bản của Turbo Pascal 5.0, 5.5, 6.0 v à 7.0. Tất nhiên cũng cần phải nói thêm là Turbo Pascal 7.0 có gây lỗi trên những bộ vi xử lý Pentium II, III, v.v có tốc độ lớn, bởi vì ông chủ của nó (Borland) đã không cập nhật nữa vì ý muốn chuyển sang dòng ngôn ngữ khác. Tuy vậy bạn đừng lo, bạn có thể tự sửa các lỗi ấy bằng những thao tác đ ơn giản, hoặc né tránh không dùng những lệnh gây lỗi đó. Các bạn nên tập trung bước đầu làm quen với "lập trình cấu trúc" này, nó sẽ là cầu nối tốt giúp bạn về sau khi học lập tr ình bằng những ngôn ngữ khác trong môi trường Windows. Khi thực hành trên máy bạn còn được cung cấp quyển bài tập Pascal mà trong đó các bài tập cùng theo trật tự của phần lý thuyết này. Chúc các bạn thành đạt! ELEC Trang 1
  2. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 1. Các thành phần cơ bản của ngôn ngữ 1.1 Bộ ký tự, từ khoá, tên gọi Các ngôn ngữ bất kỳ đều được xây dựng dựa trên một bộ các ký tự, từ các ký tự đó mà các từ có nghĩa được tạo thành. Tiếp theo là các qui tắc để tạo thành câu để diễn tả các hành vi, sự việc nghĩa là phải tuân thủ cú pháp (syntax) và ngữ pháp (grammar) của ngôn ngữ đó. Ngôn ngữ Pascal cũng theo quy cách đó. a. Bộ ký tự: Bộ chữ cái la tinh: 26 chữ cái lớn A, B, C, D Z. 26 chữ cái nhỏ a, b, c, d, , z. Ký tự gạch nối _ Các chữ số thập phân: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. Các ký tự toán học: +, -, *, /, = , , (, ) Các ký tự đặc biệt: ., ;, :, [, ], ?, %, @, Dấu cách: (Space) dùng để ngăn cách các từ. b. Một số từ của Pascal được gọi là từ khoá (keyword). Các từ khoá này bao gồm: Từ khoá chung: Program, Begin, End, Procedure, Function. Từ khoá để khai báo: Conts, Var, Label, Type, Array, String, Record, File of Từ khoá lệnh điều kiện, chọn và lặp: if then else , Case of For to do và For Downto do While do Repeat until Từ khoá điều khiển: With, Goto Từ khoá toán tử: And, Or, Not, In, Div, Mod V.v Các từ khoá có thể viết bằng chữ to hoặc chữ nhỏ, hoặc pha lẫn ví dụ: Begin, BEGIN, begin đều như nhau. d. Tên (định danh - identifier): Tên hoặc định danh dùng để chỉ tên hằng, biến, kiểu, tên chương trình con Tên được tạo thành từ các chữ cái và các chữ số nhưng chữ đầu phải là chữ cái (có thể dùng thêm dấu gạch dưới). Nên đặt tên sao cho có ý nghĩa và dễ nhận biết. Ví dụ để đặt tên biến là diện tích hình tròn ta nên dùng: S hoặc DienTichHinhTron hoặc Dien _Tich_Hinh_tron v.v Các t ên viết như sau là sai, Pascal không chấp nhận: ELEC Trang 2
  3. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI #DienTich Sai vì tên bắt đầu bằng ký tự không được phép BEGIN Sai vì tên trùng với từ khoá Dien Tich Sai vì có dấu cách (Space) 3XY Sai vì tên bắt đầu bằng chữ số, Một số tên dùng cho tên hàm như EXP, SIN, COS, ) đư ợc gọi là các tên chuẩn. Sự khác nhau giữa tên chuẩn và từ khoá là: người sử dụng có thể định nghĩa lại các tên chuẩn vào việc khác nếu cần. Còn từ khoá thì không được phép như vậy. Một số tên chuẩn của Pascal: Boolean, Char, Integer, Real, Byte, Text. False, True, MaxInt. Abs, artctan, Chr, Cos, Sin, Eof, Eoln, Exp, Ln, Odd, Ord, Round, Trunc, Sqr, Sqrt, Pred, Succ. Dispose, New, Get, Put, Read, Realn, Write, Writeln, Reset, Rewrite. 1.2 Ngăn cách các lệnh Dấu chấm phẩy ";" được dùng để ngăn cách các câu lệnh của Pascal. 1.3 Lời chú thích (Comment) Lời chú thích có thể đưa vào bất kỳ vị trí nào trong chương trình mà không ảnh hưởng đến các phần khác. Lời chú thích l à dành cho người đọc, máy sẽ bỏ qua khi gặp nó. Lời chú thích được đặt bên trong mở và đóng móc {và} hoặc ở giữa cụm dấu (*và v*). Trong chương trình nên viết những lời chú thích vào những vị trí thích hợp giúp cho con người dễ dàng kiểm tra chương trình. 1.4 Cấu trúc chung của chương trình Pascal Chương trình là một dãy các lệnh, chỉ dẫn cho máy thực hiện một nhiệm vụ nào đó. Chương trình Pascal gồm 4 phần: Tiêu đề của chương trình Phần gọi các đơn vị (Unit) chương trình Phần khai báo: hằng, biến, kiểu và chương trình con Thân chương trình chứa các lệnh Trước hết chúng ta xem một chương trình đơn giản tính tổng của hai số như sau: Program TongHaiSo; (*Tiêu đề chương trình *) Uses Crt; (*gọi đơn vị Crtg *) Var Tong,a,b: Real; (*Khai báo ba biến thực) Begin ClrScr; (*Xoá màn hìnhX *) Write('Hãy vào số thứ nhất a = '); ELEC Trang 3
  4. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Readln(a); (*Vào giá trị của a *) Write('Hãy vào số thứ hai b = '); Readln(b); (*Vào giá trị của b *) Tong:= a+b; (*Tính tổng hai số *) (*Hiển thị kết quả lên màn hình *) Writeln(' Tổng của hai số là:', Tong); End. Như vậy cấu trúc tổng quát một chương trình đầy đủ gồm các phần chính như sau: Program TenChuongTrinh ; (*Dòng tiêu đề *) Uses CRT, Printer; (*Lời gọi sử dụng các đơn vị chương trìnhL *) (*Phần khai báo dữ liệu và chương trình con *) Label Const Type Var Procedure {Có thể có nhiều Procedure và nhiều Function } Function (*Thân chương trình chính *) Begin (*Các lệnh được viết ở đây *) End. Phần tiêu đề của chương trình: Phần này bắt đầu bằng từ khoá Program, tiếp theo là tên do người lập trình đặt ra theo một ý nghĩa của nội dung chương trình. Cuối phần tên là dấu chấm phẩy";". Phần tiêu đề có thể không có cũng được. · Phần khai báo: Phần này dùng để mô tả các đối tượng dữ liệu. Có thể có các khai báo sau: Uses (*Khai báo sử dụng các UnitK *) Label (*Khai báo nhãnK *) Const (*Khai báo hằng *) Type (*Mô tả kiểu dữ liệu M *) Var (*Khai báo biến K *) Procedure (*Khai báo các thủ tụcK *) Function (*Khai báo các hàmK *) ELEC Trang 4
  5. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Các phần khai báo có thể có hoặc không, tuỳ theo thực tế của từng b ài toán. Phần thân chương trình: Thân chương trình nằm giữa hai từ khoá Begin và End. Sau từ khoá End là dấu chấm "." để báo kết thúc chương trình. Không có thân thì bất thành chương trình, thân chứa các lệnh để xử lý các đối tượng dữ liệu đã được mô tả trong phần khai báo. Ví dụ chương trình sau chỉ có thân: Begin Writeln (' Chào bạn đã đến với Turbo Pascal 7.0'); End. 1.5 Các bước cơ bản khi soạn một chương trình. Để soạn một chương trình bằng ngôn ngữ Pascal. Thông thường trải qua các bước sau: Bước 1: Bước soạn thảo chương trình Dùng một chương trình soạn thảo văn bản nào đó để soạn chương trình. Khi soạn xong ta lưu chương trình lên đĩa. Chương trình viết bằng ngôn ngữ Pascal được gọi là chương trình nguồn (source program). Tên các tệp (file) chứa chương trình nguồn Pascal có dạng chung *.Pas. Bước 2: Bước dịch chương trình Dùng chương trình dịch (compiler) Pascal để dịch ch ương trình nguồn sang mã máy (chứa trong các tệp *. COM, *.EXE, *.OBJ). Giai đoạn n ày cho phép ta phát hiện ra các lỗi cú pháp khi viết ch ương trình. Nếu có lỗi, chương trình dịch sẽ báo lỗi. Ta phải quay về bước 1 để sửa và quay lại bước 2. Nếu không có lỗi cú pháp, ta sang bước 3. Bước 3: Chạy chương trình (Ta sẽ thực hiện 3 bước đó liên tục trong toàn bộ giáo trình này) ELEC Trang 5
  6. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 2: Các kiểu dữ liệu cơ sở 2.1 Kiểu Logic (Boolean) Trong cuộc sống chúng ta thường hay gặp loại dữ liệu chỉ có hai giá trị: đúng (True) hoặc sai (False). Ví dụ khi ta viết 10>25 th ì đây là một mệnh đề có giá trị False. Hoặc 1 7) cho kết quả TRUE (3 3) OR (4 3) OR (4>7) cho kết quả FALSE (1>3) XOR (4 3) XOR (4>7) cho kết quả FALSE NOT (1>9) cho kết quả TRUE NOT (1<9) cho kết quả FALSE 2.2 kiểu số nguyên (Integer) Một giá trị có kiểu nguyên là một phần tử của tập các số nguyên mà ta có thể xử lý được trên máy, tất nhiên nó chỉ là một tập nhỏ của các số nguyên chứ không phải tất cả mọi số nguyên đều có thể xử lý được trên máy. Kiểu số nguyên được định nghĩa sẵn với từ khoá INTEGER. Thông thường nhất, các số nguyên được biểu diễn bằng hai byte (16 bít) n ên phạm vi của nó là từ - 32768 (=-215) đến +32767(=215-1). Các số nguyên được viết ra có thể có dấu dương (+) phía trước hoặc dấu (-), hoặc không có dấu. Thí dụ: +120, -267, -5, 13, 163 ELEC Trang 6
  7. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Maxint là tên giá trị cực đại cho phép của kiểu nguyên, nghĩa là Maxint = +32767. 1. Các phép tính số học đối với số nguyên: Phép cộng và phép trừ: +, - Phép nhân: * Phép chia lấy kết quả là số thực:/ ví dụ 7/2 cho ta kết quả là 3.5 Phép chia lấy kết quả là nguyên: DIV Ví dụ: 13 DIV 2 cho kết quả 6 Phép chia lấy số dư của hai số nguyên: MOD Ví dụ: 7 MOD 4; cho ta giá trị bằng 3 là số dư của phép tính . Hàm Boolean ODD (n) cho kết quả TRUE nếu n là một số lẻ, FASLE nếu n là số chẵn. Chú ý: Khi thực hiện các phép tính số học đối với số nguy ên, cần quan tâm xem các kết quả có vượt ra khỏi phạm vi biểu diễn số nguyên của máy hay không. Ví dụ: 31950 +3800= 35750 (vượt quá giới hạn) 2. 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à cũng có thể so sánh với các số thực. Kết quả của phép toán so sánh là TRUE (đúng) hoặc FALSE (sai). Ví dụ: 12 , , >=, <=) đề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. Tất nhiên không tồn tại các phép toán DIV, MOD cho kiểu số thực. Các số thực được biểu diễn trong máy ở hai dạng: dạng dấu chấm tĩnh v à dạng dấu chấm động (có phần số mũ). Dạng dấu chấm tĩnh như sau: (Dấu chấm thay cho dấu phẩy thập phân) 13.23 5.00 -32.3456 -0.00001 Gọi là tĩnh vì dấu chấm thập phân ở đâu đặc trưng cho độ lớn của số đó Dạng dấu chấm động (có phần mũ): ELEC Trang 7
  8. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Gồm hai phần: phần định trị và phần mũ viết sau chữ E để biểu diễn số mũ của cơ số 10. Ví dụ: 1233.45 = 1.23345*103 Biểu diễn bằng số dấu chấm động như sau: 1.23345E+03 Gọi là động vì dấu chấm thập phân chưa đủ để xác định độ lớn của số đó. Cách viết số thực như sau là sai, là không đủ: .8 (Phải viết là 0.8) 3. (Phải viết là 3.0 hoặc 3) Các hàm số học chuẩn (dùng cho số nguyên và số thực): 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 kết quả là trị tuyệt đối của x SQR(x) cho giá trị x2. SIN(x), COS(x), ARCTAN(x) là các hàm lượng giác. LN(x) hàm log2 (x) =ln(x). EXP(x) hàm ex SQRT(x) hàm tính căn bậc hai của x SUCC(n) đối số nguyên n, cho số nguyên tiếp theo n, tức là n +1. PRED(n) đối số nguyên n, cho ta 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. TRUNC(x) kết quả 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. ROUND(x) cho ta một số nguyên là phần nguyên của x bằng cách qui tròn phần lẻ thập phân của x. Ví dụ: Round (6.76) = 7 Round (6.36) = 6 Round (-34.812) = -35 2.4 Kiểu ký tự (character) Máy tính không chỉ xử lý các dữ liệu bằng số mà còn có khả năng xử lý các dữ liệu văn bản (ký tự). Kiểu ký tự được định nghĩa với từ khoá CHAR. Hằng ký tự phải đặt trong mở nháy đ ơn và đóng nháy đơn, ví dụ: '5', 'b', 'A', '0', '9', '*', '!', Máy tính dùng bộ ký tự để trao đổi thông tin qua các thiết bị v ào - ra. Bộ ký tự được dùng phổ biến nhất là bộ ký tự ASCII (American Standard Code for information Interchange). Hay còn g ọi là bộ mã ASCII. Các ký tự được mã hoá bằng một byte, một Byte có thể biểu diễn đ ược 256 ký tự khác nhau. Các ký tự cơ bản nhất từ 0 đến 127 được gọi là ASCII chuẩn. Còn từ 128 đến 255 gọi là ELEC Trang 8
  9. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI ASCII mở rộng và được dùng để mã hoá các ký tự riêng của một số ngôn ngữ, các ký tự toán học, đồ họa. Chúng ta quan tâm chủ yếu tới phần 128 ký tự đầu của bảng mã ASCII để xây dựng cú pháp cho lập trình. Trong ASCII, các ký tự từ 0 đến 31 là các ký tự điều khiển, không in được, dùng để điều khiển các thiết bị ngoại vi, điều khiển việc trao đổi thông tin Ví dụ khi máy nhận được ký tự số 7 (BEL), máy sẽ phát ra một tiếng k êu. Khi nhận được ký tự số 13 (CR : Carriage Return) con trỏ m àn hình sẽ xuống đầu dòng tiếp theo. Khi nhận được 10 (LF: Line Feed) đầu kim in của máy in sẽ xuống đầu dòng tiếp theo v.v Phần còn lại trong ASCII là mã của các chữ cái A, B, C, các chữ số 0, 1, ,9, các ký tự đặc biệt Ví dụ khi nhận được mã 65, máy sẽ hiện lên màn hình chữ cái A. Riêng mã 127 (Del) được dùng làm ký tự điều khiển xoá. Khi soạn chương trình, phím Delete trên bàn phím chính là phím t ạo ra mã số 127 để xoá một ký tự trên màn hình. Hai hàm chuẩn ORD và CHR cho phép thiết lập tương quan giữa mã ký tự và ký tự tương ứng, ví dụ: Hàm ORD ('A') cho kết quả 65, số thứ tự (mã) của ký tự 'A' trong bảng mã. Hàm CHR (65) cho ta ký tự A. Đương nhiên là CHR (ORD('A')) = 'A' và ORD (CHR(65)) =65 Ký tự Chr1 nhỏ hơn ký tự Chr2 nếu Ord (Chr1) < ord (Chr2). Hai cách viết sau là tương đương: #65 = CHR(65) Hàm chuẩn PRED và SUCC có thể áp dụng cho đối số là ký tự, kết quả là ký tự. Giả sử Chr là một ký tự nào đó: Hàm PRED (Chr) cho kết quả là một ký tự nằm trước ký tự Chr. Ví dụ PRED ('B')='A'. Hàm SUCC (Chr) cho kết quả là một ký tự nằm sau ký tự Chr, ví dụ: SUCC('A')='B' 2.6 Mô tả số nguyên với Word, Shortint, Longint. Số nguyên ngoài Integer và Byte còn có với các dạng Word, Shortint (Short Integer), Longint (Long Integer). Sau đây là b ảng kiệt kê các phạm vi của nó. Kiểu Phạm vi Kích thước Byte Byte 0 255 1 Shortint -128 127 1 Integer -32768 32767 2 Word 0 65535 2 Longint -214783648 21483647 4 Turbo Pascal còn cho phép biểu diễn số nguyên dưới dạng hệ 16 (số Hexa) bằng cách dùng thêm dấu $ ở đầu. Ví dụ: $E có giá trị là 14 (hệ thập phânh). ELEC Trang 9
  10. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Một byte được biểu diễn bằng hai chữ số Hexa, v ì một chữ số Hexa tương đương với số nhị phân 4 bít. Ta có bảng quan hệ sau: Hệ 10 Hệ 2 Hệ 16 0 0000 0 1 0001 1 2 0010 2 3 0011 3 4 0100 4 5 0101 5 6 0110 6 7 0111 7 8 1000 8 9 1001 9 10 1010 A 11 1011 B 12 1100 C 13 1101 D 14 1110 E 15 1111 F Ví dụ: số Hexa $7FFF =7*16^3+15*16^2+15*16^1+15*16^0= 32767 (s ố hệ 10) $8AB2=8*16^3+10*16^2+11*16^1+2*16^ 0=35506 (số hệ 10) 2.7 Mở rộng khai báo kiểu số thực Số thực còn có các dạng sau: Kiểu Phạm vi Số chữ số có Kích thước nghĩa (bytes) REAL 2.9E-39 1.7E+38 11-12 6 SINGLE 1.5E-45 3.4E+38 7-8 4 DOUBLE 5.0E-324 1.7E+308 15-16 8 EXTENDED 1.9E- 19-20 10 4951 1.1E+4932 ELEC Trang 10
  11. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 3: Khai Báo, biểu thức và câu lệnh Hằng, biến, kiểu đều phải được khai báo trước khi dùng trong chương trình. 3.1 Khai báo hằng Có các loạiC: hằng nguyên, hằng thực, hằng ký tự và hằng Boolean. Khai báo hằng: Các hằng được khai báo như sau: Const tên_hằng = giá_trị_của_hằng; 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 đặt theo qui tắc đã trình bày ở chương trước. Ví dụ: Const X=5; (*Hằng nguyênH *) Y=3.14; (*Hằng thực 5H*) A=TRUE; (*Hằng BooleanH *) Chr= 'e'; (*Hằng ký tự eH *). Các hằng không thay đổi trong suốt chương trình. 3.2 Khai báo biến Biến (variable) là đại lượng có thể thay đổi giá trị trong quá trình xử lý. Tên biến của chương trình đồng thời là địa chỉ của biến đó. Biến được khai báo như sau: Var Tên_biến: Kiểu_dữ_liệu_của_biến; Dấu hai chấm để ngăn cách hai phần của khai báo, dấu chấm phẩy kết thúc một dòng khai báo. Nếu có nhiều biến cùng kiểu có thể được rút gọn bằng cách viết tên các biến đặt cách nhau dấu phẩy (,) ví dụ: Var a, b, c: Real; i,j,k: Integer; T: Boolean; 3.3 Định nghĩa kiểu Đối với các dữ liệu cơ sở (Real, Integer, Byte, Char, Bool ean) đã được định nghĩa sẵn nên ta khai báo biến trực tiếp ngay. Còn các kiểu dữ liệu khác ta phải định nghĩa kiểu. Ví dụ: Type Mau = (Xanh, Do, Vang); Var MauSac: Mau; ELEC Trang 11
  12. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI 3.4 Biểu thức (expression) Một biểu thức gồmM: toán tử (operator) v à toán hạng (operand). Toán tử (dấu phép toán), toán hạng có thể là hằng, hàm, biến. Ví dụ: 14 + SQRT(5)-2*COS(X) Trong ví dụ này, các phép toán là phép cộng (+), phép trừ p (-) và phép nhânv (*). Các toán hạng là hằng số 14, hàm SQRT với đối số là 5, hằng 2 và hàm COS 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à integerl, byte, real) Biểu thức 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ệ ( , =, =) cũng đ ược gọi là biểu thức Boolean 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à nguyên, thực, ký tự v.v Thứ tự thực hiện từ trái qua phải với thứ tự ưu tiên như sau: Dấu ngoặc ( ) Biểu thức trong ngoặc được ưu tiên thứ nhất Not, - (dấu trừ) Các phép toán một toán hạng *, /, Div, mod, and Các phép tính loại nhân, cùng mức ưu tiên +, -, or, xor Các phép tính loại cộng, cùng mức ưu tiên =, =, >, 3) and ('c' 5 Div 3 )=Not (4 1)=Not TRUE OR TRUE=FALSE OR TRUE=TRUE 3.5 Câu lệnh (Instruction, Statemment) Ngoài phần mô tả dữ liệu còn có phần lệnh (instruction) của chương trình. Phần này quy định các công việc mà chương trình phải thực hiện để xử lý các dữ liệu. Các lệnh (hay cũng gọi là câu lệnh) cách nhau bởi dấu chấm phẩy. Câu lệnh được chia ra hai loại: Câu lệnh đơn giản và câu lệnh có cấu trúc. · Câu lệnh đơn giản bao gồm: Lệnh gán (:=), lời gọi thủ tụcl, lệnh nhẩy GOTO · Câu lệnh có cấu trúc bao gồm: Câu lệnh ghép (lệnh hợp thànhl): BEGIN END; Câu lệnh điều kiện và lựa chọn: if then else case of ELEC Trang 12
  13. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Các vòng lặp: For To Do Repeat Until While Do Với làm : With Do Mỗi một câu lệnh 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 thuộc vào câu lệnh. Pascal không bắt buộc phải viết mỗi câu lệnh một dòng. Vấn đề là phải trình bầy chương trình sao cho đẹp, rõ ràng, mô tả đượ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: A='Chao anh'; B:=TRUE;C :=12; Hoặc viết thành từng dòng: A='Chao anh'; B:=TRUE; C:=12; Các lệnh có cấu trúc sẽ được đề cập ở các chương sau. Còn thủ tục sẽ được đưa vào cùng với các cấu trúc dữ liệu. · Phép gán Phép gán dùng để gán giá trị của một biểu thức, một hằng v ào một biến. Phép gán được viết như sau: biến:= biểu_thức; Ví dụ: A:=12; biến A nhận giá trị bằng 12 b (hay đ ưa 12 vào biến có địa chỉ A) B:= FALSE; biến B nhận giá trị FALSE.b Y:= Y+1 Y cộng với 1 kết quả để tại Y 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 giống nhau. Ví dụ một biến thực X không thể nhận một giá trị Boolean đ ược. X := TRUE là sai. Trường hợp ngoại lệ: một biến nguyên không thể nhận một giá trị là số thực nhưng một biến thực thì lại có thể nhận một giá trị nguyên. Giả sử I là Integer. I:= 9.5 là sai mà phải viết I:=Round(9.5). Nhưng nếu X là biến thực, viết như sau là đúng: I:=12; X:=I; 3.6 Lệnh hợp thành hay lệnh ghép Một nhóm câu lệnh đơn giản được đặt giữa hai chữ Begin và End sẽ tạo thành một câu lệnh hợp thành hay một lệnh ghép với cách mẫu viết như sau: Begin Câu lệnh 1; Câu lệnh 2; ELEC Trang 13
  14. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Câu lệnh n; End; Cặp Begin End của câu lệnh ghép cho ta thấy rõ hơn tính có cấu trúc của ngôn ngữ Pascal. Ta có thể nhóm các lệnh th ành từng khối. Một khối lệnh chỉ có một mở đầu bằng chữ Begin và một kết thúc bằng chữ End. Chúng ta sẽ hiểu chi tiết thêm về lệnh ghép thông qua các ví dụ cụ thể ở các ch ương tiếp theo. Bài tập: Nêu quy tắc đặt tên biến trong chương trình? Hằng là gì? và được khai báo như thế nào? Hãy khai báo một biến thực, nguyên bất kỳ? Biểu thức là gì, cho ví dụ Thế nào là biểu thức Logic? Cho ví dụ Thế nào là biểu thức quan hệ? cho ví dụ Hãy cho một số ví dụ về lệnh gán Lệnh hợp thành là gì? Có thể có các lệnh hợp thành nằm trong một lệnh hợp thành? Cho ví dụ Kết quả của biến A là gì nếu sau khi thực hiện lệnh gán sau: A:=((3 3)) OR (4<11) ELEC Trang 14
  15. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 4: Thủ tục vào, ra dữ liệu. 4.1 Thủ tục hiển thị dữ liệu ra m àn hình: Write và Writeln Để hiển thị dữ liệu ra màn hình, Pascal có 3 cách viết như sau: Write ( Item1, Item2, , ItemN); Writeln(Item1, Item 2, , ItemN); (đọc là write line) Writeln; Trong đó ( Item1, Item2, , ItemN); là các mục cần hiển thị, có thể là một trong các loại sau: Ví dụ: Hằng: Writeln(3.12); Writeln(' Chào bạn!'); Biến: Writeln(A); Hàm: Writeln(Cos(x)); Biểu thức: Writeln(X+Y - 2 +Exp(X)); Một số kiểu có cấu trúc như mảng, xâu ký tự (sẽ học saus). Màn hình thông dụng hiện nay được phân thành 25 dòng, mỗi dòng có thể chứa 80 ký tự.? mỗi thời điểm, tại một vị trí xác định tr ên màn hình có một khối sáng nhấp nháy hoặc một nét gạch nhấp nh áy gọi là con trỏ màn hình hay điểm nhắc (cursor) . Sự khác nhau của 3 cách viết trên là ở chỗ vị trí con trỏ màn hình sau khi kết thúc lệnh. · Cách viết Writeln ( Item1, Item2, , ItemN); có ý nghĩa: Sau khi hiển thị các giá trị của (Item1, Item2, , ItemN) trên cùng một dòng, con trỏ sẽ chuyển xuống dòng tiếp theo (con trỏ được đặt ở đầu dòng tiếp theo) Cách viết Write (Item1, Item2, , ItemN); Sau khi hiển thị các giá trị của ( Item1, Item2, , ItemN) con trỏ sẽ không chuyển xuống đầu dòng tiếp theo (con trỏ sẽ được đặt ở vị trí sau giá trị của ItemNc). Cách viết Write (Item1, Item2, , ItemN); l à tương đương với khối lệnh như sau: Begin Write(Item1); Write(Item2); Write(ItemN); End; Thủ tục Writeln; (không có tham sốk) sẽ đặt con trỏ xuống đầu d òng tiếp theo. Vì vậy Writeln( Item1, Item2, , ItemN); tương đương v ới một lệnh ghép. Begin Write( Item1, Item2, , ItemN); WriteLn; ELEC Trang 15
  16. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI End; Trong khi dùng thủ tục Write và Writeln, có hai cách trình bày dữ liệu in ra là cách viết không qui cách và cách viết có qui cách. Chúng ta sẽ xét cụ thể lệnh viết ra với từng kiểu dữ liệu. 1. Viết ra kiểu số nguyên. Cách viết không qui cách: Var I : Integer; Begin I :=345; Writeln(I); Writeln(-98671); End. Sẽ hiển thị ra màn hình: 345 -98671 Cách viết không qui cách không chỉ rõ qui cách hiển thị trong các thủ tục Write. Các số nguyên sẽ được viết ra với số chỗ bằng độ d ài của nó (số chữ số của nó).? đây biến I có giá trị 345 chiếm 3 vị trí, còn -98671 chiếm 6 vị trí (5 chữ số và dấu 5 - ) kể từ vị trí bên trái. · Cách viết có qui cách. Ta có thể bố trí chỗ số cố định để hiển thị số nguyên bằng cách thêm dấu hai chấm (:) theo sau là số vị trí cần hiển thị. Máy sẽ xếp ch ỗ từ bên phải qua bên trái. Nếu thừa sẽ để trống ở bên trái. Ví dụ: Writeln (' 123 456'); I:= 345; Writeln(I:6); Writeln(-98671:8); Sẽ viết ra trên màn hình: 123456 345 -30567 Như vậy cách viết không qui cách sẽ căn lề b ên trái còn cách viết có qui cách sẽ căn lề bên phải. 2. Viết ra kiểu số thực Với khai báo X là một biến thực Var X: Real; · Cách viết không qui cách Sẽ hiển thị giá trị của X theo cách biểu diễn dấu chấm động, ví dụ: X :=34.56; ELEC Trang 16
  17. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Writeln(X); Write(6.72); sẽ cho kết quả trên màn hình như sau: 3.4560000000E+01 6.7200000000E+00 Hai dấu cách ở đầu, một số phần nguyên, dấu chấm thập phân, 10 chỗ phần thập phân (nếu không có giá trị cụ thể thì sẽ bị điền số 0 vào), chữ E biểu diễn số mũ, dấu của phần mũ, hai số biểu diễn giá trị phần mũ. Tổng số chỗ số thực chiếm l à 18. · Cách viết có qui cách của số thực X: Cách 1: Hiển thị số dấu chấm tĩnh X : : Cách 2: Hiển thị số dấu chấm động X : . Ví dụ: áp dụng cho cách 1 X:=123.456; Writeln(25.123456789:12:6); Writeln(X :12:6); Writeln( 3.14:12:6); cho ra kết quả: 25.123457 123.456000 3.140000 Phần thập phân được xác định 6 chỗ, nếu không đủ giá trị cụ thể, nó sẽ điền số 0 vào. Còn nếu phần thập phân mà nhiều, nó sẽ làm tròn như dòng đầu tiên (số 25.123457s). Với cách viết có qui cách này, ta có thể trình bày các số thực sao cho các dấu chấm thập phân thẳng theo chiều đứng một cách đ ẹp mắt. Ví dụ: áp dụng cho cách 2. Write ( 25.123456789:12); (cho ra kết quả có làm tròn) 2.512346E +01 Trong cách 2, số thực được viết ra dưới dạng E mũ (phần mũ chiếm 4 chỗp), toàn bộ số chỗ là 12 thì phần còn lại để viết phần định trị là 12-4=8 chỗ. 3. Hiển thị kiểu ký tự: Với cách viết không qui cách, mỗi ký tự chiếm một chỗ. C òn với cách viết có qui cách, máy sẽ bố trí thêm các chỗ trắng. Begin Writeln('ABCD'); (*Cách viết không có qui cáchC *) Writeln('E'); (*Cách viết không có qui cáchC *) Writeln('E':5); (*Cách viết có qui cáchC *) Writeln('ABCD' :5); (*Cách viết có qui cáchC *) End. ELEC Trang 17
  18. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI sẽ cho ra kết quả ABCD E ABCD E 4. Viết ra kiểu Boolean Kiểu Boolean sẽ được hiển thị với các từ True và False. Ta cũng có thể qui định số chỗ để viết các từ này. Ví dụ: Var a: Boolean; Begin a: =5>12; Writeln(a); (*Cách viết không qui cách C *) Writeln(a:7); (*Cách viết có qui cách C *) End. sẽ cho ra kết quả: FALSE FALSE 5. In ra máy in Write và Writeln được dùng để hiển thị dữ liệu ra màn hình, muốn in ra giấy (sử dụng máy in) ta thêm từ Lst và dấu phẩy vào trước các biến hoặc hằng cần in ra. Ví dụ: Writeln (Lst, X:5:2, Y:12:5, I:5); Ngoài việc phải thêm Lst còn phải khai báo: USES PRINTER; 6. Trình bày màn hình: Để trình bày màn hình theo những thủ tục xác định, ở phần khai báo phải có: USES CRT; CRT là đơn vị (Unit) chứa các thủ tục trình bày màn hình GOTOXY(X,Y); Là thủ tục đưa con trỏ đến toạ độ X, Y của màn hình. X là tọa độ cột tính từ 1 đến 80, Y là tọa độ dòng, tính từ 1 đến 25 (màn hình được chia thành 25 dòng, 80 cột). Ví dụ: GOTOXY(15,14); (đưa con trỏ đến cột 15 và dòng 14) ClrScr; (Clear Screen) là thủ tục xoá toàn bộ màn hình, sau khi xoá con trỏ nằm ở vị trí góc trái phía trên màn hình. ClrEol; (Clear end of Line) thủ tục xoá các ký tự nằm bên phải con trỏ đến hết dòng. TextColor( ) thủ tục xác định màu chữ, ví dụ Textcolor (Blue) sẽ cho chữ m àu xanh. ELEC Trang 18
  19. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI TextBackground( ) là thủ tục xác định màu nền của văn bản, ví dụ: TextBackGround(Red) sẽ cho màu nền đỏ. NormVideo: Đặt văn bản có độ sáng bình thường LowVideo: Đặt văn bản có độ sáng yếu Ta có bảng màu sau: Tên màu Tiếng Việt Mã Black Đen 0 Blue Xanh lơ 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ạt 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 11 nhạt LightRed Đỏ nhạt 12 LightMagenta Tía nhạt 13 Yellow Vàng 14 White Trắng 15 Blink Nhấp nháy 128 Hai cách viết: Textcolor(Blue) và Textcolor (1) là tương đương. Ví dụ 1: USES CRT; Var X,Y: Integer; Begin TextBackground (Red); (*Đặt mầu nền cho màn hình *) ClrScr; (*Xoá màn hình *) X :=6; Y :=3; GotoXY (X,Y);TextColor(Blue); Writeln ('Chao ban'); (*Chữ Chao ban sẽ được hiện ở toạ độ (6,3) và màu xanh *) GotoXY (X+10,Y+2); TextColor(White); Writeln ('Chao ban');(* Chữ Chao ban được hiện ở toạ độ (16,5) và màu trắng *) TextColor(White + Blink); ELEC Trang 19
  20. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Write ('Chao ban'); (*Chữ Chao ban hiện ở toạ độ (1,6), màu trắng nhấp nháy *) End. Ví dụ 2: Hiển thị từ COMPUTER (với chữ CO và ER sáng bình thường còn lại là sáng yếu) USES CRT; Begin NormVideo; write('CO'); LowVideo; write('MPUT'); NormVideo; write('ER'); End. Chú ý: Nếu bạn chạy Turbo Pascal 7.0 với một số CPU có tốc độ cao th ì Crt sẽ gây lỗi trong một số trường hợp khi gặp thủ tục Writeln. Tuỳ theo từng tr ường hợp cụ thể mà có thể có cách khắc phục. Borland sẽ không cập nhật tiếp để nâng cấp dòng Turbo Pascal. 4.2 Vào dữ liệu: READ và READLN 1. Read và Readln: Nhờ phép gán ta có thể đưa giá trị cho biến (từ một biến khác hay hằng) ở trong chương trình. Vậy muốn đưa một giá trị từ bàn phím (thông qua gõ và đưa vào biến) thì làm thế nào? Thủ tục Read và Readln (Read Line) sẽ giúp ta làm điều đó. Ba cách viết sau: READ (Var1, Var2, ,VarN); READLN(Var1, Var2, ,VarN); READLN; (Không có tham số) Trong đó Var1, Var2 là các biến (không thể hằng) đã khai báo trong chương trình. Khi gặp thủ tục này chương trình sẽ chờ để chúng ta gõ dữ liệu vào. Dữ liệu gõ vào phải có cùng kiểu với biến, các dữ liệu ngăn cách ít nhất một khoảng trống (Space), sau khi gõ xong dữ liệu hãy gõ tiếp  (Enter). Ví dụ 1: Var i,j: Integer; a,b,c: Real; Begin Readln (i,j); Readln(a,b,c); End. Khi chạy chương trình (sẽ nói ở phần sau) máy sẽ chờ để chúng ta g õ 2 số nguyên ứng với thủ tục Readln (i,j), ví dụ: 4 6  (Enter). Máy lại chờ để ta gõ ELEC Trang 20
  21. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI vào ba số thực ứng với thủ tục Readln (a,b,c), ví dụ: 12.3 15.5 20.5 . Sau hai thủ tục đó các biến sẽ có nội dung như sau: Nội dung của I là 4 (hay ta cũng có thể nói trong ô nhớ I có 4) Nội dung của J là 6 Nội dung của a là 12.3 Nội dung của b là 15.5 Nội dung của c là 20.5 Trong khi nhận nội dung từ bàn phím, 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 của biến hay không. . Ví dụ 2: ở ví dụ 1 ta cũng có thể viết gộp lại như sau: Var i,j: Integer; a,b,c: Real; Begin Readln (i,j,a,b,c); End. Và gõ dữ liệu vào như sau: 4 6 12.3 15.5 20.5  Hay cũng có thể tách thành nhiều lệnh như sau: Var i,j: Integer; a,b,c: Real; Begin Readln(i); Readln(j); Readln(a); Readln(b); Readln(c); End. Và gõ dữ liệu vào như sau: 4 6 12.3 15.5 20.5 ELEC Trang 21
  22. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Với các Version khác nhau sẽ có sự phân biệt giữ a Read và Readln khác nhau sau khi ấn  để vào dữ liệu. Ví dụ Version 3.0, Read không chuyển con trỏ xuống dòng tiếp theo như thủ tục Readln. Nói chung hai thủ tục đó c ùng để đọc dữ liệu nhưng việc di chuyển con trỏ có khác nhau sau khi ấn Enter để v ào dữ liệu, bạn thử trên máy về Read và Readln sẽ rõ. Readln; là thủ tục không có tham số, máy tính sẽ cho đến khi ta ấn Enter th ì mới làm tiếp. Readln không tham số được sử dụng khi ta muốn chương trình dừng tại một vị trí nào đó (để chúng ta đọc kết quả chẳng hạn), sau đó lại ấn nút Enter để tiếp tục chương trình. 2. Kết hợp Write và Readln để tạo giao diện người - máy. Khi gặp Read hoặc Readln chương trình tạm dừng để chờ dữ liệu. Nếu ta không để ý trước là ở đó có thủ tục Read hoặc Readln th ì nhiều khi chúng ta cứ tưởng là chương trình bị treo hoặc có sai sót gì đó. Vì vậy ta có thể kết hợp với thủ tục Write (không nên dùng Writelnk) đ ể báo là có việc vào dữ liệu như sau: Write('Bạn gõ vào một số nguyên i =?'); Readln(i); Write('Bạn gõ vào một số thực x =?'); Readln(x); Nếu dùng Writeln thì không thuận lợi và đẹp mắt vì con trỏ của màn hình xuống dòng và ít gắn bó với việc gõ dữ liệu vào. 3. Một số thủ tục nhập phím đặc biệt: · Hàm ReadKey: có kiểu ký tự, cho giá trị là ký tự nhận vào từ bàn phím ngay từ khi gõ phím mà không cần ấn tiếp Enter. Ví dụ: Đọc một ký tự từ bàn phím và lưu ở biến Chr: Chr :=ReadKey · Hàm Keypressed: có kiểu Boolean, cho giá trị True nếu ta gõ một ký tự, False nếu không gõ. Chúng ta sẽ tiếp tục khai thác hàm này. Câu hỏi và bài tập: 1. Sự khác nhau cơ bản giữa Write và Writeln? 2. Sự khác nhau cơ bản giữa Read và Readln? 3. Cách viết:Readln(4, 12, A) sai chỗ nào? 4. Đoạn chương trình sau in ra kết quả nào? Program ViDu; Var S,i:Integer; Begin I:=10; S:=20; S:=S+I; S:=S*S; Writeln(S); End. 5. Hãy in ra hình sau: ELEC Trang 22
  23. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI AAAAAAAAA AAAAAAA AAAAA AAA A 6. Chương trình sau sai ở chỗ nào? Var A,b:Char; Begin a:='A'; b:='B' c:=ReadKey; Writeln(a,b,c); End. ELEC Trang 23
  24. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 5: Các câu lệnh điều kiện và câu lệnh chọn 1.1 Câu lệnh điều kiện IF THEN ELSE Câu lệnh này có hai dạng như sau: Dạng 1: IF Then ; Dạng 2: IF Then Else ; Hoạt động của dạng 1 như sau: nếu có giá trị True thì máy sẽ thực hiện , còn nếu không thì kết thúc lệnh if và thực hiện tiếp lệnh sau if Hoạt động của dạng 2 như sau: nếu có giá trị True thì máy sẽ thực hiện , còn nếu không thì sẽ thực hiện Ví dụ 1: Để giải phương trình bậc nhất một ẩn ax +b=0 ta viết: IF a <> 0 Then x:=-b/a Else writeln('Phương trình vô nghiệm'); Ví dụ 2: Tìm giá trị Max của hai số a và b. If a < b Then Max: =b Else Max: = a; (trước Else không được phép có dấu chấm phẩy) Nếu sau Then hoặc sau Else có trên một lệnh thì phải để trong Begin End Ví dụ: If a < b Then Begin Max:=b; Min:= a; End Else Begin Max:=a; Min:=b; End; Nghĩa là nếu a < b, hai lệnh là Max:= b và Min := a cùng được thực hiện. Ví dụ 3: Giải phương trình bậc 2: Program PhươngTrinhBacHai; Uses CRT; Var a,b,c,x1,x2,Delta:Real; Begin ClrScr; (*Xoá màn hình *) Write (' Bạn gõ vào hệ số a ='); Readln(a); Write(' Bạn gõ vào hệ số b ='); Readln(b); Write(' Bạn gõ vào hệ số c ='); Readln(c); Delta := b*b - 4 *a*c; (*Tính Delta *) If Delta = 0 Then ELEC Trang 24
  25. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Begin Writeln(' Phương trình có nghiệm kép'); Writeln(' x = ', - b/(2*a)); End; If Delta > 0 Then Begin Writeln(' Hai nghiem thuc :'); x1:=(-b+Sqrt(Delta))/(2*a); (*x1 là nghiệm 1x*) x2:=(-b-Sqrt (Delta))/(2*a); (*x2 là nghiệm 2x*) Writeln ('x1 = ', x1); Writeln ('x2 = ', x2); End Else Writeln(' Phương trình vô nghiệm'); End. 1.2. Câu lệnh chọn CASE OF Lệnh IF chỉ thực hiện rẽ hai nhánh ứng với hai 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: Dạng 1 Dạng 2 CASE OF CASE OF Giá trị 1: ; Giá trị 1G: ; Giá trị 2: ; Giá trị 2G: ; Giá trị N: ; Giá trị NG: ; END; ELSE ; END; Trong đó không chỉ là biểu thức Boolean mà còn có thể là biểu thức có các kiểu vô hướng đếm được (không được là kiểu Realk). Hoạt động của dạng 1 như sau: Nếu N bằng Giá trị i thì thực hiện và kết thúc lệnh chọn. Hoạt động của dạng 2 như sau: Nếu N bằng một Giá trị i thì thực hiện và kết thúc lệnh chọn nếu không làm và kết thúc lệnh chọn. Ví dụ 1: Write(' Vào thứ cần hỏi?'); Readln(thu); CASE Thu OF 1: Writeln( 'Chủ nhật nghỉ'); 2: Writeln('Thứ 2: Toán, Lý, Sinh'); 3: Writeln('Thứ 3: Văn, Sử, Địa'); 4: Writeln('Thứ 4: Ngoại ngữ'); ELEC Trang 25
  26. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI 5: Writeln('Thứ 5: Toán, Lý, Sinh'); 6: Writeln('Thứ 6: Văn, Sử, Địa'); 7: Writeln('Thứ 7: Ngoại ngữ'); End; Ví dụ 2: Write(' Bạn hãy gõ vào một ký tự');Readln(Chr); Case Chr Of '0' '9' : Writeln('Bạn vừa gõ một ký tự số!'); 'A' 'Z' :Writeln ('Bạn vừa gõ chữ cái hoa'); 'a' 'z' :Writeln(' Bạn vừa gõ chữ cái thường'); Else Writeln('Bạn vừa gõ một ký tự đặc biệt'); End; Bài tập: Cho một ví dụ về câu lệnh IF THEN Cho một ví dụ về câu lệnh IF THEN ELSE Cho một ví dụ mà sau THEN có lệnh hợp thành Cho ví dụ mà sau ELSE có lệnh hợp thành Hai cách viết sau khác nhau ở chỗ nào? IF a<b THEN Max:=b; Min:=a; Và cách viết: IF a<b THEN Begin Max:=b; Min:=a; End; Hãy dùng CASE OF lập một chương trình xem thời gian biểu hàng ngày của ban. Dòng lệnh sau sai ở chỗ nào? Var R:Real; Begin Readln(R); Case R OF 12.34: Writeln('Đây là số thực nhỏ hơn 20'); End; ELEC Trang 26
  27. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 6: Thực hành Turbo Pascal 6.1 Nên dùng Turbo Pascal với Version nào? Turbo Pascal có nhiều phiên bản (Version). Bạn nên sử dụng phiên bản 5.0, 5.5, 6.0 hoặc 7.0 thì tốt hơn. Những lệnh cơ bản trong các Version này đều giống nhau. Từ Turbo Pascal 5.0 trở lên có nhiều file và ta nên cài đặt đầy đủ lên đĩa cứng để hoạt động cho nhanh. Hai File cơ bản nhất là: Turbo.EXE và Turbo.TPL. Ngoài ra nên có thêm File Turbo.hlp đ ể tra cứu mỗi khi cần. Nếu có nhu cầu sử dụng đồ hoạ thì phải copy thêm các File sau đây: Graph.tpu là File chứa thư viện các chương trình đồ hoạ. Tùy theo kiểu màn hình mà chọn các file *.BGI (Borland Graphic Inteface) cho thích hợp. Copy các kiểu chữ trong khi dùng Graphic như: SANS.CHR, GOTH.CHR, TRIP.CHR v.v Các File *.BGI và *.CHR thường được đặt trong thư mục con BGI nằm trong thư mục TP. 6.2 Bắt đầu sử dụng Turbo Pascal 1 Khởi động Turbo Pascal . C:\>CD TP C:\TP>TURBO Màn hình soạn thảo sẽ hiện ra và bạn có thể soạn thảo một chương trình nào đó (như các hệ soạn thảo văn bản khác). Menu Bar gồm: File, Edit, Run, Compile, Option, Debug, Break/Watch, chọn bằng cách ấn Alt đồng thời với chữ cái đầu, ví dụ Alt +F v.v Sau Menu Bar là dòng trạng thái: báo cho người lập trình biết tọa độ con trỏ màn hình, trạng thái insert/OverWrite v.v Dòng hướng dẫn nằm ở cuối màn hình gồm: F1-Help, F5-Zoom, F6-switch, F7- Trace, F8-Step, F9-Make, F10-Menu. Gõ các phím chức năng đó sẽ kích hoạt một công việc, ví dụ chọn F10 sẽ kích hoạt Menu Bar v.v 6.2 Các lệnh soạn thảo văn bản. 1. Hãy quan sát dòng trạng thái để biết: -Tọa độ con trỏ màn hình: Dòng và Cột -Chế độ soạn thảo là viết Chèn (insert) hay viết Đè (Overwrite). -Chế độ nhảy vị trí đầu dòng khi ấn Enter: Indent. -Tên file đang soạn thảo và ổ đĩa chứa file đó, thí dụ C:\ TP\Name.pas. ELEC Trang 27
  28. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI 2. Các lệnh dịch chuyển con trỏ. Phím Home đưa con trỏ về đầu dòng. Phím End đưa con trỏ về cuối dòng. Phím PgUp đưa con trỏ lên một trang màn hình. Phím PgDn đưa con trỏ xuống một trang màn hình. Ctrl+ dịch con trỏ sang trái một chữ. Ctrl+ dịch con trỏ sang phải một chữ. Ctrl+PgUp đưa con trỏ về đầu văn bản Ctrl+PgDn đưa con trỏ về cuối văn bản. Phím Del Xoá ký tự tại vị trí con trỏ Phím BackSpace Xoá ký tự nằm bên trái con trỏ. Ctrl+Y Xoá cả dòng ký tự chứa con trỏ. Các dòng ở dưới sẽ dồn lên. Ctrl+Q Y Xoá phần cuối dòng kể từ vị trí con trỏ. Đánh dấu khối: Khối được đánh dấu bằng cách dịch trỏ tới vị trí đầu và gõ Ctrl_K B, dịch trỏ tới vị trí cuối và gõ Ctrl_K K. Sau đó khối sẽ chuyển mầu. Ctrl_K C Copy khối tới vị trí mới của con trỏ. Ctrl_K V Chuyển khối tới vị trí mới của con trỏ. Ctrl_K Y Xoá cả khối Ctrl_K W Ghi khối vào một tệp trên đĩa. Nếu bạn ghi tên tệp là PRN thì tương đương với việc ghi khối sang máy in. Ctrl_K R Đọc một tệp từ đĩa vào, phần đọc vào được đánh dấu như khối. Ctrl_Q B và Ctrl _Q K đưa con trỏ về đầu khối và cuối khối. Ctrl_Q F Tìm kiếm (F: Find) một cụm từ mà bạn muốn. Ctrl_Q A Tìm kiếm và sau đó thay thế. Chương trình sẽ hỏi: Find: tìm gì Replace: thay bằng gì Option: tuỳ chọn các cách. U: tìm không phân biệt chữ to, nhỏ (Upcase). B: tìm từ vị trí con trỏ về đầu tệp. W: tìm trọn các từ, ví dụ: tìm thấy từ 'Ho' nhưng không tìm trong 'Hoang'. G: Tìm và thay thế từ đầu tệp (Global) N: tìm và thay thế mà không cần hỏi lại có thay hay không. Ctrl_L lặp lại công việc Ctrl _Q F hoặc Ctrl _Q A cuối c ùng. 6.3 Dịch và chạy chương trình. Sau khi soạn xong chương trình ta cho dịch và chạy chương trình bằng lệnh: Ctrl+F9. Dịch (Compile) chương trình vừa soạn thảo (gọi là chương trình nguồn) thành chương trình đích (executable), sau đó là chạy chương trình (Run). Hai bước này có thể được thực hiện bằng việc gõ Ctrl+F9 . ELEC Trang 28
  29. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Khi gõ Ctrl+F9, máy sẽ kiểm tra xem chương trình có lỗi không, nếu không có lỗi thì máy sẽ chạy luôn chương trình. Nếu có lỗi máy sẽ thông báo lỗi cụ thể để tìm và sửa lỗi. Ví dụ: Program DonGian; Begin y:=12.9; Writeln(' y = ',y); End. Khi dịch chương trình, con trỏ sẽ được đặt ở vị trí có lỗi và báo trên màn hình như sau: Error 3: Unknow identifier. Program DonGian; Begin y:=12.9; (vị trí con trỏ báo lỗi) Writeln ('y=',y); End. Nghĩa là chương trình không biết tên (định danh) này (y). Ta thấy sai vì biến y chưa khai báo ở mục Var. Hãy chữa lại như sau: Program DonGian; Var y: Real; Begin y:=12.9; Writeln (' y = ',y); End. Sau khi dịch ta thấy không báo lỗi nữa. Việc cho dịch và chạy có thể thực hiện bằng cách ấn Alt +C để v ào mục Compile trong Menu Bar. Sau đó chọn lệnh dịch: Compile hoặc Make ho ặc Build Turbo Pascal có thể để chương trình sau khi dịch ở trong bộ nhớ và cũng có thể để trên đĩa. Nếu để trong bộ nhớ, máy sẽ chạy nhanh h ơn song bộ nhớ sẽ bị chiếm chỗ nhiều và khi tắt máy chương trình để trong bộ nhớ cũng mất đi. Nếu dịch và lưu trên đĩa, ta sẽ có tệp kết quả với đuôi exe. Hãy ấn Alt+C để vào mục Compile và chuyển đổi mục Destination bằng cách ấn phím chữ cái D. Máy sẽ chuyển đổi để chọn một trong 2 cách Destination Disk hoặc Destination Memory. Trong các ví dụ trên chúng ta chỉ dùng một tệp để chứa toàn bộ chương trình. Nếu chương trình lớn nên thiết kế thành nhiều Modunm, mỗi modun được chứa trong một tệp chương trình nguồn, mỗi Modun có một nhiệm vụ ri êng của nó, tùy người lập trình thiết kế. Người ta thiết kế các modul này thành các đơn vị chương trình, được gọi là Unit (ta sẽ tìm hiểu Unit phần sau). Ta có thể dịch từng ELEC Trang 29
  30. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Unit một cách riêng biệt. Một Unit được dịch xong, nếu không có sửa đổi th ì lần sau máy sẽ không phải dịch lại Unit đó nữa. Ch ương trình chính được Turbo Pascal đặt trong tệp có tên là Primary file. · Primary file là tên file chứa chương trình chính (chứ không phải là Unit). Nếu chương trình chỉ có một file, không có Unit thì không phải quan tâm tới mục Primary file. Build là dịch toàn bộ chương trình chính (Primary file) cùng các Unit liên quan, cho dù các Unit không có sự thay đổi gì trước đó. · Compile là chức năng dịch những file nào đó thấy cần chứ không dịch hết như chức năng Build. Sau khi dịch xong không chạy chương trình như Ctrl +F9. · Make là chức năng dịch, nhưng chỉ dịch đúng một Unit mà ta đang soạn thảo. Sau khi dịch xong Unit sẽ được lưu với file *.PTU (Turbo Pascal Unit). 6.4 Khả năng bao hàm tệp Khi soạn thảo một chương trình quá dài, hoặc những đoạn chương trình đã hoàn chỉnh, ta có thể cắt đoạn chương trình đó ra các file khác được gọi là các file bao hàm. Sau đó tại chỗ cắt đi ta phải báo cho ch ương trình dịch đọc các file bao hàm với lời hướng dẫn. { $I FileName} Trong đó FileName là tên file bao hàm. Ví dụ với chương trình lúc ban đầu sau: Program BaoHam; Var X,y: Real; Procedure A; Begin End; Procedure B; Begin End; Begin End. Đánh dấu khối Procedure A, sau đó dùng Ctrl +W đ ể ghi sang File mới đoạn đã đánh dấu, với tên File là ThuTucA.Pas. Sau khi ghi xong xóa khối này đi và thay vào đó là lời hướng dẫn {$I ThuTucA.Pas}. Ta lại tiếp tục với Procedure B. Cuối cùng ta có tệp chứa chương trình còn lại như sau: Program BaoHam; ELEC Trang 30
  31. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Var X,y:Real; {$I ThuTucA.Pas}; {$I ThuTucB.Pas}; Begin End. Bài tập: Hãy dùng các thao tác soạn thảo để lập trình tìm nghiệm phương trình bậc hai, sau đó cho chạy chương trình và quan sát lỗi nếu có. Hãy làm quen với bao hàm tệp bằng cách lập 3 thủ tục ứng với DX =0, DX 0 (Câu1) sau đó dưa 3 thủ tục vào bao hàm và cho chạy thử. Hãy thử nghiệm trong trường hợp bao hàm tệp là một đoạn nào đó không trọn một thủ tục. Hãy dịch tệp nguồn thành tệp đích có đuôi *.EXE ELEC Trang 31
  32. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 7: Kiểu vô hướng liệt kê và kiểu đoạn con 7.1 Kiểu vô hướng liệt kê (Enumerated scalar type) Dữ liệu thuộc loại vô hướng như là một tập hợp các giá trị được sắp xếp theo một thứ tự tự nhiên. Khi khai báo một biến là kiểu vô hướng nào đó, nó có thể nhận một giá trị trong tập các giá trị đó. Pascal c òn cho phép người lập trình có thể tự định nghĩa ra các kiểu vô hướng mới bằng cách liệt kê các giá trị của kiểu vô hướng thông qua các tên do người lập trình đặt ra. Danh sách các giá trị này được đặt trong ngoặc đơn và được mô tả bằng một tên kiểu trong phần mô tả kiểu (phần Type). Kiểu vô hướng định nghĩa theo cách này được gọi là kiểu liệt kê. Thí dụ: Type Mau = (Do, Xanh, Vang, Trang ); Oto = (Toyota, Honda, Nisan); Biến vô hướng được định nghĩa sau đó như sau: Var Mau1, Mau2: Mau; Xe: Oto; Hoặc khai báo biến trực tiếp với mô tả kiểu như sau: Var Mau1, Mau2: (Do, Xanh, Vang, Trang); Xe: (Toyota, Honda, Nisan); Biến có thể nhận các giá trị của kiểu t ương ứng. Ví dụ: Mau1:=Xanh; Xe:=Honda; Một biến được định nghĩa là kiểu này không thể nhận giá trị của kiểu khác, ví dụ: Xe :=Do; Là sai vì khác kiểu. Trong kiểu vô hướng phần tử đầu tiên có số thứ tự là 0, phần tử thứ 2 có số thứ tự 1 v.v Các hàm sau đây được áp dụng cho kiểu vô hướng. · Hàm thứ tự ORD (X): Kết quả là số thứ tự của X trong kiểu vô hướng. Ví dụ: ORD(Vang) =2 (vì Vàng có số thứ tự là 2) ORD(Honda) = 1 (vì Honda có số thứ tự là 1) Với hàm ORD ta có thể so sánh hai giá trị vô hướng có cùng kiểu. Giá trị có số thứ tự lớn sẽ lớn hơn giá trị có số thứ tự nhỏ hơn. Như vậy số thứ tự liệt kê khi định nghĩa kiểu vô hướng cũng chính là thứ tự sắp xếp từ nhỏ đến lớn. Ví dụ với kiểu Xe ta có: Toyota<Honda<Nisan ELEC Trang 32
  33. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI · Hàm PRED (X) và SUCC (X) Hàm PRED (X) cho giá trị đứng trước X Hàm SUCC (X) cho ta giá trị tiếp theo của X. Ví dụ: Pred (Honda) = Toyota Succ(Honda) = Nisan Pred của giá trị đầu và Succ của giá trị cuối không có ý nghĩa . · Chuyển đổi kiểu dữ liệu Hàm ORD chuyển đổi một giá trị vô hướng sang giá trị nguyên. Turbo Pascal cho phép biến đổi ngược từ một giá trị số nguyên thành giá trị vô hướng đếm được theo cách viết. Tên_Kiểu (Số_nguyên). Ví dụ: Xe(2) cho giá trị Nisan Char(65) cho giá trị 'A' · Hiển thị kiểu liệt kê: Thủ tục Write hoặc Writeln chỉ hiển thị các giá trị thuộc kiểu vô h ướng chuẩn (Real, Integer, Byte, Char, Boolean) và không th ể hiển thị một giá trị thuộc kiểu vô hướng liệt kê. Ví dụ các câu lệnh sau là sai: Writeln (Xe(1)), Writeln (Xanh) Muốn hiển thị giá trị của biến vô hướng liệt kê, ta có thể dùng thủ thuật sau: IF Xe=Honda Then Writeln ('Honda'); · Đọc dữ liệu liệt kê: Thủ tục Read hoặc Readln cũng chỉ cho phép đọc v ào từ bàn phím các giá trị của các biến có kiểu vô hướng chuẩn. Chúng cũng không cho p hép đọc trực tiếp các giá trị kiểu liệt kê. Ví dụ ta không thể đọc biến Mau1 có giá trị l à Do bằng cách ấn các phím D, o. Ta có thể dùng phương pháp sau: Ví dụ: Type Mau = (Do, Xanh, Vang, Trang); Var I: integer; Mau1: Mau; Begin Readln(I); Mau1:= Mau(I); End. 7.2 Kiểu khoảng con (Sub-range Type) Nhiều trường hợp một biến có thể chỉ lấy giá trị trong một khoảng đ ược định bởi giá trị giới hạn dưới và giá trị giới hạn trên thuộc một kiểu vô hướng đếm ELEC Trang 33
  34. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI dược nào đó. Ví dụ tuổi thanh niên có thể được giới hạn từ 13 đến 35. Khi đó ta có thể định nghĩa ra kiểu khoảng con nh ư sau: Type ThanhNien =15 35; Var Tuoi :ThanhNien; Hoặc có thể định nghĩa trực tiếp: Var Tuoi : 15 35; Kiểu khoảng con có thể viết như sau: a b; Trong đó a là hằng cận dưới và b là hằng cận trên, a và b là hai hằng của cùng một kiểu vô hướng đếm được. Tất nhiên phải thoả mãn: a<b Kiểu khoảng con có những lợi ích: · Tiết kiệm ô nhớ · Có thể kiểm tra giá trị của biến khi chạy ch ương trình không được vượt ra khỏi giới hạn của khoảng con. Đây l à tác dụng chủ yếu của kiểu khoảng con . Một số ví dụ về kiểu khoảng con. Type Ngay = (ChuNhat, Hai, Ba, Tu, Nam, Sau, Bay); ChuCaiIn = 'A' 'Z'; Var Ch: ChuCaiIn; NgayLamViec: Hai Bay; Bài tập: 1. Hãy cho một ví dụ đơn giản về lập trình trong đó có dùng dữ liệu liệt kê, hãy viết chương trình và chạy thử 2. Hãy cho một ví dụ đơn giản về lập trình trong đó có dùng dữ liệu khoảng con, hãy viết chương trình và chạy thử 3. Khai báo sau thuộc loại khai báo nào, đúng hay sai? Type a=12 26; b='c' 'y'; c=3.14 7.34; ELEC Trang 34
  35. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 8: Lặp FOR, WHILE và REPEAT 8.1 Vòng lặp có số bước lặp xác định FOR Ví dụ: Giả sử ta phải hiển thị lên màn hình các số từ 1 đến 60, mỗi số chiếm một dòng: 1 2 . . 59 60 Việc này có thể thực hiện bằng 60 lệnh writeln nh ư sau: writeln(1); writeln(2); writeln(60); Cách này rõ ràng là quá dài dòng, để khắc phục tình trạng trên ta có thể thay thế bằng cách dùng lệnh For như sau: FOR i :=1 TO 60 DO Writeln(i); Vòng lặp này có nghĩa là cho i chạy từ 1 (giá trị đầu) tới 60 (giá trị cuối), ứng với mỗi giá trị của i, máy sẽ thực hiện lệnh sau Do, ở đây là hiển thị giá trị 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ị 1. Vì i còn nhỏ hơn giá trị cuối là 60 nên lệnh writeln(i) được thực hiện và kết quả được hiển thị là 1. 2. Sau đó i nhận giá trị tiếp theo, tức là i:=Succ(i). Lúc này i =2 và vẫn nhỏ hơn giá trị cuối là 60 nên lệnh writeln (i) vẫn được thực hiện và kết quả 2 được hiển thị. 3. Quá trình lại tiếp tục bước 2 cho đến khi i =61, lớn hơn giá trị cuối (60) thì dừng lại. Cách viết tổng quát của lệnh For như sau: FOR := TO DO Trong đó , v à là kiểu vô hướng đếm được. Nếu ta muốn hiển thị các số từ 60 đến 1 ta viết lại nh ư sau: FOR i:=60 DOWNTO 1 DO writeln(i); Tổng quát như sau: FOR := DOWNTO DO ; 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. Ví dụ 1: Tính tổng các số nguyên từ 10 đến 100: ELEC Trang 35
  36. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Program TinhTong; Var Tong, i: Integer; Begin Tong:=0; For i:= 10 To 100 Do Tong:= Tong+i; Writeln('Tong =', Tong); End. Ví dụ 2: Hiển thị các chữ cái hoa 'A' đến 'Z' ra màn hình. Program LenhFor; Uses Crt; Var Chr : Char; Begin Clrscr; For Chr:='A' To 'Z' Do Write(Chr:2); End. Kết quả hiện ra màn hình: A B C D E G H I J K L M N O P Q R S T U V W X Y Z Ví dụ 3: Lệnh For dựa trên kiểu liệt kê, chương trì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=Ng Then writeln('Ngay làm viêc '); End. Nếu sau Do có trên một lệnh hãy đặt trong Begin End. Ví dụ 4: Các vòng For lồng nhau For i:=1 To 10 Do For j:=i To 12 Do Begin k:= i+j; Writeln(k); End; ELEC Trang 36
  37. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI 8.2 Vòng lặp có số bước lặp không xác định Repeat và While. Dạng1: Dạng 2: Repeat While Do ; Begin Until ; ; End; Trong lệnh Repeat Until máy sẽ thực hiện cho đến khi có giá trị True thì ra khỏi vòng lặp. Nghĩa là làm trước thử sau. Còn trong vòng lặp While Do máy sẽ xem chừng nào có giá trị True thì thực hiện nằm giữa Begin và end. Còn khi có giá trị False thì ra khỏi vòng lặp. Ví dụ 1: Tính tổng sau: S = 1+1/22 + 1/32 + Dừng khi một số hạng nhỏ hơn 0.00000001. Program TinhTong; Var i: Integer; S,a,b: Real; Begin b:=0.00000001; a:=1; I :=1; S:=0; Repeat S:=S+a; i:=i+1; a:=1/(i*i); Until a b Do Begin S:=S+a; i:=i+1; a:=1/(i*i); ELEC Trang 37
  38. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI End ; Writeln ( ' Tổng = ', S: 12:10 ); End. Ví dụ 2: Tất nhiên với lặp For ta chuyển sang lặp Repeat hoặc While: Program TinhTong; Var Tong,i: Integer; Begin Tong:=0; i:=10; Repeat Tong:= Tong+i; i:=i+1; Until i>100; Writeln('Tong=',Tong); End. Hoặc While như sau: Program TinhTong; Var Tong,i: Integer; Begin Tong:=0; i:=10; While i<=100 Do Begin Tong:= Tong+i; i:=i+1; End; Writeln('Tong =', Tong); End. 8.3 Lệnh nhảy vô điều kiện GOTO Lệnh Goto 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í dụ: Program TinhTong; Label 3; Var ELEC Trang 38
  39. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Tong, I: Integer; Begin Tong:=0; i:=10; 3: Tong:= Tong+i; i:=i+1; if i<=100 Then Goto 3 Writeln('Tong =', Tong); End. Sự có mặt của Goto trong chương trình làm mất tính cấu trúc. Vì vậy nếu có thể được nên tránh dùng Goto. Một điều nữa 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. ELEC Trang 39
  40. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Bài tập: 1. Dùng vòng lặp For để in ra các ký tự có mã từ 65 đến 120 2. Dùng vòng lặp For lập trình để tính giai thừa n! (với n nhập từ b àn phím). 3. Tính S =1/1+1/2+1/2+ +1/n 4. Hãy lập trình giải bài toán: Trăm trâu trăm cỏ Trâu đứng ăn 5 Trâu nằm ăn 3 Lụ khụ trâu già Ba con một bó Hỏi mỗi loại có bao nhiêu con? Gợi ý: gọi x là số trâu đứng, y là trâu nằm, z là trâu già, ta có hệ phương trình vô định sau: X + Y+ Z=100 5X+3Y+1/3Z=100 hay X+Y+Z=100 15X+9Y+Z=300 Ta dùng 3 lệnh FOR như sau: For x:=1 to 100 Do For y:=1 To 100 Do For z:=1 to 100 Do IF ((X+Y+X)=100) AND ((15*X+9*Y+Z)=300)) then Begin Writeln('Trâu đứng là:',X); Writeln('Trâu nằm là:',Y); Writeln('Trâu già là:',Z); End; Bạn hãy lập trình chi tiết và chạy thử 5. Tìm chữ số x và y trong phép nhân sau: x9y.7x=xy90y Gợi ý: Ta thử bằng lênh For: For x:=0 to 9 Do For y:=0 To 9 Do IF ((x*100+90+y) * (70+x))=(x*10000+y*1000+90+y) Them Writeln(x,y); Hãy lập trình chi tiết và chạy thử. ELEC Trang 40
  41. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 9: Chương trình con (thủ tục và hàm). 9.1 Khái niệm về chương trình con: (Sub-program) Trong khi lập trình chúng ta thường gặp những đoạn chương trình được lặp đi lặp lại nhiều lần ở những chỗ khác nhau. Để tránh r ườm rà, những đoạn chương trình này được thay thế bằng một chương trình con và khi cần ta chỉ việc gọi chương trình con đó với các tham số tương ứng cần thiết. Nếu một chương trình rất dài, sẽ khó khăn cho việc gỡ rối, hiệu chỉnh. Ta có thể phân chia b ài toán thành các bài toán con, mỗi bài toán con ứng với một chương trình con và như vậy sẽ dễ dàng kiểm tra gỡ rối. Việc chia nhỏ ch ương trình thành các Modul nhỏ có thể ví như nguyên tắc " Chia để trị". Chương trình con được dùng rất phổ biến. Vì vậy chúng ta cần nắm vững các kỹ thuật lập chương trình con. 9.2 Procedure và Function (Thủ tục và hàm T) Có hai loại chương trình con: Procedure (thủ tụct) • Function (hàmh). Sự khác nhau cơ bản của hai loại này là Function trả lại kết quả cho tên của Function, còn Procedure không trả lại kết quả thông qua tên của nó. Cấu trúc chung của một chương trình trong đó có phần khai báo chương trình con như sau: Program TenChuongTrinh; (*Tiêu đề *) Label (*Khai báo các nhãn *); Const (*Khai báo các hằng *); Type (*Mô tả kiểu M *); Var (*Khai báo các biếnK *); Procedure TenThuTuc (khai báo các tham sốk, nếu cần); (*Khai báo Label, Const, Type, Var của riêng Procedure, nếu cần *). Begin (*Thân chương trình conT *). End; Function TenHam(khai báo các tham sốk, nếu cần): kiểu _dữ _liệu; (*Khai báo Label, Const, Type, Var của riêng Procedure, nếu cần *). Begin (*Thân chương trình conT *). ELEC Trang 41
  42. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI End; Begin (* Thân chương trình*) End. Theo qui định này, LABEL trước, rồi đến CONST, TYPE, VAR cuối c ùng là các PROCEDURE, các FUNCTION. Phần nào không có thì bỏ đi, đương nhiên không thể thiếu phần thân chương trình chính. Để minh hoạ, chúng ta xét một chương trình sau: Ví dụ 1: Program PhuongTrinhBacHai; Uses Crt; Var A,b,c,dx,x1,x2: Real; Procedure Vao; Begin Write(' Vào hệ số a ='); Readln(a); Write(' Vào hệ số b ='); Readln(b); Write(' Vào hệ số c ='); Readln(c); End; Procedure TinhDelta; Begin Dx:=b*b-4*a*c; If dx>=0 Then DeltaKhongAm Else DeltaAm; End; Procedure DeltaKhongAm; Begin x1:=(-b+Sqrt(dx))/(2*a); x2:=(-b-Sqrt(dx))/(2*a); End; Procedure DeltaAm; Begin Writeln('Phương trình vô nghiệm'); End; Begin Vao; TinhDelta; End. Trong chương trình trên, tất cả các biến đều được khai báo ở chương trình chính, các biến ấy được gọi là biến toàn cục, biến toàn cục có ý nghĩa trong toàn bộ chương trình (nghĩa là các chương trình con đều dùng được). Trong chương trình con cũng có phần khai báo riêng của nó, các biến đó gọi là biến cục bộ. Biến cục bộ chỉ có ý nghĩa trong chương trình con đó mà thôi. ELEC Trang 42
  43. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Cấu trúc chung của procedure và function như sau: Procedure (Khai báo các tham số hình thứcK); Begin (*Thân chương trình conT *) End; và Function như sau: Function (khai báo các tham s ố hình thứck): kiểu_dữ_liệu_của _hàm; Begin (*Thân chương trình conT *) End; Kết thúc chương trình con bằng dấu chấm phẩy (;)không phải l à dấu chấm k (.)như chương trình chính.n 9.3 Chuyển tham số cho chương trình con. Chương trình con có thể được tính toán trực tiếp với các biến toàn cục hoặc tự khai báo biến cục bộ của nó và khi khai báo cục bộ thì phải truyền tham số cho chương trình con. Có hai cách truyền tham số: truyền tham biến (variable parameter) và truyền tham trị (value parameter). Sau đây l à nội dung cụ thể. 1. Không cần biến cục bộ Ta lấy một ví dụ đơn giản là: Vào hai số, tính tổng và in kết quả. Program TongHaiSo; USES CRT; Var S,a,b :Real; Procedure VaoHaiSo; Begin Write (' a='); Readln(a); (*a là biến toàn cục *) Write (' b='); Readln(b); (*b là biến toàn cục *) End; Procedure TinhTong; Begin S:=a+b; (*S là biến toàn cục *) End; Begin VaoHaiSo; TinhTong; ELEC Trang 43
  44. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Writeln ('S=',S); End. Ở trên ta thấy s, a, b khai báo ở chương trình chính (toàn cục) và 3 biến đó được dùng trong cả hai thủ tục. Nghĩa là biến toàn cục có ý nghĩa trong toàn bộ chương trình. Cách thiết kế theo kiểu đó có nhược điểm là các chương trình con phải biết biến khai báo ở chương trình chính thì mới viết được chương trình con. Điều đó sẽ bất tiện khi chương trình lớn mà ta phải phân cho nhiều người viết (vì phải phụ thuộc biến ở chương trình chính) 2. Dùng biến cục bộ và truyền tham số Ta viết lại chương trình trên theo kiểu "ít lệ thuộc" vào chương trình chính như sau: Program TongHaiSo; Uses Crt; Var S,a,b:Real; (*S,a, b là biến toàn cục*) Procedure VaoHaiSo(Var x,y:Real); Begin Write (' x='); Readln(x); (*x là biến cục bộ *) Write (' y='); Readln(y); (*y là biến cục bộ *) End; Procedure TinhTong(Var Tong:Real; P,Q:Real); Begin Tong:=P+Q; (*Tong,P, Q là biến cục b?*) End; Begin VaoHaiSo(a,b); TinhTong(S,a,b); Writeln ('S=',S); End. Giải thích: Giả sử khi chạy chương trình gặp thủ tục VaoHaiSo(Var x,y:Real), ta gõ vào hai số 2 và 3 (nghĩa là x =2 và y =3). Thủ tục VaoHaiSo(Var x,y:Real), điều này nói lên là x, y là tham biến (hay còn gọi là tham biến biến), vì sao vậy? Bởi vì khi ta gọi: VaoHaiSo(a,b) thì x chuyển giao giá trị cho a và y cho b. Nghĩa là trước khi gọi a và b có giá trị 0 sau khi gọi a =2 và b =3 (giá trị do x và y chuyển giao cho) tức là a, b có thay đổi giá trị (chữ Var trước x và y có ý nghĩa như vậy). Giả sử ta bỏ chữ Var và thủ tục bây giờ là VaoHaiSo(x,y:Real). Khi chạy chương trình thì trước và sau khi gọi thì a và b đều có giá trị 0, mặc dù ta vẫn gõ vào x =2 và y =3. Thủ tục TinhTong(Var Tong:Real; P,Q:Real); thì biến Tong cũng là tham biến biến vì trước khi gọi s =0 và sau khi gọi s =5. Còn P, Q là tham biến trị, vì sao vậy? Vì khi ta gọi: TinhTong(s,a,b) thì a và b trước khi gọi có giá trị a ELEC Trang 44
  45. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI =2, b=3 và sau khi gọi cũng vậy nghĩa là không thay đổi giá trị. Vậy là khi nào thì cần tham biến biến và khi nào thì cần tham biến trị là ở ý nghĩa trên. 3. Sự khác nhau giữa Function và Procedure Function là một chương trình con để tính toán một giá trị nào đó, bên trong Function bắt buộc ta phải có một lệnh gán giá trị kết quả cho t ên hàm: Tên_Hàm:= ; Khi lập trình ta nên quyết định là sử dụng Procedure hay Function: Chương trình con nên là Function khi các yêu cầu sau thoả mãn: Nếu ta muốn nhận lại duy nhất một kết quả. · Kết quả đó phải là kiểu vô hướng. Còn nếu không thì chương trình con nên là Procedure. Ví dụ đơn giản là lập chương trình con tính bình phương của một số. Nếu dùng Function, ta có: Function BinhPhuong(x: real): Real; Begin BinhPhuong:= x*x; End; Nếu dùng Procedure, ta có Procedure BinhPhuong(x: Real; Var y: Real); Begin y:= x*x; End; Cả hai trường hợp x đều là tham trị. Còn nếu dùng Function thì bản thân tên của Function (BinhPhuong) được dùng làm tham biến để chứa kết quả tính toán như biến y ở cách dùng Procedure. Hãy quan sát cách tính s = x 3 +y3 + v3 +z3 trong hai trường hợp: Nếu dùng Function: S: = LapPhuong(x) + LapPhuong(y) +LapPhuong(v)+LapPhuong(z); Program TinhTong; Var S,x,y,v,z:Real; Function LapPhuong(u:Real):Real; Begin LapPhuong:=u*u*u; End; Begin x:=3; y:=5; v:=7;z:=2; s:=LapPhuong(x)+LapPhuong(y)+LapPhuong(v)+LapPhuong(z); Writeln('s=',s); End. Nếu dùng Procedure ta có: Program TinhTong; ELEC Trang 45
  46. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Var Tong,a,b,c,d:Real; Procedure LapPhuong(Var s:Real; x,y,v,z:Real); Begin S:=x*x*x+y*y*y+v*v*v+z*z*z; End; Begin a:=3; b:=5; c:=7;d:=2; LapPhuong(Tong,a,b,c,d); Writeln('Tong=',Tong); End. Ta thấy trong trường hợp này dùng Function ngắn hơn vì ta có thể lập Function chỉ với một biến. Ngoài ra giả sử nếu trong chương trình còn có thêm điều kiện là chỉ cộng vào khi lập phương của một số là dương: Nếu dùng Function, ta chỉ việc viết: If LapPhuong(x) > 0 Then s:=s+LapPhuong(x) Còn nếu dùng Procedure thì phức tạp hơn nhiều. 4. Biến toàn cục, biến cục bộ và tầm hoạt động của biến. Như đã nói ở trên, các biến được khai báo trong chương trình chính được gọi là các biến toàn cục. Các biến này có tầm hoạt động trong toàn bộ chương trình. Các biến được khai báo trong một chương trình con được gọi là biến cục bộ và chỉ có tầm hoạt động trong chương trình con đó hay trong các chương trình con khác chứa trong nó mà thôi. Khi chương trình con kết thúc thì các biến này cũng mất tác dụng theo. Giả sử ta có ch ương trình sau: Program TamHoatDong; Var a,b,c:Real; Procedure ThuTucA; Var x,y:Real; Procedure ThuTucB; Var v,z:Real; Begin End; Begin End; Begin End. Ta nhận thấy: ELEC Trang 46
  47. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Biến a,b,c: Có tầm hoạt động là toàn bộ chương trình Biến x,y : Có tầm hoạt động trong ThuTucA và tất nhiên cả trong ThuTucB (vì ThuTucB nằm trong ThuTucA) Biến v,z: Có tầm hoạt động chỉ trong ThuTucB. 5. Tính đệ quy của chương trình con. Trong Procedure hoặc Function có thể có lời gọi đến chính nó. Tính chất n ày được gọi là tính đệ quy. Ví dụ: Function DeQuy( : ); Begin DeQuy( ); (*Gọi đến chính nó *) End; Ví dụ tính giai thừa n! = 1.2.3 (n-1).n Ta có thể định nghĩa: Nếu n =0 thì n!=1 Nếu n >1 thì n!=(n-1)!.n Và Function được định nghĩa đệ quy như sau.: Function GiaiThua( n: Integer): Integer; Begin If n = 0 Then GiaiThua:=1 Else GiaiThua:= n * GiaiThua(n - 1); End; Nếu không dùng đệ quy thì: Function GiaiThua(n: Integer): Integer; Var i, P: Integer; Begin i :=1; P :=1 ; (*P là biến cục bộ để chứa kết quả trung gian *) While i <= n DO Begin k:=k*i; I:= i+1; End; GiaiThua:=P; (*gán kết quả từ biến P vào tên hàm *) End; Nếu không dùng đệ quy, ta chỉ cần hai ô nhớ cục bộ i v à P, còn dùng đệ quy mỗi lần dùng GiaiThua (n), máy phải bố trí thêm một ô nhớ chứa kết quả GiaiThua trung gian. ELEC Trang 47
  48. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Nói chung không phải lúc nào dùng đệ quy cũng có lợi. 6. Đơn vị chương trình (Unit) Trong Turbo Pascal có nhiều đơn vị chương trình (Unit) trong đó chứa những chương trình con mà khi cần đến người lập trình chỉ cần gọi chúng bằng những tên cụ thể. Ví dụ đơn vị CRT là Unit chứa các chương trình con xử lí màn hình như thủ tục: GOTOXY, ClrScr,v.v Printer là Unit chứa các thủ tục in như Writeln (Lst, ). DOS Là Unit chứa các hàm của DOS. SYSTEM là Unit chứa các chương trình con về hệ thống. GRAPH là Unit về đồ hoạ v.v Ngoài ra Unit cũng có thể do chính người lập trình tự tạo. Một Unit do bạn tạo ra sẽ được chứa trong một file, giả sử File có t ên DonVi.PAS. Cấu tạo tổng quát của Unit tự tạo nh ư sau: Unit DonVi; (*Tên Unit đặt trùng với tên File *) Uses ; Interface (*Phần khai báo các thủ tục và hàm P *) Implementation (*Khai báo dữ liệu và các thủ tục và hàm của Unit này *) End. (*Kết thúc Unit bằng End có dấu chấm *) Ví dụ ta viết lại chương trình giải phương trình bậc hai bằng Unit Unit PTBHai; Uses Crt; Interface a,b,c,dx,x1,x2: Real; Implementation Procedure Vao; Begin Write(' Vào hệ số a ='); Readln(a); Write(' Vào hệ số b ='); Readln(b); Write(' Vào hệ số c ='); Readln(c); End; Procedure TinhDelta; Begin Dx:=b*b-4*a*c; If dx>=0 Then DeltaKhongAm Else DeltaAm; End; Procedure DeltaKhongAm; Begin x1:=(-b+Sqrt(dx))/(2*a); x2:=(-b-Sqrt(dx))/(2*a); ClrScr; Writeln('x1=',x1); Writeln('x2=',x2); ELEC Trang 48
  49. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI End; Procedure DeltaAm; Begin Writeln('Phương trình vô nghiệm'); End; End. Cách gọi Unit trong chương trình: Program PhuongTrinhBacHai; Uses Crt, PTBHai; Begin ClrScr; Vao; TinhDelta; End. 7.Chương trình con là thành phần của Turbo Pascal. Các chương trình con là thành phần của Turbo Pascal bao gồm: Các hàm số học: ABS, ARCTAN, COS, SIN, EXP, LN, SQRT,SQR. Các hàm vô hướng: SUCC, PRED, ODD. Các hàm chuyển đổi: CHR, ORD, ROUND, TRUNC. Hàm Frac (x) cho giá trị là phần thập phân của x Hàm Int (x) cho giá trị là phần nguyên của x Hàm Random, cho giá trị là số ngẫu nhiên nằm trong khoảng 0 và 1 Hàm Random (n), cho giá trị số thực nằm trong khoảng 0 và n (n là số nguyên) Thủ tục Randomize, là thủ tục đảm bảo cho hàm Random chạy với một số ngẫu nhiên. Nên gọi thủ tục này trước khi gọi Random. Hàm Upcase (ch), cho ký tự chữ lớn tương ứng với Ch. Hàm KeyPressed (trong Crt), hàm cho k ết quả True nếu ta gõ một ký tự, False nếu không gõ. Hàm ReadKey (trong Crt), đọc một ký tự từ bàn phím. Thủ tục GotoXY ( X, Y); ( trong Crt) Hai hàm Wherex, Wherey cho toạ độ con trỏ. Thủ tục ClrScr; (trong Crt), xoá toàn bộ màn hình và đặt con trỏ vào vị trí phía trên, bên trái. Thủ tục ClrEof; (trong Crt), xoá to àn bộ các ký tự bên phải con trỏ màn hình, sau khi xoá con trỏ vẫn ở nguyên tại chỗ. Thủ tục DelLine; (trong Crt), xoá toàn bộ dòng màn hình chứa con trỏ, sau đó dồn các dòng ở phía dưới lên. Thủ tục InsLine; (trong Crt*), xen một d òng trắng vào màn hình từ vị trí con trỏ. ELEC Trang 49
  50. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Thủ tục LowVideo và NormVideo; (trong Crt), sau khi g ọi LowVideo, mọi ký tự hiện ra màn hình đều có độ sáng yếu cho tới khi gọi thủ tục NormVideo. Thủ tục Delay(Time); (trong Crt), tạo ra khoảng thời gian trễ (khoảng ms). Time là một số nguyên. Delay thường được dùng để làm chậm chương trình lại cho ta quan sát, khảo sát Thủ tục Sound(F) và NoSound; tạo ra âm thanh với tần số là F ( F: số nguyên) cho đến khi ta gọi NoSound. Thủ tục Halt (trong system), dừng hoạt động ch ương trình và trở về hệ điều hành. Thủ tục Exit, khi gặp thủ tục này trong chương trình con thì kết thúc chương trình con đó và quay về chương trình gọi nó. V.v Ví dụ 1: Dùng Sound(F), Delay(n) và NoSound đ ể phát âm, kéo dài và tắt âm thanh Program AmThanh; Uses Crt; Var i: Integer ; Begin For i:=100 To 1000 Do Begin Sound(i); Delay(50); Nosound; End; End. Ví dụ 2: Dùng hàm Random để tạo các số ngẫu nhiên và dùng hàm Keypressed để điều khiển. Program TaoSoNgauNhien; Uses Crt; Procedure NgauNhien; Var Ch: Char; Begin Randomize; Repeat Writeln(Random); Until Keypressed; End; Begin ELEC Trang 50
  51. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI NgauNhien; End. Câu hỏi và bài tập: Thế nào là biến toàn cục và biến cục bộ cho ví dụ? Nói rõ sự khác nhau giữa tham biến biến v à tham biến trị? Khi nào thì cần tham biến biến? Cho ví dụ minh hoạ Khi nào thì cần tham biến trị? Cho ví dụ minh hoạ Để đỡ rắc rối trong việc truyền tham biến nhiều khi ta khai báo biến to àn cục cho mọi chương trình con, nhưng phương pháp này có hạn chế gì? hãy chỉ ra X là biến toàn cục, trong thủ tục A cũng có khai báo biến X (cục bộ), đứ ng trong A nếu dùng X thì X đó là gì? (toàn cục hay cục bộ) Cho xâu a ='0123456789' hãy lập một chương trình con đảo thành a ='9876543210', bạn thử viết cho cả đệ quy và không đệ quy. Lập trình (theo kiểu thủ tục) giải phương trình bậc nhất hai ẩn sau: ax+by=c dx+ey=f ELEC Trang 51
  52. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 10: Kiểu dữ liệu có cấu trúc - Kiểu mảng Chúng ta đã làm quen với các kiểu dữ liệu: Integer, Char, Boolean, Real, Liệt k ê và Khoảng con. Trong Pascal tồn tại các kiểu dữ liệu khác đ ược tạo ra từ các phần tử có kiểu dữ liệu đơn giản trên. Dữ liệu đó được gọi là dữ liệu có cấu trúc (vì nó có tính cấu trúc). Trong Pascal có 4 kiểu dữ liệu có cấu trúc đó là: Mảng (array), tập hợp (set), bản ghi (record) và tệp (file). 10.1 Mảng (array) Mảng là một dữ liệu có cấu trúc bao gồm một số hữu hạn phần tử có cùng kiểu. Số phần tử của mảng được xác định khi định nghĩa mảng. Mỗi phần tử của mảng được biểu diễn thông qua tên mảng cùng với chỉ số nằm trong mở và đóng ngoặc vuông []. Giả sử ta có 1 mảng 10 phần tử nguyên ta định nghĩa kiểu mảng như sau: Type A = ARRAY [1 10] Of Integer; Việc khai báo một biến mảng B được viết như sau: Var B:A; Chú ý: 1 10 là một khoảng con, ý muốn nói các phần tử của mảng dựa theo chỉ dẫn đó. Ta cũng có thể khai báo trực tiếp biến B nh ư sau: Var B: ARRAY [ 1 10] Of Integer; Một số ví dụ về định nghĩa mảng như sau. Ví dụ 1: Type A=Array[1 5] of integer; B=Array[1 5] of char; Color = (Do, Vang, Xanh, Den); Var X,Y: A; M,N: B ; K: Array[ 'A' 'F'] Of Integer; P: Array[Color] Of Boolean; A, B là hai kiểu mảng gồm 5 phần tử được đánh số thứ tự từ 1 đến 5 thông qua kiểu chỉ dẫn là một khoảng con: 1 5. Các phần tử của A có kiểu nguy ên, còn các phần tử của B có kiểu ký tự. X, Y là các biến có kiểu A v.v K là một biến mảng gồm 6 số nguyên được đánh số qua chỉ dẫn là các chữ cái từ 'A' cho đến 'F'. ELEC Trang 52
  53. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI P là một mảng gồm 4 phần tử kiểu Boolean, các phần tử đ ược đánh dấu qua chỉ dẫn là tên của 4 mầu sắc. Khi khai báo mảng, kiểu chỉ dẫn chỉ có thể là kiểu đơn giản như: ký tự, khoảng con, liệt kê và Boolean. Kiểu chỉ dẫn không được là Real hoặc Integer. Nghĩa là sai nếu viết. Type A= Array[Real] of integer; Phần tử của mảng được xác định qua biến mảng và giá trị chỉ dẫn để trong ngoặc vuông. Ví dụ: K['A']:=12; X[2]:=3; P[Do]:=False; v.v Sau đây là một số ví dụ. Ví dụ 1: Vào 5 giá trị cho mảng nguyên Program VaoMangNguyen; Uses Crt; Type A=Array[1 5] of Integer; Var i: Integer; X:A; Begin For i:=1 To 5 Do Begin Write( ' X [',i, '] = ' ); (*Tạo chỉ dẫn để biết mà gõ vào *). Readln (X[i] ); (*Vào số nguyên qua bàn phím *). End; End. Khi chương trình chạy, máy sẽ hiện ra tên phần tử và chờ ta gõ vào: X [1] = 1 X [2] = 2 X [3] = 4 X [4] = 3 X [5] = 2 Ví dụ 2: Tổng hai mảng Program TongHaiMang; Uses Crt; Type A=Array[1 5] of Integer; Var i: Integer; Z, X, Y:A; Begin ClrScr; Writeln('Vào mảng X'); ELEC Trang 53
  54. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI For i:=1 To 5 Do Begin Write( ' X [',i, '] = ' ); (*Tạo chỉ dẫn để biết mà gõ vào *) Readln (X[i] ); (*Vào số nguyên qua bàn phím *) End; Writeln('Vào mảng Y'); For i:=1 To 5 Do Begin Write( ' Y [',i, '] = ' ); (*Tạo chỉ dẫn để biết mà gõ vào *) Readln (Y[i] ); (*Vào số nguyên qua bàn phím *) End; Writeln('Tính tổng Z:=X+Y'); For i:=1 To 5 Do Z[i]:=X[i]+Y[i]; (*Tính tổng hai mảng *) End. Ví dụ 3: Giả sử ta muốn biết trong 50 lần g õ vào phím chữ cái trên bàn phím (ở chế độ chữ nhỏ), có bao nhiêu lần gõ vào mỗi loại chữ cái nhỏ từ 'a' đến 'z'. Program ChuongTrinhDem; Uses Crt; Var i : integer; Chr : Char A: Array[ 'a' 'z'] Of Integer; Begin For Chr := 'a' To ' z' Do A[Chr] :=0; (*Xoá mảng A *) For i:=1 To 50 Do Begin Readln (Chr); A[Chr] :=A[Chr] + 1;(* đếm số lần xuất hiện *) End; For Chr:= 'a' To 'z' Do If A[Chr] > 0 Then Writeln ('Chu ', Chr, ' = ' , A[Chr] : 3); End. 10.2 Xếp mảng. Việc sắp xếp các phần tử của mảng tăng hoặc giảm dần l à một việc hay xảy ra trong cuộc số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ụ. Sau đây là ví dụ về việc xếp mảng. ELEC Trang 54
  55. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Đầu tiên đem phần tử thứ nhất lần lượ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, phần tử đầu tiên giữ giá trị nhỏ nhất. Tiếp tục vòng hai, đem phần tử thứ hai so sánh với các phần tử tiếp theo Program XepMang; Uses Crt; Const N=10 ; Var a: Array[1 N] Of Integer; tg: Integer ; (*tg là biến trung gian *) i,j: Integer; Begin ClrScr; (*Vào mảng *) For i:=1 To n Do Begin Write (' Vào a [' ,i ,' ] = '); Readln (a[i]); End; (*xếp mảng lớn dầnx *) For i:=1 To n-1 Do For j:=i+1 To n Do Begin If a[i] >a[j] Then Begin (*đổi chỗ phần tử cho nhau® *) tg:=a[i]; a[i]: = a[j]; a[j]:= tg; End; End; (*In ra kết quả I*) For i:=1 To n Do Writeln (a[i]:5); End. Ví dụ 2: Cộng hai ma trận cùng số dòng và cùng số cột: c(m,n) = a(m,n)+b(m,n) Program TongHaiMaTran; Const m =3; n=4; Var a, b, c: Array [1 m, 1 n ] Of Integer; i, j, k: Integer; Begin ELEC Trang 55
  56. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI (*Vào dữ liệu cho ma trận aV *) For i:= 1 To m Do For j:= 1 To n Do Begin Write( 'a[', i, ',' , j, '] =' ); Readln (a[i, j] ); End; (*Vào dữ liệu cho ma trận bV *) For i:= 1 To m Do For j := 1 To n Do Begin Write( 'b[', i, ',' , j, '] =' ); Readln (b[i,j] ); End; (*Cộng hai ma trậnC *) For i:=1 To m Do For j:= 1 To n Do c[i,j]:=a[i,j]+b[i,j]; (*Hiển thị ma trận CH *) For i:=1 To m Do Begin For j:= 1 To n Do Write (C [I, J] : 5 ); (*In một hàng *) Writeln; End; End. Trong chương trình trên, việc vào dữ liệu cho ma trận được tiến hành theo từng dòng. Ví dụ 3: Ví dụ 2 được viết lại theo kiểu thủ tục: Program TongHaiMaTran; Const m =3; n=4; Type Mang= Array [1 m, 1 n] Of Real; Var a,b,c: Mang; Procedure VaoMang(Var x, y: Mang); Var i, j : Integer; Begin (*Vào dữ liệu cho ma trận xV *) For i:= 1 To m Do For j:= 1 To n Do ELEC Trang 56
  57. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Begin Write( 'x[', i, ',' , j, '] =' ); Readln (x[i, j] ); End; (*Vào dữ liệu cho ma trận yV *) For i:= 1 To m Do For j := 1 To n Do Begin Write( 'y[', i, ',' , j, '] =' ); Readln (y[i,j] ); End; End; Procedure TongHaiMaTran(x,y:Mang; Var Tong:Mang); Var I,j: Integer; Begin For i:=1 To m Do For j:= 1 To n Do Tong[i,j]:=x[i,j]+y[i,j]; End; Begin VaoMang(a,b); TongHaiMaTran(a,b,c); For i:=1 To m Do Begin For j:=1 To n Do Write(c[i,j]; Writeln; End; End. Câu hỏi và bài tâp: 1. Vào lương của 10 người sau đó tính tổng lương? 2. Vào tên củ 10 sinh viên sau đó xếp tên theo A,B,C 3. Vào dữ liệu cho ma trận có dạng sau: 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 Sau đó chuyển thành: 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 Nghĩa là nếu a [i,j]= 1 thì a[i,j]:= 0 và ngược lại. ELEC Trang 57
  58. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI 4. Tìm Max của mảng một chiều có 10 phần tử 5. Tìm Max của mảng A (10,12) 6. Cho hai mảng một chiều A và B hãy xếp hai mảng đó tăng dần sau đó trộn hai mảng đó thành mảng C theo trật tự sau: a[1],b[1],a[2],b[2] v.v. 7. Cho ma trận thực dạng A [1 10,1 10] hãy đưa vào 100 thành phần của nó là các số ngẫu nhiên (Random), sau đó tính tổng hai đường chéo chính. Tính tổng tất cả các phần tử, trừ các thành phần của hai đường chéo chính. 8. Giải phương trình bậc nhất hai ẩn bằng khai báo mảng ELEC Trang 58
  59. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 11: Xâu ký tự (STRING) 11.1 Định nghĩa xâu ký tự Một xâu ký tự được định nghĩa bằng từ khoá 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[n]; với n là độ dài cực đại của xâu. Ví dụ 1: Type Xau1= String [10]; Xau2= String [40]; Var A:Xau1; B: Xau2; Hay cũng có thể khai báo trực tiếp: Var A:String[10]; B:String[40]; Xâu ký tự chiếm số byte bằng số ký tự cực đại khi khai báo, cộng với một byte đầu tiên chứa số ký tự hiện có của xâu. Ví dụ 2: Var a,b:String[15]; Begin a:='Tin hoc'; End. Biến a khai báo ở trên được gán giá trị B: a:='Tin hoc'; a trong trường hợp này chỉ có độ dài 7 ký tự, mặc dù độ dài cực đại cho phép của biến a là 15. Như đã nói ở trên, byte đầu tiên để biểu diễn độ dài xâu ký tự. Vì độ dài xâu ký tự được biểu diễn bằng một byte nên ta thấy ngay rằng độ dài xâu ký tự chỉ nằm trong khoảng từ 1 đến 255. Người ta có thể hiểu String như là một mảng ký tự có chỉ số chạy từ 0 đến độ d ài cực đại, phần tử thứ 0 chứa độ dài thực của xâu. Song mảng ký tự có độ d ài luôn luôn không đổi. Ta có thể truy nhập vào từng ký tự của một xâu ký tự với tên biến và chỉ số đặt trong ngoặc vuông như khi truy nhập vào phần tử của mảng. Chỉ số này có thể chạy từ 1 tới độ dài cực đại của xâu ký tự. Ví dụ: Writeln(a[3]) sẽ cho chữ 'n' (*vì a:='Tin hoc'*) Nếu vị trí ký tự đó nằm ngoài độ dài thực của xâu thì phần tử đó của xâu không xác định. Vì vậy khi truy nhập vào từng phần tử của xâu ta 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. ELEC Trang 59
  60. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI 11.2 Các thao tác với xâu ký tự 1. Phép cộng xâu Ta dùng dấu cộng (+) để ghép hai xâu lại với nhau. Ví dụ: A:= 'Tin hoc'+' van phong' ; Trong biến a sẽ có: a:='Tin hoc van phong'. 2. So sánh xâu ký tự Xâu ký tự có thể được dùng trong các biểu thức so sánh: Khi so sánh hai xâu ký tự, các ký tự của hai xâu được so sánh từng cặp một từ trái qua phải theo giá trị của bảng m ã ASCII. Nếu hai xâu có độ dài khác nhau nhưng số ký tự đều giống nhau thì xâu có độ dài ngắn hơn được coi là bé hơn. Ví dụ: 'Tin hoc van phong'<'Tin hoc van phong trinh do A'; Cho giá trị True Hai xâu ký tự bằng nhau nếu như cả về nội dung lẫn độ dài của chúng là giống nhau. 'Tin hoc van phong'='Tin hoc van phong'; có giá tr ị True. 3. Khai báo String làm tham số cho chương trình con. Tương tự như Array, String có thể dùng làm tham số cho chương trình con. Ví dụ: Type a= String[10]; b=String[20]; Var x: a; y: b; Function HamXau:a; Procedure ThuTucXau(St: b); Khi dùng String làm tham số cho chương trình con, về nguyên tắc độ dài của tham số thực phải bằng độ dài của tham số hình thức. Ví dụ lời gọi sau là đúng: ThuTucXau(b); vì b (tham số thực sựt) có kiểu là a trùng với tham số hình thức là St cũng có kiểu là a. 4. Các thủ tục và hàm chuẩn xử lý xâu ký tự Trong Turbo Pascal có một số thủ tục và hàm để xử lý xâu ký tự như sau: Length (St) là hàm cho ta độ dài của xâu ký tự St. Ví dụ: với St:= 'Tin hoc'; thì length(St) có giá trị bằng 7. Delete (St, Pos,Num) Là thủ tục xoá đi Num ký tự từ vị trí Pos trong xâu St. Ví dụ với St:='Tin hoc'; Sau khi gọi Delete(St, 2, 3); St sẽ còn lại: Thoc. Insert (Obj, St, Pos) ELEC Trang 60
  61. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Là thủ tục xen xâu ký tự Obj vào xâu St tại vị trí Pos. Ví dụ với St = 'Tin hoc'; Obj = ' 23'; Sau khi gọi Insert(obj, St, 6); St sẽ thành ' Tin h23oc'. 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ố đó. Cách biểu diễn của St sẽ đ ược qui định do qui cách của Value. Ví dụ: i là một số nguyên bằng 52 với qui cách viết là 5 ký tự. Str (i:5, St) sẽ cho ra St = ' 52'; ( *5 ký tự *) giả sử X là số thực và bằng 123.5678901. Ta muốn biểu diễn X d ưới dạng 10 ký tự với 5 số thập phân. Str(X :10:5, St) sẽ cho kết quả St = ' 123.56789'; Val(St, Value, Code ) Là thủ tục biến đổi 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 value. Code l à số nguyên để phát hiện lỗi: nếu phép biến đổi mà đúng thì Code có giá trị 0, nếu sai do St không biểu diễn đúng số nguyên hoặc số thực, Code sẽ nhận giá trị bằng vị trí của ký tự sai trong xâu chữ St. Ví dụ X là biến thực, St = '123.56', Z là biến nguyên. Val (St, X, Z) cho ta X = 123.56 và Z = 0 thí dụ i là biến nguyên, St = '123', Z là biến nguyên. Val (St, i, Z ) cho ta i = 123 và Z =0; nếu St = ' 123X' tức là St không biểu diễn đúng số nguyên do có chữ X thì Val (St, i, Z ) cho ta i không xác định và Z=4; Ví dụ: Var St : String [4]; K,I : Integer; Begin Repeat Write('Vào xâu ký tự số nguyên St ='); Readln (St); (*Vào xâu ký tự số nguyênV *) Val (St, I, K); (*Chuyển St thành số nguyên IC *) If K <> 0 Then writeln (# 7, 'Lỗi!' ); Until z = 0; End; Copy (St, Pos, n) Hàm Copy sẽ nhận n ký tự trong St từ vị trí Pos. Ví dụ: St :='123456789 '; St1 là một xâu ký tự khác. St1: = Copy (St, 3, 2); sẽ cho St1 = '34'; Concat (St1, St2, , StN); ELEC Trang 61
  62. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI 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 số chiều dài của các xâu ký tự lớn hơn 255 thì máy sẽ báo lỗi. chúng ta cũng có thể dùng phép + để ghép nối xâu ký tự. 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í dụ: 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. ELEC Trang 62
  63. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 12: Kiểu bản ghi (RECORD) 12.1 Record là gì? Chúng ta đã biết về dữ liệu có cấu trúc như mảng (array). 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 kiểu. Ví dụ các phần tử của một Array [1 10] of Real là các số thực hay Array [1 10] of String[12] l à các xâu ký tự. Một dữ liệu có cấu trúc mới với các phần tử có kiểu khác nhau được gọi là bản ghi (tiếng Anh gọi là Record). Như vậy Record là một dữ liệu có cấu trúc mà các phần tử có kiểu khác nhau, điều đó nói l ên tính linh hoạt của nó trong việc thiết lập các dữ liệu phong phú trong cuộc sống. 12.2 Mô tả Record Để mô tả A có kiểu Record với các biến trường có tên là t1, t2, , tn và kiểu của biến trường tương ứng là: k1, k2, kn, ta có cách viết tổng quát như sau: Type A = Record t1 : k1; t2 : k2; tn : kn; End; Ví dụ 1: Một sơ yếu lý lịch bao gồm: Họ tên, Ngày sinh, Chức vụ, Văn hoá, Lương v.v Ta mô tả như sau: Type A = Record HoTen : String[25]; NgaySinh : String[8]; VanHoa : String[10]; Luong : Real; SoCon : Byte; End; Ta có 5 trường với kiểu: String, Real, Byte để mô tả một nhân sự n ào đó. Ví dụ 2: Để mô tả thời gian (ngày/Tháng /năm) ta mô tả một Record như sau: Type ThoiGian= Record Ngay : 1 31; Thang: 1 12; Nam : Integer; ELEC Trang 63
  64. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI End; Và ví dụ 1 có thể viết lại như sau: Type ThoiGian= Record Ngay : 1 31; Thang: 1 12; Nam : Integer; End; Type A = Record HoTen : String[25]; NgaySinh : ThoiGian; VanHoa : String[10]; Luong : Real; SoCon : Byte; End; Hay cũng có thể viết lồng nhau như sau: Type A = Record HoTen : String[25]; NgaySinh : Record Ngay : 1 31; Thang: 1 12; Nam : Integer; End; VanHoa : String[10]; Luong : Real; SoCon : Byte; End; 12.3 Vào - Ra Record Để xác định một trường của Record, ta cần phải dùng tên biến Record, dấu chấm và tên trường của Record. Ví dụ BanGhi.NgaySinh (BanGhi là biến Record, NgaySinh là biến trường của Record đó) Ví dụ 1: Vào dữ liệu cho bản ghi có tên NhanSu sau: Program VaoRaBanGhi; Uses Crt; Type A=Record HoTen : String[25]; ELEC Trang 64
  65. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI NgaySinh : String[8]; VanHoa : String[10]; Luong : Real; SoCon : Byte; End; Var NhanSu: A; Begin ClrScr; Write ( 'Vào họ tên? '); Readln ( NhanSu.HoTen); Write ( 'Vào ngày sinh? '); Readln ( NhanSu. NgaySinh); Write ( 'Vào văn hoá? '); Readln ( NhanSu. VanHoa); Write ( 'Vào lương?'); Readln ( NhanSu.Luong); Write ( 'Vào số con?'); Readln( NhanSu. SoCon); (* Hiển thị dữ liệu trên màn hình *) Writeln ( 'Họ tên: ',NhanSu.HoTen); Writeln ( 'Ngày sinh: ',NhanSu.NgaySinh); Writeln ( 'Trinh độ văn hoá:',NhanSu.VanHoa); Writeln ( 'Bậc lương:',NhanSu.Luong); Writeln ( 'Số con:',NhanSu.SoCon); End. Ở trên ta thấy biến NhanSu được viết lặp quá nhiều lần, do đó trong Turbo Pascal có sử dụng lệnh With Do để rút gọn quá trình đó, chương trình trên được viết lại như sau: Program VaoRaBanGhi; Uses Crt; Type A=Record HoTen : String[25]; NgaySinh : String[8]; VanHoa : String[10]; Luong : Real; SoCon : Byte; End; Var ELEC Trang 65
  66. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI NhanSu: A; Begin ClrScr; With NhanSu Do Begin Write ( 'Vào họ tên? '); Readln (HoTen); Write ( 'Vào ngày sinh? '); Readln ( NgaySinh); Write ( 'Vào văn hoá? '); Readln (VanHoa); Write ( 'Vào lương?'); Readln (Luong); Write ( 'Vào số con?'); Readln ( Con); (* Hiển thị dữ liệu trên màn hình *) Writeln ( 'Họ tên: ',HoTen); Writeln ( 'Ngày sinh: ',NgaySinh); Writeln ( 'Trinh độ văn hoá:',VanHoa); Writeln ( 'Bậc lương:',Luong); Writeln ( 'Số con:',SoCon); End; End. 12.4 Mảng các Record Ta thấy biến NhanSu ở trên chỉ "chứa" được một người, vậy trong một tổ chức có nhiều người thì xử lý thế nào? Tất nhiên ta phải dùng mảng. Ví dụ 1: Program VaoRaBanGhi; Uses Crt; Const n=10; Type A=Record HoTen : String[25]; NgaySinh : String[8]; VanHoa : String[10]; Luong : Real; SoCon : Byte; End; B=Array[1 n] Of A; Var NhanSu: B; ELEC Trang 66
  67. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI i: Integer; Begin ClrScr; For i:=1 To n Do With NhanSu[i] Do Begin Write ( 'Vào họ tên? '); Readln (HoTen); Write ( 'Vào ngày sinh? '); Readln ( NgaySinh); Write ( 'Vào văn hoá? '); Readln (VanHoa); Write ( 'Vào lương?'); Readln (Luong); Write ( 'Vào số con?'); Readln ( SoCon); (* Hiển thị dữ liệu trên màn hình *) Writeln ( 'Họ tên: ',HoTen); Writeln ( 'Ngày sinh: ',NgaySinh); Writeln ( 'Trinh độ văn hoá:',VanHoa); Writeln ( 'Bậc lương:',Luong); Writeln ( 'Số con:',SoCon); End; End. Ví dụ 2: Tính tổng số con và tổng lương của mảng NhanSu trên: Program VaoRaBanGhi; Uses Crt; Const n=10; Type A=Record HoTen : String[25]; NgaySinh : String[8]; VanHoa : String[10]; Luong : Real; SoCon : Byte; End; B=Array[1 n] Of A; Var NhanSu: B; i: Integer; TongCon, TongLuong: Integer; Begin ELEC Trang 67
  68. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI ClrScr; For i:=1 To n Do With NhanSu[i] Do Begin Write ( 'Vào họ tên? '); Readln (HoTen); Write ( 'Vào ngày sinh? '); Readln ( NgaySinh); Write ( 'Vào văn hoá? '); Readln (VanHoa); Write ( 'Vào lương?'); Readln (Luong); Write ( 'Vào số con?'); Readln ( SoCon); End; TongCon:=0; TongLuong:=0; For i:=1 To n Do With NhanSu[i] Do Begin TongCon:=TongCon+SoCon; TongLuong:=TongLuong+Luong; End; Writeln('Tổng con:',TongCon); Writeln('Tổng lương:',TongLuong); End. Câu hỏi và bài tập: Một nhân viên có các thông tin sau: Họ đệm Tên Ngày sinh Địa chỉ Bậc lương Số con Lập trình cấu trúc để xử lý các việc sau: a. Vào cho 10 nhân viên b. Tính tổng lương của toàn bộ nhân viên c. Sắp xếp lương nhân viên giảm dần d. Hãy in ra danh sách nhân viên đã xếp theo vần A,B,C Một thí sinh có các thông tin sau: · Họ đệm · Tên · Ngày sinh ELEC Trang 68
  69. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI · SBD · Khối thi · Phòng thi · Môn toán · Môn lý · Môn hoa · Tổng điểm · Khu vực Hãy lập trình cấu trúc chứa các thủ tục sau: a. Thủ tục Vao để vào bản ghi như trên b. Thủ tục TinhTong để tính tổng điểm c. Thủ tục XetTuyen để in danh sách đỗ: Đi ểm chuẩn >=16 nếu khu vực 3; Điểm chuẩn >=14 nếu khu vực 2 và điểm chuẩn >=12 nếu khu vực 1. ELEC Trang 69
  70. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Chương 13: Dữ liệu kiểu tệp (FILE) 13.1 Khái niệm về tệp Tệp là một tập hợp các dữ liệu có cùng kiểu và liên quan với nhau, được chứa trên một thiết bị nhớ ngoài của máy tính, thông thường nhất là đĩa mềm hoặc đĩa cứng và được xác định qua tên tệp. T là kiểu tệp với các phần tử có kiểu xác định đ ược mô tả như sau: Type T = File Of ; Ví dụ 1: Type TenSoNguyên= File Of Integer; TepSoThuc= File Of Real; TepBoolean = File Of Boolean; NhanSu = Record HoTen: String[30]; NgaySinh: String[8]; Lương: Real; End; TepNhanSu= File Of NhanSu; Var F1: TepSoNguyên; F2: TepSoThuc; TepLyLich: TepNhanSu; F3: File Of Array [1 15] Of Integer. F3 là biến tệp được khai báo trực tiếp với các phần tử l à mảng một chiều, độ dài mảng là 15. Kiểu phần tử của tệp có thể là bất kỳ (kiểu vô hướng, kiểu mảng, bản ghi), trừ kiểu tệp nghĩa là không có kiểu tệp của tệp. 13.2 Cấu trúc và phân loại tệp Các phần tử của Array hoặc Record có thể đ ược truy cập thông qua tên biến và chỉ dẫn hoặc tên trường. Các phần tử của tệp không có t ên, vậy truy cập như thế nào? Các phần tử của tệp được xếp thành một dãy, ở mỗi thời điểm chỉ có thể truy cập vào một phần tử của tệp thông qua giá trị của một biến trung gian. Biến trung gian này được dùng để lưu giá trị vị trí truy cập, hay còn gọi là con trỏ tệp. Tệp được kết thúc bằng một dấu hiệu đặc biệt. Khi gặp dấu hiệu n ày hàm Boolean Eof (f) (End of file) cho giá tr ị True. Nếu con trỏ tệp chưa trỏ vào phần tử này thì hàm Eof (f) có giá trị là False. ELEC Trang 70
  71. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Tệp có hai loại: Tệp truy cập tuần tự (sequential access) v à tệp truy cập trực tiếp (direct access). Việc đọc một phần tử bất kỳ của tệp có cấu trúc tuần tự bắt buộc phải đi qua các phần tử trước đó. Còn muốn ghi hay thêm một phần tử vào tệp, ta cần phải đặt con trỏ tệp vào vị trí cuối tệp. Kiểu truy cập này là đơn giản nhưng kém linh hoạt. Bộ nhớ ngoài điển hình tương ứng với cấu trúc tuần tự là băng từ. Tệp truy cập trực tiếp là tệp có thể đặt con trỏ tệp vào một phần tử bất kỳ của tệp thông qua số thứ tự của phần tử đó. Không phải bộ nhớ ngoài nào cũng có thể xây dựng tệp truy cập trực tiếp. Ví dụ băng từ l à loại chỉ có thể truy cập tuần tự. Còn đĩa mềm và đĩa cứng là loại ngoài việc xây dựng tệp tuần tự còn có thể tạo được truy cập trực tiếp do đầu đọc-ghi có thể được đặt vào một vị trí bất kỳ trên đĩa. Giống như băng ca nhạc muốn chọn một bài phải tua băng qua lại (bắt buộc truy cập tuần tự) với đĩa ca nhạc việc chọn một b ài chỉ việc cho máy biết chỉ số của bài đó (khả năng truy cập trực tiếp). 13.3 Mở tệp tuần tự mới để ghi dữ liệu v ào. Ta chỉ có thể ghi dữ liệu vào một tệp, sau khi mở tệp.Việc mở tệp thông qua hai thủ tục đi liền nhau như sau: Assign(F, FileName); Rewrite(F); Trong đó F là biến tệp và FileName là tên tệp. Ví dụ: Assign(F, 'SoNguyen.Dat'); (*Gán tên tệp SoNguyen.dat cho biến FG *) Rewrite(F); (*Mở tệp để ghi dữ liệu M *) Tên tệp theo qui đị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ó thể với số chữ nhiều nhất không quá 8. Phần thứ hai là phần mở rộng gồm nhiều nhất không quá 3. Sau khi mở tệp, tệp sẽ rỗng. Việc ghi các giá trị v ào tệp nhờ vào thủ tục WRITE: Write (Biến Tệp, Các giá trị cần ghi vào tệp); Ví dụ: Write (F1, 3 , 5, I, k+1,15); Sau khi hoàn tất của việc ghi dữ liệu là đóng tệp lại bằng thủ tục Close(Biến_Tệp); Ví dụ với tệp F ta viết: Close(F); Ví dụ 1: Tạo một tệp chứa các số lẻ từ 1 đến 99 với t ên tệp là: SoLe.dat. Program TaoTepSoLe; Var i: integer; F: File of Integer; Begin Assign (F, 'SoLe.dat'); Rewrite (F); i:=1; ELEC Trang 71
  72. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI While i<=99 Do Begin Write (F, i); i:=i+2; End; Close (F); End. Ví dụ 2: Một tệp có thể được dùng làm tham số của chương trình con, vớ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 biến. Program TaoTep; Type KieuTep = File of Integer; KieuTenTep= String[12]; Var BienTep:KieuTep; TenTep: KieuTenTep; Procedure TaoFile (Var F: KieuTep; Ten: KieuTenTep); Var i: Integer; Begin Assign (F, Ten); Rewrite (F); i:=1; While i<=99 Do Begin Write (F, i); i:=i+2; End; Close (F); Begin Write ('Hãy gõ tên tệp?'); Readln (TenTep); TaoFile (BienTep, TenTep); End. 13.4 Đọc dữ liệu từ một tệp tuần tự đã có. Tệp tuần tự cùng một lúc không thể vừa ghi lại vừa đọc đ ược. Nhưng sau khi ghi dữ liệu xong và đóng lại, ta có thể đọc lại được giá trị dữ liệu đó trong tệp. Muốn đọc dữ liệu thì phải mở tệp đó, công việc này như sau: Assign(Biến Tệp, Tên Tệp); (Gán tên tệp cho biến tệp) Reset (Biến Tệp); (mở tệp để đọc) ELEC Trang 72
  73. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Và lệnh đọc dữ liệu từ tệp như sau: Read (Biến Tệp, Các biến); Việc đọc một phần tử của tệp còn cần phải thử xem tệp có còn phần tử hay không: Việc cuối cùng sau khi kết thúc việc đọc tệp là đóng tệp lại: Close(Biến Tệp); Ví dụ 1V: Giả sử tồn tại một tệp có tên là SoLe.dat (mà ta vừa tạo trên) Ta phải đọc ra giá trị của nó và hiện lên màn hình. Program DocTep; Var a: Integer; F: File Of Integer; Begin Assign(F, 'SoLe.dat'); Reset(F); While Not Eof(f) Do Begin Read(F, a); (*Đọc phần tử thứ nhất của tệp ra biến a *) Writeln(a); End; Close (F); End. Ví dụ 2: Copy từ tệp sang một tệp khác. Chương trình được viết dưới dạng thủ tục như sau: Program ProSaoTep; Type F= File of Integer; Var F1, F2 : F; (*F1 là tệp nguồn, F2 là tệp đích *) FileName1, FileName2: String[12]; Procedure SaoTep; Var i : Integer; Begin Reset (F1); Rewrite (F2); While Not Eof (F1) Do Begin Read (F1, i ); Write(F2,i); End; ELEC Trang 73
  74. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Close (F1); Close (F2); End; Begin Write('Cho biết tệp nguồn?'); Readln(FileName1); Write(' Cho biết tệp đích?'; Readln (FileName2); Assign (F1 , FileName1); Assign (F2, FileName2); SaoTep; End. Ví dụ 3: Tệp mà các phần tử của nó là dữ liệu có cấu trúc, giả sử các phần tử l à Record: Program TepCoCauTruc; Uses Crt; Const n=10; Type A=Record HoTen : String[25]; NgaySinh : String[8]; VanHoa : String[10]; Luong : Real; SoCon : Byte; End; Var F: File of A; NhanSu: A; i: Integer; Begin ClrScr; Assign(F, 'LyLich.dat'); Rewrite(F); For i:=1 To n Do (*Tệp có n =10 phần tử, mỗi phần tử là một bản ghi *) With NhanSu Do Begin Write ( 'Vào họ tên? '); Readln (HoTen); Write ( 'Vào ngày sinh? '); Readln ( NgaySinh); Write ( 'Vào văn hoá? '); Readln (VanHoa); Write ( 'Vào lương?'); Readln (Luong); ELEC Trang 74
  75. TRUNG TÂM ĐÀO TẠO TRỰC TUYẾN - ĐẠI HỌC KINH DOANH & CÔNG NGHỆ H À NỘI Write ( 'Vào số con?'); Readln ( SoCon); Write(F, NhanSu); End; Close(F); Assign(F,'LyLich.dat'); Reset(F); While Not Eof(F) Do Begin Read(F,NhanSu); With NhanSu Do Begin Writeln('Họ tên:',HoTen); Writeln('Ngày sinh:',NgaySinh); Writeln('Trình độ văn hoá:', VanHoa); Writeln('Bậc lương:',Luong); Writeln('Số con:',SoCon); End; End; End. 13.5 Tệp truy cập trực tiếp Với bộ nhớ ngoài như đĩa mềm, đĩa cứng, ta có thể tính toán đ ược toạ độ của một phần tử bất kỳ của tệp. Điều đó có nghĩa l à ta có thể truy cập trực tiếp vào tệp mặc dù các phần tử của tệp vẫn là dạng tuần tự, nghĩa là phần tử nọ xếp sau phần tử kia. Thủ tục truy cập trực tiếp nh ư sau: SEEK (F, n); Trong đó F là biến tệp, n là số thứ tự của phần tử trong tệp. Với thủ tục này, máy sẽ đặt con trỏ tệp vào phần tử thứ n. Sau đó ta dùng thủ tục Read để đọc phần tử đó ra hoặc Write để đặt giá trị mới v ào. Ví dụ 1: Giả sử một tệp đã chứa các số lẻ từ 1 đến 99 (như đã tổ chức ở trên). Ta phải kiểm tra xem phần tử thứ thứ 4 (vị trí đầu có số thứ tự l à 0, thứ 2 là 1 v.v ) của tệp có giá trị bằng 9 hay không, nếu không thì đưa 9 vào vị trí đó. Program KiemTra; Var F: File of Integer; Ch : Char; i: Integer; Begin Assign (F, ' SoLe.dat') ; Reset (F); Seek(F, 4); (*Đặt trỏ tệp vào vị trí thứ 4*) ELEC Trang 75