1. Trang chủ
  2. » Giáo án - Bài giảng

Giao trinh Pascal

291 18 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Ðó là một tập các chỉ thị instruction được sắp xếp theo một trật tự định trước nhằm hướng dẫn máy tính thực hiện các thao tác, hành động cần thiết để đáp ứng một mục tiêu đã định trước c[r]

(1)I NGÔN NGỮ LẬP TRÌNH 1.1 Khái niệm ngôn ngữ lập trình & chương trình máy tính Con người liên lạc với thông qua ngôn ngữ, tạo các mẫu từ ngữ và âm Ngôn ngữ lập trình tương tự vậy, đó là tập từ ngữ và ký hiệu cho phép lập trình viên người dùng có thể nói chuyện với máy tính Cũng giống tiếng Anh, tiếng Tây Ban Nha tiếng Trung Quốc và ngôn ngữ tiếng nói khác, ngôn ngữ lập trình có các luật gọi là cú pháp (syntax) để đảm bảo ngôn ngữ đó vận dụng cách chính xác Ðó là tập các thị (instruction) xếp theo trật tự định trước nhằm hướng dẫn máy tính thực các thao tác, hành động cần thiết để đáp ứng mục tiêu đã định trước người truy xuất liệu, tìm kiếm, giải bài toán, Các thị này có thể viết nhiều ngôn ngữ lập trình khác 1.2 Các loại ngôn ngữ lập trình thông dụng Có hàng trăm loại ngôn ngữ lập trình khác nhau, loại ngôn ngữ có cú pháp riêng nó Một số ngôn ngữ thì phát triển để dùng trên các loại máy tính chuyên biệt, số ngôn ngữ khác thì - thành công nó - đã trở thành chuẩn và áp dụng trên đa số các máy tính Ngôn ngữ lập trình có thể phân chia thành loại chính : ngôn ngữ máy, hợp ngữ và ngôn ngữ cấp cao Ngôn ngữ máy Ngôn ngữ máy (mã máy) là ngôn ngữ tảng vi xử lý Các chương trình viết tất các loại ngôn ngữ khác cuối cùng chuyển thành ngôn ngữ máy trước chương trình đó thi hành Vì tập lệnh ngôn ngữ máy phụ thuộc vào loại vi xử lý nên ngôn ngữ máy khác trên máy tính có sử dụng vi xử lý khác Lợi điểm viết chương trình ngôn ngữ máy là lập trình viên có thể điều khiển máy tính trực tiếp và đạt chính xác điều mình muốn làm Do đó, các chương trình ngôn ngữ máy viết tốt là chương trình hiệu (tốc độ thi hành nhanh, kích thước nhỏ) Bất lợi chương trình ngôn ngữ máy là thông thường nhiều thời gian để viết, khó đọc, theo dõi để tìm lỗi Thêm vào đó, vì chương trình viết tập lệnh phụ thuộc vào vi xử lý nên chương trình chạy trên máy tính có cùng vi xử lý mà thôi Ngôn ngữ máy gọi là ngôn ngữ cấp thấp (low-level language) Hợp ngữ Hợp ngữ phát triển nhằm giúp các lập trình viên dễ nhớ các thị chương trình Hợp ngữ tương tự ngôn ngữ máy lại sử dụng các ký hiệu gợi nhớ (mnemonics hay mã lệnh hình thức - symbolic operation code) để biểu diễn cho các mã lệnh máy Một đặc điểm khác là hợp ngữ thông thường cho phép định địa hình thức (symbolic addressing), nghĩa là vị trí nhớ máy tính có thể tham chiếu tới thông qua cái tên ký hiệu, chẳng hạn TOTAL thay vì phải sử dụng địa thực nó (bằng số nhị phân) ngôn ngữ máy Các chương trình hợp ngữ còn bao gồm các thị vĩ mô (macro instruction) có thể tạo nhiều lệnh mã máy Các chương trình hợp ngữ chuyển sang mã máy thông qua chương trình đặc biệt gọi là trình hợp dịch (assembler) (2) Mặc dù hợp ngữ tương đối dễ dùng mã máy hợp ngữ xem là ngôn ngữ cấp thấp vì nó còn gần với thiết kế máy tính Ngôn ngữ cấp cao Cuộc cách mạng ngôn ngữ máy tính bắt đầu với phát triển ngôn ngữ cấp cao vào cuối thập kỷ 1950 và 1960 Ngôn ngữ cấp cao gần gũi với ý niệm ngôn ngữ mà hầu hết người biết, nó bao gồm các danh từ, động từ, ký hiệu toán học, liên hệ và các thao tác luận lý Các yếu tố này có thể phối hợp, liên kết với tạo thành hình thức câu Các "câu" này gọi là các mệnh đề chương trình (program statement) Chính vì đặc điểm này, các lập trình viên dễ dàng đọc và dễ học ngôn ngữ cấp cao so với ngôn ngữ máy hợp ngữ Một lợi điểm quan trọng là ngôn ngữ cấp cao thông thường không phụ thuộc vào máy tính, nghĩa là các chương trình viết ngôn ngữ cấp cao có thể chạy trên các loại máy tính khác (sử dụng các vi xử lý khác nhau) Các ngôn ngữ lập trình thông dụng Mặc dù đã có hàng trăm ngôn ngữ lập trình sinh ra, có số ít là sử dụng rộng rãi và xem là chuẩn công nghiệp Các ngôn ngữ này có thể sử dụng trên nhiều loại máy tính khác BASIC, viết tắt cụm từ Beginner's All-Purpose Symbolic Instruction Code, phát triển John Kermeny và Thomas Kurtz vào năm 1964 trường đại học Dartmouth Ban đầu, họ thiết kế BASIC là ngôn ngữ lập trình đơn giản, có tính tương tác để các sinh viên học tập và sử dụng BASIC đã trở thành ngôn ngữ lập trình thông dụng sử dụng trên các máy vi tính và máy tính mini ngày COBOL, viết tắt COmmon Business Oriented Language, giới thiệu vào năm 1960 Ðược hỗ trợ quốc phòng Hoa Kỳ, COBOL phát triển hội đồng bao gồm các đại diện từ phía chính phủ và công nghiệp Grace M.Hopper là người chính yếu hội đồng và xem là nhà phát triển chính ngôn ngữ COBOL COBOL đã là ngôn ngữ dùng rộng rãi cho các ứng dụng thương mại Bằng cách dùng hình thức tựa tiếng Anh, các câu lệnh COBOL xếp vào các câu và nhóm lại thành đoạn (paragraph) Hình thức tiếng Anh giúp COBOL dễ viết và đọc làm cho chương trình nguồn dài COBOL tốt việc xử lý các tập tin lớn và thực phép tính thương mại tương đối đơn giản C, phát triển tác giả Dennis Ritchie phòng thí nghiệm Bell vào năm 1972 Ban đầu, C thiết kế là ngôn ngữ để viết các phần mềm hệ thống, ngày nay, nó xem là ngôn ngữ công dụng chung C là ngôn ngữ lập trình mạnh mẽ đòi hỏi kỹ lập trình chuyên nghiệp có thể sử dụng hiệu Nhu cầu dùng C để phát triển nhiều loại phần mềm kể các ứng thương mại gia tăng Các chương trình C thường dùng với hệ điều hành Unix (phần lớn hệ điều hành Unix viết C) FORTRAN, viết tắt FORmula TRANslator phát triển nhóm lập trình viên công ty IBM lãnh đạo John Backus Công bố vào năm 1957, FORTRAN thiết kế là ngôn ngữ lập trình dành cho các nhà khoa học, kỹ sư và toán học FORTRAN xem là ngôn ngữ lập trình cấp (3) cao đầu tiên và chú ý khả nó cho phép dễ dàng diễn đạt và tính toán các phương trình toán học PASCAL, ngôn ngữ sử dụng để giảng dạy giáo trình này, phát triển vào năm 1968 Niklaus Wirth, nhà khoa học máy tính Zurich, Thụy Sĩ Pascal phát triển để giảng dạy lập trình Tên Pascal không phải là từ viết tắt, đó là tên nhà toán học, Blaise Pascal (1623 - 1662) người đầu tiên tạo máy tính Pascal, dùng máy tính cá nhân và máy tính lớn là ngôn ngữ lập trình đầu tiên phát triển đó khuyến khích phương pháp lập trình cấu trúc Các loại ngôn ngữ lập trình khác ALGOL (ALGOrithmetic Language) Ngôn ngữ lập trình cấu trúc dùng cho các ứng dụng khoa học và toán học APL(A Programming Language) Một ngôn ngữ mạnh mẽ, dễ dùng, tốt việc xử lý liệu lưu dạng bảng (ma trận) FORTH, tương tự C, tạo các mã chương trình nhanh và hiệu Ban đầu phát triển để điều khiển kính viễn vọng không gian LISP, LISt Processing, ngôn ngữ trí tuệ nhân tạo thông dụng LOGO, chủ yếu biết đến là công cụ để dạy khả giải vấn đề MODULA-3, tương tự PASCAL Dùng chủ yếu để phát triển các phần mềm hệ thống PILOT, Programmed Inquiry Learning Or Teaching, dùng các nhà giáo dục để viết các chương trình hướng dẫn CAD PL/I, Programming Language/ One Ngôn ngữ thương mại và khoa học phối hợp nhiều chức FORTRAN và COBOL PROLOG, PROgramming LOgic Dùng trí tuệ nhân tạo RPG, Report Program Generator Dùng các mẫu đặc biệt để giúp người dùng xác định liệu vào, liệu và các yêu cầu tính toán chương trình ADA, lấy tên Augusta Ada Bryon, người xem là đã viết chương trình đầu tiên, thiết kế để phục vụ cho việc viết, bảo trì các chương trình lớn khoảng thời gian dài 1.3 Trình thông dịch và biên dịch Mọi chương trình viết các ngôn ngữ không phải là ngôn ngữ máy cuối cùng phải chuyển đổi sang ngôn ngữ máy trước thi hành Chương trình ngôn ngữ cấp cao dịch sang ngôn ngữ máy hai cách : trình biên dịch (compiler) trình thông dịch (interpreter) (4) Trình biên dịch : Sẽ chuyển đổi toàn chương trình sang mã máy, chứa kết vào dĩa để có thể thi hành sau Chương trình ngôn ngữ cấp cao chuyển đổi gọi là chương trình nguồn (source program) và chương trình ngôn ngữ máy tạo gọi là chương trình đối tượng (object program) mã đối tượng (object code) Khi người dùng muốn chạy chương trình, chương trình đối tượng nạp lên nhớ chính CPU và các thị chương trình thi hành Khi hướng dẫn các thị chương trình, CPU truy xuất liệu và tạo các kết Trình biên dịch kiểm tra cú pháp chương trình, thực các phép kiểm tra logic và đảm bảo các liệu sử dụng các phép so sánh, tính toán đã định nghĩa cách hợp lý nơi nào đó chương trình Một chức quan trọng trình biên dịch là nó tạo danh sách lỗi tất mệnh đề chương trình vi phạm cú pháp ngôn ngữ Danh sách này giúp lập trình viên dễ dàng sửa đổi chương trình Do ngôn ngữ máy phụ thuộc vào vi xử lý nên các máy tính khác cần có các trình biên dịch khác cùng ngôn ngữ cấp cao Ví dụ, máy mainframe, máy mini và máy tính cá nhân cần có các trình biên dịch khác để biên dịch cùng chương trình nguồn sang mã máy loại máy này Trình thông dịch : Thay vì chuyển đổi toàn chương trình nguồn trình biên dịch, trình thông dịch chuyển đổi mệnh đề chương trình và thực đoạn mã kết ngay, sau đó nó tiếp tục chuyển đổi mệnh đề thứ thi hành đoạn mã kết thứ và Khi sử dụng trình thông dịch, lần chạy chương trình là lần chương trình nguồn thông dịch sang ngôn ngữ máy Không có chương trình đối tượng nào tạo Các trình thông dịch thường dùng trên các máy tính cá nhân không có đủ nhớ sức mạnh tính toán cần thiết để dùng trình biên dịch Lợi điểm trình thông dịch là lập trình viên có thể chạy chương trình còn lỗi cú pháp Chỉ đến lúc thông dịch đến câu lệnh có lỗi cú pháp, quá trình thi hành chương trình bị ngừng lại và trình thông dịch thông báo lỗi Ðiểm bất lợi là các chương trình thông dịch chạy không nhanh các chương trình biên dịch vì quá trình chuyển đổi sang ngôn ngữ máy thực cùng với quá trình thi hành chương trình Vì lý này, ngày nay, đa số các ngôn ngữ cấp cao dùng trình biên dịch 1.4 Lập trình cấu trúc Lập trình cấu trúc là phương pháp lập trình có các đặc trưng sau : tính đơn thể, cấu trúc điều khiển và tính vào/ra đơn Tuân thủ theo nguyên tắc lập trình có cấu trúc giúp các chương trình dễ viết, dễ đọc, dễ hiểu, dễ kiểm lỗi và dễ hiệu chỉnh Tính đơn thể (modules) : Với lập trình cấu trúc, các vấn đề lập trình phân rã (chia nhỏ) thành phần nhỏ gọi là các đơn thể Mỗi đơn thể, gọi là chương trình các ngôn ngữ lập trình, thực nhiệm vụ định trước chương trình Ðiểm lợi chính kỹ thuật này là nó đơn giản hóa việc phát triển (5) chương trình vì đơn thể chương trình có thể phát triển cách độc lập Khi các đơn thể lắp ghép lại, chúng tạo thành chương trình hoàn chỉnh tạo kết mong muốn Sơ đồ cấu trúc (structure chart) hay còn gọi là sơ đồ phân cấp (hierarchy chart) thường dùng để phân rã và biểu diễn cho các đơn thể chương trình Khi quá trình phân rã chương trình hoàn tất, toàn cấu trúc chương trình biểu diễn sơ đồ phân cấp Sau đây là ví dụ : Cấu trúc điều khiển (control structure) : Trong lập trình cấu trúc, người ta sử dụng cấu trúc điều khiển để tạo nên logic chương trình Mọi vấn đề logic có thể giải cách phối hợp cấu trúc này cấu trúc này là : cấu trúc (sequence), cấu trúc chọn (selection) và cấu trúc lặp (iteration) Cấu trúc : cấu trúc này, việc các quá trình thực tuần tự, từ quá trình này đến quá trình theo sau nó Cấu trúc chọn : hay còn gọi là cấu trúc … thì …ngược lại (if….then…else) cho phép các lập trình viên diễn đạt các logic điều kiện chương trình Ý nghĩa cấu trúc này là điều kiện là đúng thì thực quá trình ứng với điều kiện đúng, ngược lại, thực quá trình ứng với điều kiện sai Một dạng khác cấu trúc chọn là cấu trúc case Cấu trúc case dùng điều kiện kiểm tra có thể dẫn đến hay nhiều quá trình xử lý khác Trong chương trình, menu là ví dụ cấu trúc case vì nó cung cấp nhiều chọn lựa xử lý khác Cấu trúc lặp : (iteration structure looping structure) : cho phép thực nhiều lần quá trình dựa trên điều kiện cho trước Có dạng cấu trúc lặp là cấu trúc lặp for và while Cấu trúc lặp for cho phép lặp lại quá trình xử lý số lần xác định trước Còn cấu trúc lặp while thì lặp lại quá trình xử lý lúc điều kiện kiểm tra không còn đúng Chi tiết các cấu trúc này giới thiệu chi tiết các bài học liên quan đến ngôn ngữ PASCAL Vào/ra đơn( single entry/exit) : Đây là khái niệm quan trọng lập trình cấu trúc Vào/ đơn nghĩa là có điểm vào và điểm cấu trúc cấu trúc trên Ðiểm vào là điểm bắt đầu cấu trúc điều khiển và điểm là điểm kết thúc cấu trúc điều khiển Tính chất này cải thiện đáng kể logic chương trình, vì, đọc chương trình, lập trình viên có thể đảm bảo cho dù có chuyện gì xảy cấu trúc thì cấu trúc điều khiển điểm Trước có lập trình cấu trúc, nhiều lập trình viên hay có thói quen chuyển điều khiển đến phần khác chương trình màkhông tuân theo luật vào/ra đơn Ðiều này dẫn đến thiết kế chương trình tồi, khó khăn để đọc và kiểm tra lỗi hiệu chỉnh Chương trình viết theo lối này giống mớ dây rối !! (6) 1.5 Lập trình hướng đối tượng Lập trình hướng đối tượng (Object Oriented Programming – OOP) là tiếp cận cho việc phát triển phần mềm cho phép lập trình viên tạo các đối tượng (object), phương pháp kết hợp liệu và các câu lệnh chương trình Theo kiểu lập trình truyền thống, người ta thường lưu trữ liệu - chẳng hạn các tập tin - độc lập với chương trình thao tác trên liệu đó Do đó, chương trình phải tự định nghĩa cách thức sử dụng liệu cho chính nó Ðiều này thường dẫn đến trùng lắp mã lệnh, nữa, lần liệu thay đổi thì mã chương trình phải thay đổi theo Với lập trình hướng đối tượng, các câu lệnh chương trình liệu kết hợp các đối tượng mà sau đó có thể dùng dùng lại nhiều lần nào ta cần Các lệnh đặc biệt gọi là phương thức (method) định nghĩa cách thức phản ứng đối tượng đối tượng đó dùng chương trình Khi dùng lập trình hướng đối tượng, các lập trình viên định nghĩa các lớp đối tượng (class) Mỗi lớp có phương thức đặc trưng cho lớp đó Ngoài ra, các lớp đối tượng còn có khả truyền phương thức nó cho lớp thấp gọi là thừa kế (inheritance) Một dẫn xuất (instance) đối tượng chứa tất phương thức từ các lớp cao cộng với các phương thức đặc trưng nó Khi đối tượng nhận thị để thực điều gì, người ta thị đó là thông điệp (message) Không giống lập trình truyền thống, thông điệp không cần phải rõ cho đối tượng biết phải thực nào mà cần bảo đối tượng phải cung cấp kết gì Còn thực nào định nghĩa các phương thức đối tượng đó thừa kế từ các cấp cao Liên quan đến lập trình hướng đối tượng là các phần mềm hướng đối tượng (object-oriented software) và hệ điều hành hướng đối tượng (object-oriented operating system) Phần mềm hướng đối tượng là phần mềm sử dụng phương pháp lập trình hướng đối tượng Còn hệ điều hành hướng đối tượng là hệ điều hành thiết kế đặc biệt để chạy các ứng dụng hướng đối tượng II CÁC BƯỚC XÂY DỰNG CHƯƠNG TRÌNH Việc sử dụng máy tính điện tử (MTÐT) để giải vấn đề nào đó thường quan niệm cách không chuẩn xác, đơn giản đó là việc lập trình túy Thực ra, đó là quá trình phức tạp bao gồm nhiều giai đoạn phát triển mà lập trình là các giai đoạn đó (thậm chí chưa đã là phần việc quan trọng nhất) Các bước quan trọng toàn quá trình liệt kê đây: Bước Xác định vấn đề - bài toán Bước đầu tiên bước phân tích hệ thống là nhằm phát biểu chính xác vấn đề - bài toán, làm rõ yêu cầu mà người sử dụng đòi hỏi Sau nghiên cứu vấn đề đặt ra, người phân tích viên thiết lập mối phụ thuộc các kiện và kết phải tìm Trên sở có mô hình vấn đề - bài toán, người phân tích viên đánh (7) giá, nhận định tính khả thi vấn đề - bài toán đặt có đáng phải giải không? Bước Lựa chọn phương pháp giải Có thể có nhiều cách khác để giải vấn đề - bài toán đã thiết lập bước Các phương pháp có thể khác thời gian thực chi phí lưu trữ liệu, độ chính xác Nói chung không có phương pháp tối ưu phương diện Tùy theo nhu cầu cụ thể mà lựa chọn phương pháp thích hợp Việc lựa chọn trên cần vào khả xử lý tự động mà ta sử dụng Bước Xây dựng thuật toán thuật giải Xây dựng mô hình chặt chẽ, chính xác và chi tiết hóa phương pháp đã lựa chọn Xác định rõ ràng liệu vào, cho các bước thực và trật tự thực các bước đó Nên áp dụng phương pháp thiết kế có cấu trúc, từ thiết kế tổng thể tiến hành làm mịn dần bước Bước Cài đặt chương trình Mô tả thuật giải chương trình Dựa vào thuật giải đã xây dựng, quy tắc ngôn ngữ lập trình để soạn thảo chương trình thể giải thuật thiết lập bước Bước Hiệu chỉnh chương trình Ở bước 4, nói chung chúng ta không tránh khỏi sai sót Ở bước này chúng ta cho chương trình chạy thử để phát và điều chỉnh các sai sót tìm thấy Có hai loại lỗi: Lỗi cú pháp là lỗi không tuân thủ đúng các quy tắc viết chương trình trên ngôn ngữ lập trình cụ thể Lỗi ngữ nghĩa là lỗi làm sai lạc ý nghĩa dẫn đến bế tắc chương trình Lỗi cú pháp thường dễ phát và hiệu chỉnh lỗi ngữ nghĩa Cần phải nói việc hiệu chỉnh chương trình khá phức tạp, nhiều thời gian và công sức Việc xây dựng tốt, phù hợp, đầy đủ các liệu để kiểm chứng chương trình là quan trọng, giúp phát các lỗi ngữ nghĩa chương trình có thể có vấn đề gì đó bị bỏ sót Bước Thực chương trình Cho MTÐT thực chương trình Tiến hành phân tích kết thu Việc phân tích kết nhằm khẳng định kết đó có phù hợp hay không Nếu không, cần kiểm tra lại toàn các bước lần Nói chung, dù thận trọng đến mức nào thì sau bước thực nêu trên không khẳng định kết thực bước là đúng đắn tuyệt đối Hơn nữa, bước 5, ta hiệu chỉnh tất các lỗi đã phát Còn có thể có sai sót khác chương trình với liệu nào khác phức tạp mà ta chưa có hội để phát trước đó Do đó, ta không thể khẳng định rằng, chương trình đúng tuyệt đối, không còn sai sót Như vậy, việc giải vấn đề cụ thể thực qua hai giai đoạn Giai đoạn (8) đầu là giai đoạn quan niệm, gồm các bước phân tích, lựa chọn mô hình, xây dựng thuật giải, cài đặt chương trình Giai đoạn sau là khai thác và bảo trì chương trình Trong quá trình sử dụng, nói chung thường có nhu cầu cải tiến, mở rộng chương trình các yếu tố bài toán ban đầu có thể thay đổi III CÂU HỎI ÔN TẬP Chương trình máy tính là gì? Thế nào là ngôn ngữ lập trình? Theo anh chị, ngôn ngữ lập trình giống và khác nào so với ngôn ngữ tự nhiên tiếng Việt ? Ngôn ngữ lập trình có thể phân chia làm loại? Ưu điểm chương trình mã máy là gì? Liệu có nên viết toàn phần mềm mã máy không? So sánh trình thông dịch và trình biên dịch? Ưu điểm và khuyết điểm trình thông dịch và biên dịch? Lập trình cấu trúc là gì? Tại phải lập trình cấu trúc? cấu trúc điều khiển là gì? Cho ví dụ minh họa? Các bước xây dựng chương trình? Tại phải có các bước này? Liệu có thể viết chương trình mà không cần các bước xác định bài toán, xây dựng thuật giải hay không? §2 : Mở đầu ngôn ngữ Pascal YÊU CẦU CỦA BÀI GIẢNG Nắm : Các khái niệm từ khóa, tên , tên chuẩn và cách đặt tên ngôn ngữ Pascal Cấu trúc chương trình Pascal Cách sử dụng phần mềm Turbo Pascal để soạn thảo và thực chương trình Pascal 5.1 GIỚI THIỆU NGÔN NGỮ PASCAL PASCAL là ngôn ngữ lập trình cấp cao giáo sư Niklaus Wirth trường đại học Kỹ thuật Zurich (Thụy sĩ) thiết kế và công bố vào năm 1971 Ông đặt tên cho ngôn ngữ mình là Pascal để tưởng nhớ nhà toán học tiếng người Pháp kỷ 17: Blaise Pascal, người đã sáng chế máy tính khí đầu tiên nhân loại Qua thời gian sử dụng, Pascal ngày càng đông đảo người dùng đánh gía cao, và trở thành các ngôn ngữ thảo chương phổ biến Thành công ngôn ngữ Pascal là chỗ: nó là ngôn ngữ đầu tiên đưa và thể khái niệm lập trình có cấu trúc Ý tưởng chương trình có cấu trúc xuất phát từ suy nghĩ cho có thể chia bài toán lớn, phức tạp thành nhiều bài toán nhỏ, đơn giản Nếu bài toán nhỏ giải chương trình con, thì liên kết các chương trình này lại tạo nên chương trình lớn giải bài toán ban đầ? Bằng cách chia chương trình thành các chương trình vậy, người thảo chương có thể lập trình để giải riêng lẻ phần một, khối một, có thể tổ chức để nhiều (9) người cùng tham gia, người phụ trách vài khối Ðặc biệt phải thay đổi hay sửa chữa khối thì điều đó ít ảnh hưởng đến các khối khác Tính cấu trúc ngôn ngữ Pascal còn thể việc tổ chức các câu lệnh và tổ chức liệu Từ các lệnh đã có, người thảo chương có thể nhóm chúng lại với và đặt hai từ khóa Begin và End tạo thành câu lệnh phức tạp gọi là câu lệnh ghép Ðến lượt mình, hai hay nhiều lệnh ghép lại có thể nhóm lại để tạo thành câu lệnh ghép phức tạp nữa,.v.v Tương tự thế, ngôn ngữ Pascal cho phép xây dựng các kiểu liệu phức tạp từ các kiểu liệu đã có Pascal là ngôn ngữ không chặt chẽ mặt cú pháp mà còn chặt chẽ mặt liệu Mỗi biến, tham gia chương trình luôn có kiểu liệu xác định và nhận gía trị có cùng kiểu liệu với nó Ðiều này buộc người lập trình phải nắm cú pháp và luôn chú ý đến tính tương thích các biểu thức mặt kiểu liệu Chính vì thế, thảo chương ngôn ngữ Pascal là hội tốt không rèn luyện tư mà còn rèn luyện tính cẩn thận và chính xác Ngày nay, Ngôn ngữ Pascal dùng để viết các chương trình ứng dụng nhiều lĩnh vực Với văn phạm sáng sủa, dễ hiểu, với khả đủ mạnh, Pascal xem là ngôn ngữ thích hợp để giảng dạy các trường phổ thông và đại học 5.2 CÁC PHẦN TỬ CƠ BẢN CỦA NGÔN NGỮ PASCAL 5.2.1.Tập ký tự Mỗi ngôn ngữ xây dựng từ tập ký tự nào đó Nhiều ký tự nhóm lại với tạo nên các từ Nhiều từ liên kết với theo qui tắc ngữ pháp định (gọi là văn phạm) thì tạo nên các mệnh đề Trong các ngôn ngữ thảo chương, mệnh đề?còn gọi là câu lệnh Một tập hợp các câu lệnh xếp theo trật tự định nhằm thị cho máy các thao tác phải thực tạo thành chương trình Các chương trình soạn thảo người thảo chương và lưu trữ trên đĩa dạng các tập tin Ngôn ngữ Pascal xây dựng trên ký tự bản, gồm: các chữ cái la tinh: A, B, C, ,Z, a, b, c, , z các chữ số :0, 1, 2, 3, 4, 5, 6, 7, 8, các ký hiệu đặc biệt: +, -, *, /, =, <, {, }, [, ], %, $, &, #, ký tự gạch nối ‘_’ và ký tự trắng ‘ ‘ ( space) Các chữ Ả rập:  ,  ,  , không thuộc ký tự Pascal 5.2.2 Từ khóa ( key word ): Có số từ Pascal dành riêng cho việc xây dựng các câu lệnh, các khai báo, các phép tính, gọi là từ khóa Việc sử dụng các từ khóa đòi hỏi phải tuân thủ đúng quy tắc đề ra, và đặc biệt là người lập trình không đặt tên (tên biến, tên hằng, tên hàm, tên thủ tục, ) trùng với các từ khóa Dưới đây là danh sách các từ khóa Pascal : (10) absolute, and, array, begin, case, const, div, do, downto, else, end, file, for, forward, function, goto, if, implementation, in, inline, interface, interrupt, label, mod, nil, not, of, or, packed, procedure, program, record, repeat, set, shl, shr, string, then, to, type, unit, until, uses, var, while, with, xor Các từ khóa có thể viết dạng chữ hoa hay chữ thường hay xen kẽ chữ hoa với chữ thường Ví dụ viết begin hay Begin hay BEGIN là 5.2.3 Tên (identifier): Các biến, các hằng, các hàm, các thủ tục, sử dụng chương trình cần phải đặt tên, còn gọi là định danh hay danh hiệu Các tên này người thảo chương tự đặt và phải đảm bảo đúng quy tắc: tên phải bắt đầu chữ cái, kế đó có thể là chữ cái, chữ số, hay dấu gạch nối ‘_’ Tên không đặt trùng với từ khóa Chiều dài tên tối đa là 127 ký tự Thông thường tên nên đặt ngắn gọn và có tính gợi nhớ Dưới đây là ví dụ các tên đặt đúng: Delta, X1, X2, i, j , Chuc_vu, Luong, So_luong, Don_gia Còn các tên: 3ABC, In, Chu vi, Ma-so là sai vì : 3ABC: bắt đầu số Chu vi: có chứa ký tự trắng Ma-so : ký tự ‘-’ là dấu trừ không phải gạch nối In : trùng với từ khóa In Cũng giống từ khóa, Tên không phân biệt viết hoa hay viết thường Ví dụ viết X1 hay x1 là tên thôi Trong Pascal có số tên đã đặt sẵn rồi, gọi là tên chuẩn, chẳng hạn : Abs, Arctan, Boolean, Byte, Char, Cos, Copy, Delete, Eof, False, Longint, Ord, Integer, Real, Readln, Writeln, True, Text, Mặc dù người thảo chương có thể đặt tên trùng với các tên chuẩn, song, để đỡ nhầm lẫn, chúng ta nên tránh điều này 5.3 CẤU TRÚC CHUNG CỦA CHƯƠNG TRÌNH PASCAL 5.3.1 Ví dụ mở đầu : Để có cái nhìn tổng quan trước vào các vấn đề chi tiết ngôn ngữ Pascal, xin hãy cùng xem chương trình sau: 5.3.1.1 Bài toán và chương trình : Viết chương trình để nhập vào độ dài hai cạnh hình chữ nhật, tính và in lên màn hình diện tích và chu vi hình chữ nhật đó (11) Nếu gọi hai cạnh hình chữ nhật là a và b, gọi diện tích và chu vi là S và P thì công thức tính S và P là: S = a.b P = 2(a+b) Chương trình cụ thể sau : PROGRAM VIDU51; { Tinh dien tich va chu vi hinh chu nhat } Uses CRT; Var a, b, S, P : Real ; Begin Clrscr; Write( ‘Nhap chieu dai : ‘); Readln(a); Write( ‘Nhap chieu rong : ‘); Readln(b); S:=a*b; P:=2* (a+b); Writeln (‘ Dien tich = ‘, S:8:2); Writeln (‘ Chu vi = ‘, P:8:2); Readln; End Chay <VD51.EXE> Chép chương trình nguồn VD52.PAS 5.3.1.2 Giải thích các dòng chương trình : (12) { Tinh dien tich va chu vi hinh chu nhat } Đây là lời chú giải, nêu lên mục đích chương trình Uses CRT ; Khai báo sử dụng thư viện CRT Turbo Pascal Var a, b, S, P : Real ; Khai báo biến a, b, S, P có kiểu liệu là số thực (Real) Begin Lệnh bắt đầu chương trình Clrscr ; Lệnh xóa màn hình Write( ‘Nhap chieu dai: ‘); Lệnh in lên màn hình câu ‘ Nhap chieu dai: ‘ nhằm nhắc người dùng nhập vào số đo chiều dài Readln(a) ; Lệnh nhập liệu cho biến a Write( ‘Nhap chieu rong : ‘); Lệnh in lên màn hình câu ‘Nhap chieu rong :’ nhằm nhắc người dùng nhập vào số đo chiều rộng Readln(b); Lệnh nhập liệu cho biến b S := a* b; Lệnh tính diện tích S hình chữ nhật P := 2*(a+b); Tương tự, lệnh tính chu vi P hình chữ nhật Writeln(‘Dien tich = ‘, S:8:2); (13) Lệnh này in lên màn hình câu ‘ Dien tich= ‘ , kế đó in gía trị biến S Chỉ thị S:8:2 ấn định dành cột trên màn hình để in gía trị S, đó có cột để in phần thập phân Writeln(‘ Chu vi = ‘, P:8:2); Lệnh này in lên màn hình câu ‘Chu vi = ‘, kế đó in gía trị chu vi P có thảy chữ số, đó có số phần lẻ Readln; Lệnh dừng màn hình để xem kết qủa chạy chương trình End Dấu hiệu kết thúc chương trình 5.3.1.3 Chạy minh họa chương trình : Để chạy chương trình mẫu nói trên, hãy nhắp vào mục Chay<VD51.EXE> cuối chương trình đó Nhưng trước hết xin xem phần hướng dẫn sau đây: Khi chương trình bắt đầu chạy, trên màn hình lên lời nhắc : Nhap chieu dai : Bạn cần nhập số đo chiều dài từ bàn phím, chẳng hạn gõ số và Enter : Nhap chieu dai :  Màn hình tiếp lời nhắc : Nhap chieu rong : Bạn nhập số đo chiều rộng, chẳng hạn gõ số và Enter : Nhap chieu rong :  Chương trình tính toán và in kết qủa lên màn hình sau : Dien tich = 48.00 Chu vi = 28.00 Để kết thúc, hãy gõ phím Enter 5.3.2 Cấu trúc chung chương trình Pascal : Chương trình là dãy các câu lệnh thị cho máy các công việc phải thực Một chương trình Pasccal đầy đủ gồm ba phần chính : Phần tiêu đề (14) Phần khai báo Phần thân chương chình Program Têntựđặt ; { Phần tiêu đề} { Phần khai báo  } Uses {khai báo sử dụng thư viện chuẩn} Label {khai báo nhãn} Const {khai báo hằng} Type {khai báo kiểu liệu} Var { khai báo biến} Function { khai báo các chương trình con} Procedure {hàm và thủ tục } { Phần thân chương trình  } Begin { Các lệnh } End Hình 5.1: Cấu trúc chương trình Pascal 5.3.2.1 Phần tiêu đề chương trình : Phần này khóa Program, sau đó ít là khoảng trắng và tên người dùng tự đặt, cuối cùng kết thúc dấu chấm phẩy ‘;’ Ví dụ : Program Btap1; : Program Giai_pt_bac2; Phần tiêu đề chiếm dòng, còn gọi là phần đầu chương trình, nó có thể không có 5.3.2.2 Phần khai báo : (15) Phần khai báo có nhiệm vụ giới thiệu và mô tả các đối tượng, các đại lượng tham gia chương trình, giống ta giới thiệu các thành viên họp Nó gồm khai báo sử dụng thư viện chuẩn, khai báo nhãn, khai báo hằng, khai báo kiểu liệu mới, khai báo biến, và khai báo các chương trình Tùy theo yêu cầu cụ thể mà khai báo này có thể có không Khai báo nhãn (Label) dùng chương trình có sử dụng lệnh nhảy vô điều kiện GOTO Nhược điểm lệnh GOTO là làm tính cấu trúc chương trình, có thể thay nó các câu lệnh có cấu trúc Pascal Vì thế, để rèn luyện kỹ lập trình có cấu trúc, chúng ta không dùng lệnh GOTO giáo trình này Các thủ tục và hàm dùng có nhu cầu thiết kế các chương trình lớn, phức tạp Đối với các bài toán nhỏ, đơn giản, việc sử dụng chương trình là chưa cần thiết Chi tiết phần này trình bày kỹ bài 12 Sau đây ta điểm qua vài nét các khai báo thông dụng a) Khai báo và khai báo biến : Biến là đại lượng có gía trị thay đổi được, còn Hằng là đại lượng có gía trị không đổi, chúng dùng chương trình để lưu trữ các liệu, tham gia vào các biểu thức tính toán và các quá trình xử lý máy Việc khai báo có tác dụng xác định tên và kiểu liệu biến hay Biến và Hằng là thành phần khó có thể thiếu chương trình Để khai báo biến ta dùng từ khóa Var, để khai báo ta dùng từ khóa Const, ví dụ: Const N=10 ; Var x, y : Real ; i, k : Integer ; b) Khai báo (định nghĩa) kiểu liệu mới: Ngoài các kiểu liệu mà thân ngôn ngữ đã có sẵn kiểu thực, kiểu nguyên, kiểu ký tự, kiểu lôgic,.v.v người dùng có thể tự xây dựng các kiểu liệu phục vụ cho chương trình mình, phải mô tả sau từ khóa TYPE Khi đã định nghĩa kiểu liệu mới, ta có thể khai báo các biến thuộc kiểu liệu này Ví dụ, ta định nghĩa kiểu liệu có tên là Mang : Type Mang = Array[1 10] of Real; (16) Bây có thể khai báo hai biến A và B có kiểu liệu là kiểu Mang : Var A, B : Mang ; c) Khai báo sử dụng thư viện chuẩn: Turbo Pascal có sẵn số hàm và thủ tục chuẩn, chúng phân thành nhóm theo chức mang các tên đặc trưng, gọi là các thư viện hay đơn vị chương trình ( Unit ), : Crt, Graph, Dos, Printer, v.v Muốn sử dụng các hàm hay thủ tục thư viện nào, ta phải khai báo có sử dụng thư viện đó, lời khai báo phải để sau phần tiêu đề chương trình theo cú pháp : Uses danhsáchthư viện ; Ví dụ: thủ tục Clrscr nằm thư viện CRT, nên chương trình mà có dùng lệnh Clrscr, thì phải khai báo : Uses CRT ; Muốn sử dụng hai thư viện CRT và GRAPH, ta khai báo : Uses CRT, GRAPH ; 5.3.2.3 Phần thân chương trình : Đây là phần chủ yếu chương trình, bắt buộc phải có Thân chương trình khóa BEGIN và kết thúc END (có dấu chấm cuối) Giữa khối BEGIN và END là các lệnh Mỗi lệnh phải kết thúc dấu chấm phẩy ‘;’ Một lệnh, dài, thì có thể viết trên hai hay nhiều dòng, ví dụ : Writeln(‘ Phuong trinh co hai nghiem la X1= ‘, X1:8:2,‘ va X2= ‘, X2:8:2) ; Ngược lại, dòng có thể viết nhiều lệnh miễn là có dấu ‘;’ để phân cách các lệnh đó, chẳng hạn : Write(‘ Nhap A, B, C: ‘ ) ; Readln(A,B,C) ; Thông thường dòng nên viết lệnh để dễ đọc, dễ kiểm tra lỗi 5.3.3 Ví dụ : Để kết thúc phần này, xin giới thiệu chương trình cho phép nhập vào họ tên, mã số, các điểm Toán, Lý sinh viên, tính điểm trung bình theo công thức : (17) in Họ tên, mã số, các điểm Toán, Lý và điểm trung bình sinh viên đó lên màn hình PROGRAM VIDU52; Uses CRT; Var Ho_ten, Maso : String[20]; Toan, Ly, Dtb : Real; Begin Write(‘ Nhap Ho va ten : ‘); Readln(Ho_ten); Write(‘ Nhap ma so : ‘); Readln(Maso); Write(‘ Nhap diem Toan : ‘); Readln(Toan); Write(‘ Nhap diem Ly : ‘); Readln(Ly); Dtb:= (Toan+Ly) / 2; { In lên màn hình các liệu sinh viên } TextMode(C40); { đặt mode C40 cho màn hình } TextBackGround(Green); { đặt màu là Green } TextColor(Red); { đặt màu chữ là Red} Clrscr ; Writeln(‘ KET QUA THI CUA SINH VIEN:’); Writeln(‘Ho va ten : ‘, Ho_ten); Writeln(‘Ma so : ‘, Maso); Writeln(‘Diem Toan : ‘, Toan:3:1); Writeln(‘Diem Ly : ‘, Ly:3:1); Writeln(‘Diem Tbinh : ‘, Dtb:3:1); Readln; (18) TextMode(C80); { đặt trả lại mode C80 cho màn hình} END Chạy<VD52.EXE> Chép chương trình nguồn VD52.PAS Trong chương trình này có sử dụng bốn thủ tục thuộc thư viện CRT, đó là : Clrscr : xóa màn hình TextMode(C40) và TextMode(C80) : chuyển màn hình sang chế độ bề ngang 40 cột (chữ to) 80 cột (chữ bình thường) TextBackGround(tênmàu) : đặt lại màu màn hình TextColor(tênmàu) : đặt lại màu chữ trên màn hình Tên màu có thể là số từ đến 15 có thể viết trực tiếp tiếng Anh : White, Black, Green, Red, Blue, Bạn có thể chạy minh họa chương trình này cách nhắp chọn vào mục Chay<VD52.EXE> cuối chương trình Cách nhập liệu tương tự ví dụ trước Chẳng hạn ta nhập họ tên là Nguyen Van An, mã số là 1990064, điểm toán là 6, điểm lý là đây : Nhap Ho va ten : Nguyen Van An  Nhap ma so : 1990064  Nhap diem Toan :  Nhap diem Ly :  Chương trình tính điểm trung bình và in kết qủa sau: KET QUA THI CUA SINH VIEN: Ho va ten : Nguyen Van An Ma so : 1990064 Diem Toan : 6.0 Diem Ly : 7.0 (19) Diem Tbinh : 6.5 Hãy Enter để kết thúc và trở lại màn hình ban đầu Để soạn và chạy chương trình trên cần phải biết sử dụng phần mềm Turbo Pascal ( viết tắt là TP ) 5.4 SỬ DỤNG PHẦN MỀM TURBO PASCAL 5.4.1 Giới thiệu Turbo Pascal: Turbo Pascal là phần mềm có nhiệm vụ giúp người thảo chương soạn thảo và thực các chương trình viết ngôn ngữ Pascal Các chức chính Turbo Pascal là : Cung cấp hệ soạn thảo văn cho phép người thảo chương soạn và sửa chương trình dễ dàng, tiện lợi Giúp người thảo chương tìm các lỗi văn phạm chương trình Dịch (compiler) chương trình viết bằøng ngôn ngữ Pascal thành chương trình viết dạng mã máy Thực hay chạy ( Run ) chương trình viết ngôn ngữ Pascal Cung cấp các thư viện có sẵn nhiều hàm (function) và thủ tục (procedure) chuẩn mang lại cho người thảo chương nhiều công cụ hữu ích, làm giảm bớt khối lượng phải lập trình Là sản phẩm hãng Borland tiếng, Turbo Pascal (viết tắt là TP) không ngừng cải tiến, đến đã đời version 7.0 Tuy nhiên, mức độ thảo chương bản, người ta thích dùng phiên 5.5 6.0 vì nó đơn giản mà đủ dùng, tốc độ nhanh hơn, thích hợp với các máy có cấu hình chưa mạnh 5.4.2 Khởi động Turbo Pascal: Trong phần này trình bày cách sử dụng Turbo Pascal 6.0 Người đọc có thể tự mình suy cách sử dụng Turbo Pascal 5.5 hay 7.0, vì vềø chúng giống với phiên 6.0 5.4.2.1 Các tập tin chính Turbo Pascal: Để chạy Turbo Pascal 6.0, cần hai tập tin sau là đủ : TURBO.EXE : tập tin chính TP TURBO.TPL : tập tin chứa các thư viện TP Nếu muốn vẽ đồ họa thì phải có thêm các tập tin: GRAPH.TPU, tập tin chứa thư viện đồ họa *.BGI : các tập tin màn hình đồ họa (20) *.CHR : các tập tin tạo kiểu chữ Trong các tập tin màn hình đồ họa thì thông thường cần tập tin EGAVGA.BGI là đủ, vì ngày phần lớn màn hình có kiểu EGA hay VGA Nếu muốn xem hướng dẫn sử dụng Turbo Pascal thì cần có thêm tập tin TURBO.HLP Thông thường các tập tin này để thư mục riêng có tên là TP, hay TP6 Dưới đây ta giả thiết thư mục chứa Turbo Pascal là TP nằm gốc đĩa cứng C hay đĩa mềm A 5.4.2.2 Khởi động Turbo Pascal: a) Nếu bạn làm việc trên máy cá nhân mạng có hệ điều hành là MSDOS thì sau khởi động máy xong: Trường hợp dễ là máy bạn đã thiết lập sẵn đường dẫn đến thư mục TP chứa Turbo Pascal thì bạn cần gõ lệnh : TURBO  Trên màn hình cửa sổ soạn thảo hình 5.2 Nếu gõ lệnh trên mà cửa sổ Turbo Pascal không ra, máy bạn chưa thiết lập đường dẫn đến thư mục TP, trường hợp này bạn phải di chuyển vào thư mục TP lệnh : CD \TP sau đó gõ tiếp : TURBO  (21) b) Nếu bạn làm việc trên máy cá nhân mạng có hệ điều hành là WINDOWS 95 hơn, thì sau khởi động WINDOWS 95 : Trường hợp có sẵn Shortcut chứa Turbo Pascal trên Desktop : hãy nhắp left mouse hai lần liên tiếp vào biểu tượng Shortcut Turbo Pascal Trường hợp không có sẵn Shortcut chứa Turbo Pascal: hãy chọn lệnh Start, chọn tiếp lệnh Run, gõ vào đường dẫn đầy đủ tập tin TURBO.EXE, chẳng hạn: C:\TP\TURBO.EXE  , khởi động TP từ đĩa C A:\TP\TURBO.EXE  , khởi động TP từ đĩa A 5.4.2.3 Cửa sổ Turbo Pascal và cách chọn lệnh : Trong cửa sổ này, dòng trên cùng là thực đơn ngang, liệt kê chín nhóm lệnh chính TP Muốn chọn lệnh thực đơn này, có thể tiến hành theo hai cách: Cách một: Gõ phím F10 Lúc này, trên thực đơn xuất khung sáng (thường là màu xanh) Muốn chọn lệnh nào thì gõ các phím mũi tên  ,  dời khung sáng đến lệnh đó Enter Một thực đơn lệnh vừa chọn ra, gọi là thực đơn dọc Ví dụ, chọn lệnh File, ta thực đơn sau: Để chọn lệnh thực đơn dọc, hãy gõ các phím mũi tên ,  dời khung sáng đến lệnh đó Enter Khi không muốn chọn lệnh nào thì gõ phím ESC để trở vùng soạn thảo (22) Ngoài cách dùng phím F10 nói trên, có thể chọn lệnh thực đơn ngang cách gõ đồng thời phím Alt với phím chữ cái đầu tiên tên lệnh muốn chọn Ví dụ, muốn chọn lệnh File thì gõ đồng thời hai phím Alt và F (viết tắt là Alt-F), tương tự, muốn chọn lệnh Compile thì gõ Alt-C Cách hai: dùng phím " nóng" : Có số lệnh gán cho phím đặc biệt gọi là phím "nóng", ví dụ lệnh Open: F3, lệnh Save : F2, lệnh Exit : Alt-X Để thực lệnh này, thay vì phải chọn nó từ thực đơn, ta cần gõ phím nóng tương ứng với nó Ví dụ, thay vì chọn lệnh Open thì gõ phím F3, thay vì chọn lệnh Save thì gõ phím F2, Dưới thực đơn ngang là vùng soạn thảo dùng để gõ chương trình vào Đầøu vùng này tên tập tin soạn, và người thảo chương chưa đặt tên thì TP đặt giùm tên mặc nhiên là NONAME00.PAS Dòng cuối cùng tóm tắt số phím " nóng" hay dùng, phím F1 để xem hướng dẫn, phím F2 để lưu tập tin lên đĩa, phím F3 dùng để mở xem tập tin, phím F10 để khởi động thực đơn,.v.v 5.4.2.4 Thoát khỏi Turbo Pascal: Chọn lệnh File thực đơn ngang, chọn tiếp lệnh Exit thực đơn dọc (viết gọn là chọn lệnh File/ Exit) Nếu làm việc TP 5.5 thì chọn lệnh File/ Quit Hoặc gõ cặp phím nóng Alt-X 5.4.3 Các bước thực chương trình Pascal: Để soạn và chạy chương trình Pascal Turbo Pascal, nên tiến hành các bước sau: Bước 1: Khởi động Turbo Pascal Bước 2: Đặt tên cho tập tin soạn : Chọn lệnh File/ Open (nếu làm việc TP 5.5 thì chọn lệnh File/ Load) gõ phím F3, sau đó gõ tên tập tin (không cầøn gõ phần đuôi) vào khung vừa ra, ví dụ : (23) Khi đó tên BTAP1.PAS đầu vùng soạn thảo Đuôi PAS TP tự động gắn thêm vào Tập tin BTAP1.PAS lưu thư mục thời Nếu muốn tập tin BTAP1.PAS lưu lên đĩa A thì nhập tên tập tin ta nên gõ thêm tên ổ đĩa đằng trước, ví dụ : Bước 3: Soạn thảo ( gõ ) chương trình Bạn hãy gõ chương trình mẫu sau vào vùng soạn thảo Turbo Pascal : (24) Bước 4: Dịch và sửa lỗi: Chọn lệnh Compile/ Compile (hoặc gõ cặp phím Alt-F9, hay đơn giản gõ phím F9 được) Máy dịch chương trình sang mã máy, gặp lỗi thì dừng và thông báo lỗi màu đỏ đầu màn hình, đồøng thời trỏ đặt vị trí có lỗi Người thảo chương phải tự mình sửa lỗi, gõ Alt-F9 để dịch và sửa lỗi tiếp hết lỗi Dấu hiệu cho biết việc dịch đã xong là màn hình xuất cửa sổ thông báo có dòng chữ đặc trưng là: Bước 5: Lưu trữ chương trình lên đĩa: chọn lệnh File/ Save gõ phím F2 Bước 6: Chạy thử chương trình: Chọn lệnh Run/ Run gõ phím nóng Ctrl-F9 (viết tắt là ^F9) Mỗi lần chạy thử, ta cần nhập liệu cụ thể và kiểm tra xem kết qủa in lên màn hình có đúng không Cần phải chạy thử số lần ứng với các liệu khác Nếu kết qủa các lần chạy thử đúng thì chương trình đã hoàn thành Ngược lại, có lần chạy thử cho kết qủa sai thì chương trình chưa ổn, cần phải sửa lại thuật toán chương trình Ví dụ : Để chạy thử chương trình mẫu trên, hãy gõ ^F9 và nhập vào chiều dài 10, chiều rộng 7, sau : (25) Nhap chieu dai : 10  Nhap chieu rong :  Chương trình in kết qủa lên màn hình : Dien tich = 70.00 Chu vi = 34.00 Hãy Enter để trở lại màn hình soạn thảo Việc chạy thử với liệu khác, xin dành cho độc giả Bước 7: Nếu chương trình chạy đúng thì gõ phím F2 để lưu nó lên đĩa lần cuối Bây có thể lặp lại từ bước để soạn chương trình 5.4.4 Mở xem chương trình cũ : Muốn xem lại chương trình đã có trên đĩa, hãy chọn lệnh File/ Open gõ phím F3, khung có tiêu là Name, gõ vào *.PAS  (hoặc A:*.PAS  tập tin nằm trên đĩa A), danh sách các tập tin có đuôi PAS khung phía cho ta chọn ( hình 5.4) : Dùng các phím mũi tên  , , , để di chuyển và đặt sáng vào tên muốn chọn Enter Nội dung tập tin này đưa lên màn hình cho chúng ta xem, sửa, chạy thử, v.v Chú ý TP từ 6.0 trở lên, để đưa trỏ từ hộp Name trên xuống hộp Files dưới, dùng phím Tab, từ hộp File lại hộp Name : gõ Shift_Tab 5.4.5 Lưu tập tin sang đĩa khác : Khi cần ghi tập tin soạn từ đĩa cứng sang đĩa A, có thể làm sau: Chọn lệnh File/ Save as (nếu làm việc TP 5.5 thì chọn lệnh File/ Write to ) (26) Trong khung , hãy gõ tên tập tin vào, nhớ gõ thêm tên đĩa A: đằng trước: Name: A:\BTAP.PAS Từ nay, gõ phím F2 chọn lệnh File/ Save, tập tin BTAP1.PAS ghi lên đĩa A 5.4.6 Một vài kỹ thuật soạn thảo : 5.4.6.1 Thao tác trên khối: Ta gọi khối là đoạn văn gồm hay nhiềøu dòng liên tiếp Ký tự đầu tiên khối gọi là đầu khối, ký tự cuối cùng khối gọi là cuối khối Dưới đây là khối gồm hai dòng lệnh: Write(‘ Nhap chieu dai va chieu rong hinh chu nhat: ‘); Readln(a,b); a) Đánh dấu khối: Đưa trỏ đầu khối Một tay đè phím Shift, tay gõ các phím mũi tên  ,, , kéo vùng sáng phủ đến cuối khối Nếu làm việc TP 5.5 thì đánh dấu khối cách: đưa trỏ vềø đầu khối, gõ ^K_B, sau đó đưa trỏ cuối khối, gõ ^K_K (Cách gõ ^K_B: tay đè phím Ctrl tay gõ liên tiếp hai phím K và B) b) Sao chép khối: Đánh dấu khối cần chép Đưa trỏ đến nơi cần chép tới Gõ lệnh ^K_C c) Di chuyển khối: Đánh dấu khối cần di chuyển Đưa trỏ đến nơi cần chuyển khối tới Gõ lệnh ^K_V (27) d) Xóa khối: Đánh dấu khối cần xóa Gõ lệnh ^K_Y e) Che lại khối đã đánh dấu : lệnh ^K_H 5.4.6.2 Các phím lệnh soạn thảo thông dụng: Phím Home : đưa trỏ đầu dòng thời Phím End : đưa trỏ cuối dòng thời Phím Delete : xóa ký tự vị trí trỏ Nếu trỏ đứng cuối dòng trên mà gõ phím Delete thì nối dòng vào cuối dòng trên Phím Back Space ( là phím mũi tên  nằm phía trên phím Enter) : xóa ký tự bên trái trỏ Nếu trỏ đứng đầu dòng mà gõ phím Back Space thì nối dòng vào cuối dòng trên Cặp phím Ctrl_Y : xóa toàn dòng thời và đôn các dòng lên Nhóm phím Ctrl_Q_Y : xóa từ vị trí trỏ đến cuối dòng Các phím  , , , : dời trỏ theo hướng mũi tên Phím Insert : mở tắt chế độ viết chèn Ở chế độ viết chèn, trỏ màn hình có dạng bình thường, tắt chế độ viết chèn, trỏ có kích thước lớn gấp lần bình thường (Trong TP 5.5, chế độ viết chèn hay tắt viết chèn nhận biết việc chữ Insert có hay không đầu cửa sổ soạn thảo) Phím Enter : Trong chế độ viết chèn: gõ Enter có tác dụng đưa trỏ xuống đầu dòng dưới, đó toàn các chữ đứng sau trỏ (nếu có) bị cắt xuống dòng Khi trỏ đứng đầøu dòng mà Enter thì tạo dòng trống vị trí đó Nếu chế độ viết chèn là tắt thì gõ phím Enter, trỏ đầu dòng thời (dòng chứa trỏ), không xuống dòng Chú ý: Trong Turbo Pascal không dùng chữ có dấu tiếng Việt Tuy nhiên các chương trình mẫu giáo trình này viết chữ có dấu là để dễ đọc, dễ hiểu Khi soạn Turbo Pascal xin hãy bỏ dấu (28) 5.5 CÂU HỎI TRẮC NGHIỆM Trong các câu hỏi đây, hãy chọn câu trả lời thích hợp nhất: Câu 1: Tính cấu trúc ngôn ngữ Pascal thể : a) việc tổ chức các dtệu; b) việc tổ chức các câu lệnh; c) việc tổ chức chương trình; d)ở ba mục a), b), c) ; Câu 2: Ðiều gì làm cho Pacal đánh gía cao và trở thành ngôn ngữ thảo chương phổ biến ? a) Nó là ngôn ngữ đầu tiên đưa và thể khái niệm lập trình có cấu trúc.; b) Nó là ngôn ngữ chặt chẽ mặt cú pháp và mặt dtệu; c) Nó là ngôn ngữ có văn phạm sáng sủa, dễ hiểu, có khả đủ mạnh; d)Cả ba điều nêu các mục a), b), c) ; Câu 3: Khẳng định nào đúng: a) VAR , BEGIN, end là các từ khóa Pascal khái niệm lập trình có cấu trúc.; b) Các ký hiệu a , b , g , d thuộc ký tự Pascal; c) Var, begin, Integer, Real là các từ khóa Pascal; d)VAR, Var, vaR, var là các từ khóa khác Pascal ; Câu 4: Tên nào đặt Sai quy định Pascal: a) Giai_Ptrinh_Bac_2; b) Ngaysinh; c) Noi sinh; d)Sv2000 ; Câu 5: Mục nào có các Tên đặt đúng quy định Pascal: a) x1 , X-2 ; b) Xx1 , X2; c) CONST , X_234; d)X[1], x2 ; Câu 6: Chọn câu Sai : chương trình Pascal, có thể không có : a) phần thân chương trình ; b) phần khai báo biến; c) phần đầu chương trình; d)phần khai báo ; Câu 7: Dấu hiệu kết thúc chương trình Pascal là : (29) a) End; b) END; c) end d) End ! ; Câu 8: Trong Pascal, lệnh nào có tác dụng xóa màn hình : a) CLRSSR ; b) CLRSR; c) Clrscl; d) Clrscr ; Câu 9: Trong Pascal, muốn dùng lệnh xóa màn hình Clrscr thì phải khai báo nào sau phần tiêu đề chương trình : a) Uses CRT ; b) USES Graph; c) use CRT ; d) không khai báo gì ; Câu 10: Khẳng định nào Sai: Turbo Pascal, a) để lưu chương trình lên đĩa, gõ phím F2 chọn lệnh File / Save ; b) để mở tập tin cũ, gõ phím F1; c) để tìm lỗi cú pháp chương trình, gõ phím Alt_F9, hay F9 ; d) để chạy chương trình, gõ phím ^F9 chọn lệnh Run / Run ; 5.6 BÀI TẬP Câu Soạn và chạy thử chương trình ví dụ mở đầu mục 5.3.1 Câu Soạn và chạy thử chương trình ví dụ mục 5.3.3 Câu Viết chương trình nhập vào số đo cạnh và diện tích hình chữ nhật, tính cạnh và chu vi hình chữ nhật Câu Viết chương trình in lên màn hình hai câu sau : " Chao cac ban ! " " Rat vui đuoc lam quen voi cac ban ! " Câu Viết chương trình nhập hai số x và y, tính và in lên màn hình tổng x+y, hiệu x-y và tích x*y hai số đó (30) Bài Các kiểu liệu đơn giản YÊU CẦU CỦA BÀI GIẢNG Nắm : Khái niệm kiểu liệu, kiểu liệu đơn giản, kiểu liệu có cấu trúc và kiểu liệu đếm Pascal Phạm vi gía trị và các phép toán kiểu nguyên, thực, ký tự và lô gic, ý nghĩa và cách sử dụng các hàm và thủ tục thông dụng Nội dung các chương trình mẫu, thực hành các chương trình mẫu Turbo Pascal 6.1 KHÁI NIỆM VỀ KIỂU DỮ LIỆU 6.1.1 Khái niệm : Chức máy điện toán là xử lý các thông tin Các thông tin nhập và lưu trữ nhớ máy các dạng khác nhau: có thể là số, là chữ, có thể là hình ảnh, âm thanh,.v.v mà thuật ngữ tin học gọi chung là liệu Tính đa dạng liệu đòi hỏi phải tổ chức và phân phối nhớ thích hợp để lưu trữ và xử lý tốt các liệu Ngôn ngữ thảo chương chia các liệu thành nhóm riêng trên đó xây dựng số phép toán tạo nên các kiểu liệu khác nhau, kiểu liệu là tập hợp các gía trị mà biến thuộc kiểu đó có thể nhận Khi biến khai báo thuộc kiểu liệu nào thì máy dành cho biến đó dung lượng thích hợp nhớ để có thể lưu trữ các gía trị thuộc kiểu liệu đó 6.1.2 Phân loại kiểu liệu : Các kiểu liệu ngôn ngữ Pascal chia thành hai loại chính: loại đơn giản và loại có cấu trúc Mỗi kiểu liệu đơn giản là tập các giá trị sở có thứ tự Ví dụ kiểu Integer gồm các số nguyên nằm phạm vi từ -32768 đến 32767 và có thứ tự tự nhiên : -32768< < -1 < < < < 32767 , kiểu lô gic có hai gía trị False, True với quy ước False < True Các kiểu liệu có cấu trúc xây dựng từ các kiểu liệu đơn giản Mỗi kiểu liệu có cấu trúc là tập các phần tử thuộc kiểu liệu đơn giản tổ chức lại theo quy tắc định Các kiểu liệu đơn giản gồm có: kiểu nguyên, kiểu thực, kiểu lô gic, kiểu ký tự, kiểu liệt kê và kiểu đoạn Các kiểu liệu có cấu trúc gồm có :kiểu mảng, kiểu ghi, kiểu tập hợp và kiểu tập tin Riêng chuỗi ký tự (STRING) là kiểu liệu đặc biệt, vừa có tính đơn giản lại vừa có tính cấu trúc Mỗi chuỗi có thể xem là gía trị, có thể xem là mảng các gía trị kiểu ký tự Vì vậy, việc sử dụng chuỗi có hai mức khác nhau: mức đơn giản và mức có cấu trúc (31) Các kiểu liệu đơn giản còn phân thành hai loại: đếm (Ordinal type) và không đếm Kiểu thực thuộc loại không đếm được, các gía trị nó dày đặc Tất các kiểu liệu đơn giản còn lại : nguyên, ký tự, lô gic, liệt kê và đoạn thuộc loại đếm (còn gọi là rời rạc) Dưới đây trình bày kỹ kiểu liệu đơn giản chuẩn và thông dụng: kiểu nguyên, kiểu thực, kiểu logic, kiểu ký tự Kiểu chuỗi giới thiệu để có thể sử dụng mức đơn giản 6.2 KIỂU SỐ NGUYÊN 6.2.1 Các kiểu số nguyên : Tên kiểu Phạm vi gía trị ShortInt -128 127 Byte 255 Integer -32768 32767 Word 65535 LongInt -2147483648 2147483647 Số byte 1 2 Bảng 6.1 Ngoài kiểu Integer là thông dụng nhất, các số nguyên còn chia thành kiểu đó là: Byte, Word, ShortInt và LongInt Bảng 6.1 liệt kê chi tiết tên gọi, phạm vi gía trị và độ dài tính theo đơn vị byte kiểu nguyên Các biến nguyên có thể nhận các gía trị là các số nguyên nằm phạm vi gía trị biến đó Khi gán cho biến số nguyên nằm ngoài phạm vi biến thì máy báo lỗi: "Const out of range" Ví dụ, cho khai báo : Var i : Byte; N : Integer; thì các lệnh đưới đây là đúng: i:= 200; (32) N:= -1500; còn các lệnh đây là bị lỗi : i:= -5; N:= 50000; Ðặc biệt không thể gán số thực cho biến nguyên Câu lệnh sau là sai : N:= 12.5 ; Khi gặp tình này, máy báo lỗi "Type mismatch" Chú ý: Các số nguyên hệ thập lục phân (hệ 16) biểu diễn cách viết thêm dấu $ trước số, ví dụ ba số đây : $A , $FF và $10 là các số nguyên viết hệ 16 Chúng có gía trị tương ứng hệ 10 là: 10 , 255 và 16 6.2.2 Các phép toán số học trên số nguyên: Phép cộng và trừ : ký hiệu + và - thường lệ Phép nhân : ký hiệu dấu *, ví dụ 4*2 cho kết qủa là Phép chia : ký hiệu dấu / , ví dụ 6/4 cho kết qủa là 1.5 Phép chia lấy phần nguyên : ký hiệu từ khóa DIV Phép lấy phần dư nguyên phép chia: ký hiệu từ khóa MOD Ví dụ: 15 DIV cho kết qủa là 15 MOD cho kết qủa là Các phép toán trên cho kết qủa là các số nguyên, trừ phép chia ( / ) luôn cho kết qủa là số thực Vì N là biến nguyên, mà gán : N:= 20/5; thì máy báo lỗi, vế phải có gía trị kiểu thực (=4.0) mặc dù phần lẻ không Nhận xét : số nguyên N là chẵn N mod = (tức N chia hết cho 2), ngược lại, là lẻ N mod <> (dấu <> Pascal có nghĩa là khác ) (33) Thứ tự thực các phép toán giống thường lệ: Các biểu thức ( ) tính trước tiên Kế đến là *, /, div, mod Sau cùng là +, Ðối với các phép toán cùng thứ tự mà đứng liền thì phép toán nào đứng trước làm trước Ví dụ: tính biểu thức sau : 15 mod (2 +4) * 20 div (10 div 4) + 40 mod ( 5* 3) =15 mod * 20 div + 40 mod 15 = * 20 div + 10 = 60 div + 10 = 30 + 10 = 40 Ví dụ sau đây là ứng dụng các phép toán div, mod : Ví dụ 6.1: Nhập số tiền N đồng, đổi xem bao nhiêu tờ đồng, bao nhiêu tờ đồng, bao nhiêu tờ đồng cho tổng số tờ là ít Ví dụ N=43 đ = tờ đ + tờ đ + tờ đ Cách tính sau : Số tờ đ = 43 div = Số tiền dư = 43 mod = Số tờ đ = Số tiền dư div = div =1 Số tờ đ = Số tiền dư mod = mod = Dưới đây là chương trình cụ thể : PROGRAM VIDU61; { Ðổi tiền } Var N, st5, st2, st1, sodu : LongInt; Begin (34) Write(‘ Nhap so tien : ’); Readln(N); st5 := N div 5; Sodu := N mod 5; { tính phần dư } st2 := Sodu div 2; st1 := Sodu mod 2; Writeln(‘ KET QUA DOI TIEN LA: ’ ) ; Writeln(‘ So to 5đ= ‘, st5); Writeln(‘ So to 2đ= ‘, st2); Writeln(‘ So to 1đ=‘, st1); Readln; End Chạy<VD61.EXE> Chép tập tin nguồn <VD61.PAS> 6.2.3 Các phép toán so sánh : Ngôn ngữ Pascal có sáu phép toán so sánh liệt kê bảng 6.2 Ký hiệu Ý nghĩa = <> khác < nhỏ <= nhỏ > lớn >= lớn Ví dụ x=y x<>y x<y x<=y x>y x>=y (35) Bảng 6.2 Kết qủa các biểu thức so sánh là gía trị lôgic Ðúng (TRUE) Sai (FALSE) Ví dụ: Biểu thức 5*2=10 cho kết qủa là TRUE Biểu thức 5+2 <> cho kết qủa là FALSE Biểu thức div > 10 div cho kết qủa là FALSE 6.2.4 Các phép toán lôgic trên số nguyên : Các phép tính NOT, AND, OR, XOR xử lý các bít nhị phân xác định sau ( bảng 6.3 ): NOT = AND 1=1 OR 1=1 XOR 1=0 NOT = 1 AND 0=0 OR 0=1 XOR 0=1 AND 1=0 OR 1=1 XOR 1=1 AND 0=0 OR 0=0 XOR 0=0 Bảng 6.3 Mỗi số nguyên biểu diễn máy dạng dãy các bít nhị phân Số kiểu Integer biểu diễn 16 bit Ví dụ, số và số có biểu diễn máy là : 0000 0000 0000 0001 0000 0000 0000 0011 Phép lấy NOT số nguyên đảo tất các bít biểu diễn số nguyên đó, tức là thành 1, còn thành Ví dụ: NOT = 1111 1111 1111 1110 NOT = 1111 1111 1111 1100 Phép lấy AND, OR, XOR hai số nguyên tiến hành cách AND, OR, XOR cặp bít tương ứng hai số đó, ví dụ: OR = 0000 0000 0000 0011= AND = 0000 0000 0000 0001= 6.2.5 Các phép dịch chuyển số học SHR và SHL : (36) N SHR k : dịch các bít số nguyên N sang phải k bít N SHL k : dịch các bít số nguyên N sang trái k bít Có thể chứng minh : N SHR k = N div 2k N SHL k = N * 2k Ví dụ: 120 shr = 7, vì : 120 shr = 120 div 24 = 120 div 16 = 120 shl = 960, vì : 120 shl = 120 * 23 = 120 * = 960 Hai phép toán SHR và SHL dùng muốn tăng tốc độ tính toán trên các số nguyên 6.2.6 Các hàm có đối số nguyên : Hàm PRED(k) : đối số k nguyên, trả số nguyên đứng trước k, tức là k-1 Ví dụ: Pred (5) = 4, Pred (-6) = -7 Hàm SUCC(k) : đối số k nguyên, trả số nguyên đứng sau k, tức là k+1 Ví dụ: Succ (5) = 6, Succ (-6) = -5 Nhận xét : Lệnh k:=k+1; tương đương với lệnh k:=Succ(k); Lệnh k:=k-1; tương đương với lệnh k:=Pred(k); Hàm ODD(k) : đối số k nguyên, trả gía trị logic là TRUE k lẻ, là FALSE k chẵn Ví dụ: Odd(15) = True Odd(4) = False Ví dụ 6.2 : Nhập số nguyên N, N chẵn thì in chữ chẵn, N lẻ thì in chữ le? Chương trình sau : (37) PROGRAM VIDU62; Var N : Integer; Begin Write(‘Nhap so N :’); Readln(N); If Odd(N) = TRUE then write(N, ‘ La so le’) else write(N, ‘ La so chan’); Readln; End Chạy<VD62.EXE> Chép tập tin nguồn <VD62.PAS> 6.2.7 Các thủ tục có đối số nguyên: Có hai thủ tục khá thông dụng là: Thủ tục INC(k) : tăng k lên đơn vị Ví dụ, sau thực các lệnh : k:=5; Inc(k); thì gía trị sau cùng k là Vậy, lệnh Inc(k); tương đương với lệnh k:=k+1; hay k:=Succ(k); Thủ tục DEC(k) : giảm k đơn vị Ví dụ, sau thực các lệnh : k:=5; Dec(k); thì gía trị k là Vậy, lệnh Dec(k) ; tương đương với lệnh k:=k-1; hay k:=Pred(k); 6.3 KIỂU SỐ THỰC 6.3.1 Kiểu Real và các kiểu mở rộng : (38) Kiểu Real là kiểu số thực thông dụng dùng để biểu diễn các số thực x có trị tuyệt đối  x nằm khoảng từ 2.9*10-39 đến 1.7*10+38 Nếu  x > 1.7*10+38 thì không biểu diễn x máy được, còn  x < 2.9*10-39 thì x coi là Có hai cách biểu diễn các số thực: Cách 1: Viết bình thường, đó dấu phẩy thập phân thay dấu chấm thập phân Ví dụ: 45.0 -256.45 +122.08 Cách 2: Viết số dạng khoa học : 1.257E+01 (có gía trị = 1.257*101 = 12.57 ) 1257.0E-02 (có gía trị = 1257*10-2 = 12.57 ) Trong dạng này số gồm có hai phần, phần đứng trước E gọi là phần định trị, viết theo cách 1, phần đứng sau E gọi là phần bậc, gồm dấu cộng trừ, tiếp đến là số nguyên Số viết theo cách còn gọi là số có dấu chấm thập phân cố định, số viết theo cách còn gọi là số có dấu chấm thập phân di động hay số dạng khoa học (Scientific) Ví dụ: Muốn khai báo hai biến x, y kiểu real, ta viết: Var x, y : Real; Ngoài kiểu Real ra, các số thực còn có kiểu mở rộng là Single, Double, Extended va? Comp Bảng 6.4 nêu chi tiết phạm vi gía trị và số byte dùng để lưu trữ nhớ kiểu số thực Tên kiểu Phạm vi gía trị Real 2.9*10-39 1.7*1038 Single 1.5*10-45 3.4*1038 Double 5.0*10-324 1.7*10308 Extended 3.4*10-4932 1.1*104932 Comp -9.2*1018 9.2*1018 Số byte 10 (39) Bảng 6.4 Chú y? : Turbo Pascal thường làm việc với kiểu Real Muốn dùng kiểu thực còn lại, phải chuyển sang mode 8087 bằ?g cách viết thị {$N+} đầu chương trình 6.3.2 Các phép toán trên số thực : Có phép toán số học là nhân (*), chia (/), cộng (+) và trừ (-) Khi các số hạng tham gia tính toán là kiểu thực thì kết qủa phép toán là số thực Phép toán DIV, MOD không dùng cho các số thực Ví dụ: với hai biến x, y kiểu thực thì lệnh sau là bị lỗi vì biểu thức vế phải không hợp lệ: y:= x mod 10 ; Các phép toán so sánh (= , <> , < , <= , > , >= ) dùng cho các số hạng là thực hay nguyên 6.3.3 Các hàm có đối số nguyên thực : Hàm ABS(x): tính trị tuyệt đối x : x Kiểu liệu kết qủa cùng kiểu với đối số Nếu x nguyên thì ABS(x) nguyên, x là số thực thì ABS(x) là số thực Ví dụ: Abs(5 - 8) = Hàm SQR(x): tính bình phương x: x2 Kiểu liệu kết qủa cùng kiểu với đối số Ví dụ: Sqr(4.0) = 16.0 Sqr(7 div 3) = Trong các hàm đây, đối số x có thể là nguyên hay thực, gía trị trả về?luôn luôn là kiểu thực: Hàm SQRT(x): tính , (x  0) Hàm EXP(x) : tính ex Hàm LN(x): tính lnx, (x > 0) Các hàm SIN(x), COS(x), và ARCTAN(x): tính sinx, cosx và arctgx Hàm INT(x) : cho số thực phần nguyên x Ví dụ : Int(12.55) = 12.0 Int(1+10/3)=4.0 (40) Hàm FRAC(x) : cho số thực phần lẻ x Ví dụ : Frac(12.55) = 0.55 Hai hàm đặc biệt đây cho kết qủa là số nguyên: Hàm TRUNC(x): cho số nguyên là phần nguyên x Ví dụ : Trunc(12.55) = 12 Trunc(-2.98) = -2 Hàm ROUND(x): cho số nguyên cách làm tròn x Ví dụ : Round(12.45) = 12 Round(-2.98) = -3 Chú ý hàm Int(x) và hàm Trunc(x) cùng cho phần nguyên x, chúng khác kiểu liệu gía trị trả Int(4.5)= 4.0 còn Trunc(4.5) = (viết thì hiểu đó là số nguyên, còn viết 4.0 thì hiểu đó là số thực) Ví dụ 6.3: Viết chương trình nhập số thực x bất kỳ, tính và in các gía trị y và z lên màn hình theo công thức: Trong Pascal không có hàm tính trực tiếp 2x và Log4(x), nên ta phải chuyển qua hàm ex và Ln(x) sau: , và Chương trình cụ thể sau: PROGRAM VIDU63; Var x, y, z : Real; Begin Write(‘Nhap x: ‘); Readln(x); y:= ( sqrt (x*x+1) + sin(x)*sin(x) ) / ( 3*exp(2*x) + ); (41) z:= exp( x*Ln(2) ) + Ln(abs(x)+1) / Ln(4); Writeln(‘y= ‘, y:10:3 ); Writeln(‘z= ‘, z:10:3 ); Readln; End Khi chạy chương trình, nhập x =0 thì kết qủa y=0.250 và z=1.000 6.4 KIỂU KÝ TỰ (CHAR) 6.4.1 Ký tự và biến kiểu ký tự: Ký Mã Ký Mã Ký Mã tự ASCII tự ASCII tự ASCII 32 A 65 a 97 48 B 66 b 98 49 C 67 c 99 50 D 68 d 100 51 E 69 f 101 52 F 70 e 102 53 G 71 g 103 54 H 72 h 104 55 I 73 i 105 56 J 74 j 106 (42) 57 K 75 k 107 L 76 l 108 M 77 m 109 N 78 n 110 O 79 o 111 P 80 p 112 Q 81 q 113 R 82 r 114 S 83 s 115 T 84 t 116 U 85 u 117 V 86 v upload 123doc net W 87 w 119 X 88 x 120 Y 89 y 121 Z 90 z 122 Bảng 6.5 (43) Các ký tự dùng máy tính điện tử liệt kê đầy đủ bảng mã ASCII gồm 256 ký tự khác và đánh số thứ tự từ đến 255 Số thứ tự ký tự còn gọi là mã ASCII ký tự đó Biểu 6.5 liệt kê phần bảng mã ASCII gồm các chữ số và chữ cái kèm theo mã chúng Trong bảng 6.5, ký tự có mã 32 là ký tự trắng (space) Tuy có 256 ký tự khác song có 128 ký tự đầu tiên là hay dùng, còn lại là các ký tự mở rộng Các ký tự có mã từ đến 31 gọi 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, chẳng hạn ký tự có mã là dùng để tạo tiếng kêu bip, ký tự có mã là 13 dùng để chuyển trỏ màn hình xuống đầu dòng Mỗi ký tự bảng mã ASCII gọi là ký tự, chiếm độ dài byte, và viết Pascal phải đặt cặp nháy đơn: ‘0’, ‘1’, ‘A’, ‘B’, ‘$’, Giữa các ký tự, có thứ tự mặc nhiên theo nguyên tắc : ký tự có mã nhỏ thì nhỏ Tức là: Ký tự trắng < ‘0’< ‘1’< < ‘9’< ‘A’< ‘B’< ’Z’< ‘a’< ‘b’< < ‘z’ Biến nhận gía trị là các ký tự gọi là biến kiểu ký tự, chúng khai báo nhờ từ khóa CHAR, chẳng hạn khai báo hai biến ch và ch1 đây: Var ch, ch1: Char ; Khi đó có thể gán: ch:=‘A’; ch1:=‘$’; Ký tự ‘A’ gọi là gía trị biến ch, còn ‘$’ là gía trị biến ch1 Nhận xét: Từ bảng mã các chữ cái ta suy ra: Mã chữ thường = Mã chữ hoa tương ứng + 32 (1) 6.4.2 Các hàm liên quan đến ký tự : Hàm PRED(ch): cho ký tự đứng trước ký tự ch bảng mã Ví dụ: Pred(‘B’)=‘A’ Hàm SUCC(ch): cho ký tự đứng sau ký tự ch bảng mã Ví dụ: Succ(‘A’)=‘B’ Hàm UpCase(ch): đổi ký tự ch thành chữ hoa Ví dụ: Upcase( ‘a’ ) = ‘A’, Upcase( ‘b’ ) = ‘B’, Upcase( ‘A’ ) = ‘A’ (44) Hàm ORD(ch) : cho mã ký tự ch Ví dụ: Ord (‘A’) = 65, Ord (‘a’) = 97 Hàm CHR(k) : đối số k nguyên, 0 k  255, cho ký tự có mã bằ?g k Ví dụ: Chr (65)= ‘A’ , Chr (97)= ‘a’, Chr(32) là ký tự trắng Có số ký tự không có trên bàn phím, để viết chúng lên màn hình ta phải dùng lệnh Write và hàm CHR Ví dụ: Lệnh Writeln(Chr(201)) ; in ký tự : + Lệnh Writeln(Chr(187)) ; in ký tự : + Ký tự có mã là gọi là ký tự BEL (chuông), và lệnh: Write( Chr(7) ) ; hay Write(#7) ; có tác dụng phát tiếng kêu bip Chú ý: Turbo Pascal ( TP ) cho phép viết gọn Chr(k) thành #k k là số Ví dụ, hai lệnh sau cùng in lên màn hình chữ A : Write(#65); Write(Chr(65)); Trong TP không có hàm đổi chữ hoa chữ thường, có thể làm việc này nhờ công thức (1) và hai hàm Ord và Chr : Chữ thường := Chr ( Ord(chữ hoa) + 32 ) Ví dụ 6.4: Nhập vào số nguyên k, 0 k  255, in ký tự có mã là k Chương trình kết thúc nhập vào số : PROGRAM VIDU64 ; Uses CRT; Var k : Byte; Begin CLRSCR; Writeln(‘ Nhập số để kết thúc :’); (45) Repeat Write(‘ Nhập mã ký tự : ‘); Readln(k); Writeln(‘ Ký tự có mã ‘, k, ‘ là ‘ , Chr(k) ); Until k=0; End Chạy<VD64.EXE> Chép tập tin nguồn <VD64.PAS> Ví dụ 6.5: Nhập ký tự, là chữ hoa thì đổi chữ thường, là chữ thường thì đổi chữ hoa PROGRAM VIDU65; { Ðổi chữ hoa thường và ngược lại} Var ch, ch1 : Char; Begin Write(‘ Nhập ký tự :’); Readln(ch); If (ch>=‘A’) and ( ch<=‘Z’) then ch1:=Chr( Ord (ch)+32) else ch1:= Upcase(ch); Writeln(ch, ‘ đã đổi ra: ‘ , ch1); Readln; End 6.5 KIỂU LÔGIC (BOOLEAN) Kiểu boolean có hai gía trị là TRUE (đúng) và FALSE (sai), không phân biệt chữ hoa hay chữ thường Về quan hệ thứ tự thì FALSE< TRUE Mỗi gía trị boolean chiếm byte nhớ Các phép toán lôgic gồm có: NOT, AND, OR và XOR Nếu A và B là hai đại lượng lôgic thì NOT A, A and B, A or B và A xor B là đại lượng lôgic có kết qủa cho bảng 6.6 A not A (46) True False False True A B A and B A or B A xor B True True True True False True False False True True False True False True True False False False False False Bảng 6.6 Cũng từ bảng này ta rút các nhận xét : A and B là đúng và A và B đồng thời đúng (Do đó cần hai biến A B sai thì A and B sai) A or B là sai và A và B đồng thời sai (Do đó cần hai biến A B đúng thì A or B đúng) A xor B là đúng và A khác B Thứ tự thực các phép toán lôgic là sau: NOT tính trước, AND, sau cùng là OR, XOR Ví dụ, sau thực lệnh: A:=Not (2*3=5) or (‘A’<‘B’) and not (4/2=2) xor (Sqrt(2) >1); thì gía trị A= FALSE, : Not (2*3=5) or (‘A’<‘B’) and not (4/2=2) xor (Sqrt(2) >1) = TRUE or TRUE and FALSE xor TRUE = TRUE or FALSE xor TRUE = TRUE xor TRUE (47) = FALSE Biến nhận gía trị là TRUE FALSE gọi là biến kiểu lôgic Khi khai báo biến kiểu lôgic ta dùng từ khóa Boolean, ví dụ : Var A, B : Boolean; Trong chương trình ta có thể gán : A:= true; B:=2*2 < 3; Gía trị biến B là False vì biểu thức 2*2< là sai Về thứ tự tính toán, các phép so sánh thì ngang cấp và tính sau tất các phép toán khác Ví dụ tính biểu thức : 5+7 div < -7 mod + 5*2 = = + < -1 + 10 = 8< = TRUE Do đó, biểu thức mà có các phép toán lôgic xen kẽ với các biểu thức so sánh thì các biểu thức so sánh phải để ngoặc đơn Chẳng hạn, biểu thức sau là sai quy cách: N > and N<10 Cần sửa đúng thành : (N > 0) and (N<10) Ví dụ 6.6: Nhập vào độ dài ba cạnh a,b,c tam giác, a, b, c không phải là ba cạnh tam giác thì in lên màn hình câu " không phải ba cạnh tam gíac", ngược lại, đúng là ba cạnh tam giác thì tính chu vi và diện tích tam giác đó theo công thức Hêrông: , với p là nửa chu vi: (48) Ta biết, điều kiện để a,b,c là ba cạnh tam giác là cạnh phải dương và tổng hai cạnh thì lớn cạnh còn lại Dưới đây là chương trình cụ thể : PROGRAM VIDU66; {Tính diện tích và chu vi tam giác theo cạnh} Var a, b, c, P, S : Real; Tgiac: Boolean; Begin Write(‘ Nhap canh cua tam giac : ‘); Readln(a, b, c); Tgiac:= (a>0) and (b>0) and (c>0) and (a+b>c) and (a+c>b) and (b+c>a); If Tgiac= FALSE then Writeln(‘ Khong phai ba canh cua tam giac !’) else begin P:=(a+b+c)/2; S:= Sqrt( P*(P-a)*(P-b)*(P-c) ); Writeln(‘ chu vi = ‘ , 2*P:10:2); Writeln(‘ dien tich S= ‘ , S:10:2); end; Readln; End Khi chạy chương trình này, để nhập ba cạnh tam giác, bạn gõ ba số cách khoảng trắng enter, chẳng hạn : Nhap canh cua tam giac : (49) Kết qủa chu vi= 12.00, dien tich= 6.00 Nếu nhập ba cạnh là : thì máy câu: "Không phải ba cạnh tam giác ! " (vì 2+3 < 6) 6.6 CHUỖI KÝ TỰ (STRING) Một dãy ký tự đặt cặp nháy đơn gọi là chuỗi Dưới đây là ba chuỗi : ‘NGON NGU PASCAL’ ‘Tin hoc nam 2000’ ‘123456’ Các chuỗi có thể ghép nối với nhờ phép cộng chuỗi Khi cộng (+) hai chuỗi ta chuỗi cách ghép chuỗi sau vào cuối chuỗi đầu Ví dụ phép cộng : ‘Ngon ngu’ + ‘ Pascal’ cho kết qủa là ‘Ngon ngu Pascal’ Các chuỗi so sánh với Việc so sánh hai chuỗi thực cách so sánh cặp ký tự tương ứng từ trái qua phải Khi phát có cặp ký tự khác thì chuỗi nào chứa ký tự nhỏ nhỏ hơn, ví dụ: Biểu thức ‘Anh’ < ‘an’ là đúng vì ‘A’ < ‘a’ Biểu thức ‘Thong’ > ‘Tha’ là đúng vì ‘o’ > ‘a’ Nếu nội dung?của hai chuỗi giống từ đầu đến hết chiều dài chuỗi ngắn thì chuỗi ngắn là nhỏ hơn, ví dụ: Biểu thức ‘Tha’ < ‘Thang’ là đúng vì ‘Tha’ ngắn ‘Thang’ Hai chuỗi chúng dài và cặp ký tự các vị trí tương ứng giống Ví dụ: Biểu thức ‘Pascal’ = ‘Pascal’ cho kết qủa là đúng Biểu thức ‘Pascal’ = ‘PAscal’ cho kết qủa là sai Biến nhận giá trị là các chuỗi gọi là biến kiểu chuỗi Có thể khai báo hai biến chuỗi sau: Var Ho_ten : String[20]; St : String; đó Ho_ten là biến chuỗi có thể chứa tối đa 20 ký tự, còn biến chuỗi St có thể chứa tối đa 255 ký tự, và ta có thể gán : Ho_ten := ‘Nguyen Van An’; (50) St :=‘Thao chuong bang ngon ngu Pascal’; Chuỗi ‘Nguyen Van An’ gọi là gía trị biến Ho_ten Tương tự, chuỗi ‘Thao chuong bang ngon ngu Pascal’ là gía trị biến St (51) 6.7 CÂU HỎI TRẮC NGHIỆM Câu 1: Cho khai báo biến : Var m, n : integer; x, y : Real; Lệnh nào sai : a) m := -4; b) n := 3.5; c) x := 6; d) y := +10.5; Câu 2: Ðể tính gía trị , chọn cách viết nào : a) x := -b/2a; b) x := -b/2*a; c) ; d) x := -b/2/a; Câu 3: Biểu thức : 25 div + 5/2*3 có giá trị là : a) 8.0; b) 15.5; c) 9.5; d) 15.0; Câu 4: Cho phương trình : ax2 + bx + c = Giả sử a? và Delta:= b*b- 4*a*c > Một nghiệm phương trình là : a) X:= -b + SQRT(Delta) / (2*a); b) X:= (-b + SQRT(Delta) ) /2*a; c) X:= (-b + SQRT(Delta) ) / (2*a); d) X:= (-b -SQR(Delta) ) /2/a; Câu 5: Cho ch là biến có kiểu Char Lệnh nào đúng : a) ch:="a" b) ch:=65; c) ch:=chr(65); d) ch:='abcd'; Câu 6:Biến X khai báo là kiểu integer Lệnh nào sai : (52) a) X:= round(275/3); b) X:= 210 div 4; c) X:= SQRT(49); d) X:= ABS(-453); Câu 7: Biểu thức nào sau đây có giá trị TRUE : a) (100 > 76) and ('B' < 'A'); b) not (49.5 + < 5) or (2 > div 2); c) (49.5 + < 5) and (2 < div 2); d) 2*(3+5) < 18 div 4*4; Câu 8: Khi chạy chương trình : Var St, St1 : String; Begin St := '123'; St1 := '456'; Write(St + St1); End; Kết in là : a) '123456'; b) 123456; c) 579; d) Câu a), b), c) sai; Câu 9: Sau phép gán : Ch := CHR( ORD('a')- 32 ); thì giá trị Ch là : a) 65; b) A; c) 'A'; d) 'a'; Câu 10: Khi chạy chương trình : Var a, b, c, N : integer; Begin N:=546; a:=N div 100; (53) b:=(N Mod 100) div 10; c:=(N Mod 100) Mod 10; Write(a+b+c); End Kết in : a) 546; b) 5; c) 15; d) 6; Bài Các khái niệm Pascal YÊU CẦU CỦA BÀI GIẢNG Nắm : Khái niệm biến, hằng, cách khai báo biến, Khái niệm câu lệnh, lệnh đơn giản và lệnh có cấu trúc Thứ tự tính toán và kiểu liệu biểu thức Lệnh gán và tính tương thích kiểu liệu lệnh gán Chi tiết các lệnh nhập, xuất liệu Cách khai báo kiểu liệu mới, kiểu liệt kê và đoạn 7.1 HẰNG, BIẾN và BIỂU THỨC 7.1.1 Khái niệm biến và : Trong phần trước ta đã biết kiểu liệu có tập các giá trị tương ứng Các giá trị kiểu nguyên hay kiểu thực là các số, 40 hay 5.72, các gía trị kiểu ký tự là các ký tự ‘A’ hay ‘a’, còn kiểu lôgic thì có hai gía trị là True và False, Qúa trình xử lý máy tính đòi hỏi gía trị phải lưu trữ ô nhớ nào đó nhớ máy, và ô nhớ này đặt cái tên để gọi Khi đó việc tính toán hay xử lý liên quan đến gía trị thực gián tiếp thông qua tên ô nhớ chứa giá trị đó Ví dụ, số 5.72 lưu ô nhớ có tên là x, thì biểu thức 5.72*2 có thể viết là x*2 Việc dùng tên x dễ nhớ và tiện nhiều so với việc dùng và nhớ số 5.72 Như vậy, ô nhớ đặt tên thì tên này đồng với giá trị nó Trong chương trình, ô nhớ có tên giá trị nó thì có thể thay đổi không Nếu gía trị ô nhớ có thể thay đổi thì ô nhớ này là biến, tên ô nhớ là tên biến, ngược lại, gía trị ô nhớ không thể thay đổi, thì ô nhớ là hằng, tên ô nhớ là tên (54) Các biến và tham gia chương trình phải khai báo Việc khai báo có tác dụng báo trước cho máy dành sẵn các ô nhớ thích hợp nhớ để sẵn sàng chứa liệu 7.1.2 Khai báo biến và khai báo : Biến là đại lượng có gía trị thay đổi chương trình Cách khai báo biến sau : Var Danhsáchtênbiến : TênKiểuDữliệu ; Tên biến là tự đặt, theo đúng quy tắc tên Ví dụ : Var i, j : Integer; x, y : Real; Theo khai báo trên, ta có hai biến i và j cùng kiểu số nguyên (Integer), và hai biến x, y cùng kiểu số thực (Real) Hằng là đại lượng có gía trị không đổi chương trình Cách khai báo : Const Tên_hằng = gíatrị ; Tên là tự đặt, theo đúng quy tắc tên Ví dụ : Const N = 10; SoPi = 3.1416; SoE = 2.718; Turbo Pascal có sẵn số hằ?g chuẩn cho phép sử dụng mà không phải khai báo, : Pi, MaxInt Hằng Pi có gía trị số  , còn MaxInt = 32767, là số Integer lớn Chẳng hạn, có thể dùng các lệnh sau: Writeln(‘Dien tich hinh tron ban kinh r=5 la: ‘ , Pi*5*5:8:3); Writeln(‘So Integer lon nhat = ‘ , MaxInt); 7.1.3 Biểu thức : Biểu thức là công thức gồm có hay nhiều thành phần kết nối với các phép toán Mỗi thành phầ? (hay toán hạng) có thể là hằng, là biến hay là hàm Khi các phép toán biểu thức thực thì ta nhận gía trị gọi là kết qủa biểu thức Kiểu liệu kết qủa gọi là kiểu liệu biểu thức Ví dụ: (55) 3* div + mod là biểu thức nguyên, có kết qủa là 10 + sin(pi/2) là biểu thức thực, có kết qủa là 3.0 Chr( ord(‘a’) - 32 ) là biểu thức ký tự, có kết qủa là ‘A’ (4+2=6) and (‘B’<>‘b’) là biểu thức lôgic, có kết qủa là True ‘AB’+’CD’ là biểu thức chuỗi, có kết qủa là ‘ABCD’ Các thành phần biểu thức cầ? phải có kiểu liệu phù hợp các phép toán thực được, không máy báo lỗi Ví dụ, biểu thức sau : + ‘A’ là sai vì ta không thể cộng số nguyên với ký tự Một biểu thức có thể chứa nhiều phép toán Thứ tự thực các phép toán cho bảng 7.1 đây Cấp ưu tiên Phép toán biểu thức ngoặc đơn ( ) Các hàm NOT, - (phép lấy dấu âm) * , /, DIV, MOD, AND Shl, Shr +, - (trư?, OR, XOR =, <>, <, <=, >, >=, IN Bảng 7.1 Việc tính toán biểu thức dựa theo hai quy tắc : Quy tắc 1: Phép toán có cấp ưu tiên nhỏ thì tính trước, phép toán có cấp ưu tiên lớn thì tính sau (56) Quy tắc 2: Ðối với các phép toán đứng liền và có cùng cấp ưu tiên, thì cái nào đứng trước tính trước Ví dụ : tính biểu thức số học : (4+5)*2 div + sin(pi/6) = = * div + 0.5 = 18 div + 0.5 = + 0.5 = 2.5 Ví dụ : tính biểu thức lôgic : ( > div 2) or Not ( 49.25 + < 50) = (2 > 2) or Not ( 51.25 < 50) = FALSE or Not FALSE = FALSE or TRUE = TRUE 7.2 CÂU LỆNH VÀ LỜI CHÚ GIẢI 7.2.1 Phân loại câu lệnh : Câu lệnh là dãy các ký tự xây dựng theo quy tắc định (gọi là cú pháp) nhằm thị cho máy thực công việc xác định Các câu lệnh chia hai loại: câu lệnh đơn giản và câu lệnh có cấu trúc Lệnh gán và lời gọi thủ tục xếp vào loại đơn giản Ví dụ: k := 20; Clrscr ; Writeln(k) ; Các lệnh rẽ nhánh và lệnh lặp xếp vào loại có cấu trúc, chúng xây dựng từ các lệnh đơn giản, ví dụ: If k>=0 then Writeln(k) else Writeln( -k) ; (57) Hai hay nhiều lệnh đơn giản gom lại và đặt hai từ khóa BEGIN và END tạo thành câu lệnh ghép, câu lệnh ghép là lệnh có cấu trúc, ví dụ: Begin Write(‘ nhập k :’); Readln(k); End; Từ các lệnh đơn giản và các lệnh có cấu trúc đã có lại có thể xây dựng các lệnh có cấu trúc phức tạp hơn, ví dụ: If k>= then Writeln(k) else Begin Writeln(‘ k âm, xin nhập lại : ‘); Readln(k); End; Sau đây trình bày kỹ lệnh đơn giản vàthông dụng : lệnh gán 7.2.2 Lệnh gán : Lệnh gán có cú pháp sau : TênBiến := Biểuthức ; Ý nghĩa : tính toán biểu thức bên phải, lưu kết qủa tính vào tên biến vế trái Ví dụ, cho khai báo : Var A, B : Real; K : Integer; Khi dùng lệnh các lệnh: K := 10 ; B := K* 3+5.5; thì biến K có gía trị là 10, biến B có gía trị là 35.5 Nếu thực tiếp lệnh gán : (58) B:= 17/2; thì gía trị B bây là 8.5 Như biến gán nhiề? lần thì nó lấy gía trị lần gán sau cùng, tính đến thời điểm xét Ðặc biệt, lệnh: B:=B +1; có tác dụng tăng gía trị biến B lên đơn vị, kết qủa là B có gía trị 9.5 Cách thực lệnh B:=B+1 là sau: lấy gía trị thời biến B (là 8.5) cộng thêm (được 9.5), đem kết qủa gán cho chính biến B Tương tự, lệnh B:=B-1; có tác dụng giảm B đơn vị Yêu cầu lệnh gán thực là kiểu liệu biểu thức vế phải phải phù hợp với kiểu liệu biến vế trái, không phù hợp thì dịch (Compile) chương trình, Turbo Pascal thông báo lỗi : "Error 26 : Type mismatch" Ví dụ, lệnh gán đây là sai vì vế trái là kiểu thực còn vế phải là kiểu chuỗi : A:=‘Pascal’; Chú ý số nguyên có thể gán cho biến thực, (chẳng hạn lệnh A:=10; là đúng ), số thực không thể gán cho biến nguyên Ví dụ lệnh K:=10/4; là sai vì biến K có kiểu nguyên, còn vế phải cho kết qủa là số thực (=2.5) Xét thêm ví dụ các kiểu liệu khác : Cho khai báo : Var Ch : Char ; St: String[20]; Khi đó: Lệnh St:=‘A’; là đúng Lệnh St:=‘1234’; là đúng Lệnh Ch:=‘ABCD’; là sai vì vế phải là chuỗi Lệnh St:= 100; là sai vì vế phải là số Lệnh Ch:=‘1’ ; là đúng Lệnh Ch:=St ; là sai vì vế phải là chuỗi 7.2.3 Lời chú giải : (59) Lời chú giải có thể đặt chỗ nào chương trình và viết theo hai cách : { lời giải thích } (* lời giải thích *) Lời giải thích là chuỗi ký tự giải thích mục đích chương trình hay câu lệnh Nó có tác dụng cho người dùng tham khảo nhằm hiểu nhanh mục đích chương trình hay câu lệnh mà không cần phải đọc hết chương trình hay câu lệnh đó 7.3.1 Nhập liệu, thủ tục Readln Nhập và xuất liệu là hai khâu quan trọng qúa trình xử lý thông tin Hầu chương trình nào phải giải vấn đề nhập, xuất liệu Có nhập liệu thì có liệu để tính toán hay xử lý Có liệu xuất thì biết kết qủa qúa trình xử lý máy 7.3.1.1 Nhập liệu kiểu số : Ðể nhập liệu cho biến nguyên hay thực, ta dùng lệnh: Readln(biến1, biến2, , biếnk); đó biến1, biến2, , biếnk đã khai báo và có kiểu liệu là nguyên hay thực Khi gặp lệnh này, chương trình tạm dừng, chờ ta gõ đủ k số từ bàn phím và kết thúc Enter, gán k số đó cho biến1, biến2, , biếnk Ví dụ, để nhập liệu cho hai biến thực x, y và biến nguyên j, ta dùng lệnh: Readln(x, y, j); Cách nhập sau: gõ 10 6.5  (có khoảng trắng hai số ), gõ số và Enter đây : 10 6.5 4 Trong hai trường hợp ta được: x=10, y=6.5, và j=4 Ngoài cách dùng lệnh Readln(x, y, j) ; ta có thể nhập riêng cho biến ba lệnh sau : Readln(x); Readln(y); (60) Readln(j); 7.3.1.2 Nhập liệu kiểu ký tự hay kiểu chuỗi: Ta dùng lệnh : Readln( biến ); Ví dụ, cho khai báo : Var Ho_ten: String[18]; Phai: String[3]; Khoi_thi : Char; Muốn nhập liệu cho ba biến Ho_ten, Phai, Khoi_thi ta phải dùng ba lệnh : Readln(Ho_ten); Readln(Phai); Readln(Khoi_thi); Khi nhập, ta gõ: Tran Van Thanh  nam A Kết qủa, ba biến có giá trị là: Ho_ten = ‘Tran Van Thanh’, Phai= ‘nam’ và Khoi_thi=‘A’ Khác với liệu số, ta không nên dùng lệnh Readln để nhập liệu cho hai hay nhiều biến kiểu ký tự hay kiểu chuỗi, vì có nhầm lẫn không kiểm soát Ví dụ, không dùng lệnh sau: Readln( Ho_ten, Phai, Khoi_thi); mà phải dùng ba lệnh Readln, lệnh nhập cho biến đã nêu trên 7.3.1.3 Các chú ý : a) Dữ liệu nhập phải phù hợp với kiểu biến Nếu không phù hợp thì chương trình dừng và thông báo lỗi.Ví dụ gặp lệnh Readln(j) ; mà ta gõ 4.5 thì bị lỗi vì j là biến nguyên, còn 4.5 là số thực (61) b) Lệnh: Readln ; là dạng nhập liệu đặc biệt vì nó không có biến nào để nhận liệu nhập vào Người ta dùng lệnh này muốn tạm dừng chương trình để xem kết qủa trên màn hình, xem xong, gõ phím Enter thì chương trình chạy tiếp c) Biến kiểu lôgic không nhập từ bàn phím d) Pascal còn có lệnh nhập liệu là Read, có công dụng lệnh Readln, ít dùng Sự khác Read và Readln là chỗ: sau đã nhận đủ các gía trị cho các biến cần nhập, lệnh Readln xóa các gía trị nhập thừa, còn lệnh Read thì không Các gía trị nhập thừa lệnh Read tự động gán cho các biến lệnh nhập Ví dụ, xét hai lệnh: Readln(x, y); Readln(j); Nếu nhập, ta gõ : 12.5 20.6 10  thì x=12.5, y=20.6, còn số 10 thừa bị xóa luôn Biến j lệnh Readln(j) không bị ảnh hưởng Muốn nhập số cho j, ta gõ 9 Với đoạn chương trình : Read(x, y); Readln(j); Nếu nhập, ta gõ : 12.5 20.6 10  thì x=12.5, y=20.6, còn số 10 thừa không bị xóa mà tự động gán cho biến j lệnh Readln(j) tiếp theo, kết qủa j=10 cho dù ta chưa muốn nhập cho j Vậy, lệnh Read có thể làm sai ý đồ nhập lệnh nhập Lời khuyên là không nên dùng lệnh Read, dùng Readln 7.3.2 Xuất liệu, thủ tục Write và Writeln Các liệu in lên màn hình nhờ các lệnh sau: Writeln( bt1, bt2 , , btk ); Write( bt1, bt2 , , btk ); đây, bt1, bt2, , btk là các biểu thức cầ? phải in gía trị lên màn hình Trong trường hợp đơn giản, biểu thức này có thể là biến, hằng, hay hàm (62) Việc in thực sau: vị trí thời trỏ trên màn hình, in gía trị biểu thức bt1, in tiếp gía trị biểu thức bt2, , in tiếp gía trị biểu thức btk Các gía trị này in trên dòng, dài qúa khổ màn hình thì in tiếp dòng Ví dụ, lệnh Writeln(3*2+9); in lên màn hình số 15 Nếu i, j là các biến nguyên thì thực các lệnh sau: i :=10 ; j:=15*2 ; Writeln(i, j+1, 678); trên màn hình hiện: 1031678 Sự khác lệnh Writeln và Write là chỗ: sau in xong giá trị các biểu thức, lệnh Writeln đưa trỏ xuống đầu dòng dưới, còn lệnh Write thì không Ðiều này ảnh hưởng đến lệnh in mà thôi Ví dụ, thực hai lệnh sau : Writeln(‘Thao chuong bang ‘); Writeln(‘ngon ngu pascal’); kết qủa trên màn hình hai dòng : Thao chuong bang ngon ngu pascal Nếu thay lệnh đầu Write đây: Write(‘Thao chuong bang ‘); Writeln(‘ngon ngu pascal’); thì kết qủa trên màn hình dòng: Thao chuong bang ngon ngu pascal 7.3.2.1 In không định dạng: Ðối với các biểu thức kiểu nguyên, kiểu ký tự, kiểu lô gíc hay kiểu chuỗi, thì lệnh : Writeln( biểuthức ) ; in nguyên văn gía trị biểu thức Ví dụ : Lệnh Writen(‘ket qủa x=‘ , 4+15); in ra: ket qua x=19 (63) Lệnh Writeln(‘A’ , ‘=‘ , 2*3<5); in ra: A=FALSE vì biểu thức 2*3< có kết qủa là FALSE Nếu gán: Ho_ten:=‘ Tran Van Thanh’; thì lệnh Writeln(‘Ho va ten: ‘, Ho_ten); in lên màn hình dòng chữ : Ho va ten: Tran Van Thanh Cần phân biệt hai đại lượng ‘Ho va ten: ‘ và Ho_ten Chúng khác hoàn toàn: ‘Ho va ten: ‘ là gía trị chuỗi, tức là chuỗi nên in nguyên văn lên màn hình, còn Ho_ten là biến kiểu chuỗi nên in gía trị mà biến này chứa Ðối với các biểu thức kiểu số thực thì lệnh: Writeln( biểuthức ); in gía trị biểu thức dạng dấu chấm thập phân di động có thảy 17 ký số, đó có 10 ký số phần định trị, sau: Ở đây ta dùng ký hiệu  để ký tự trắng, còn X đại diện ký số Ví dụ, cho x, y là hai biến thực và gán x:=100/4; y:=-9/300; thì hai lệnh sau : Writeln(‘ x= ‘, x); Writeln(‘ y= ‘, y); in lên màn hình : x = 2.5000000000E+01 y = -3.0000000000E-02 7.3.2.2 In có định dạng: a) In số thực có định dạng: In các số thực theo cách trên khó đọc Vì các số thực thường in có định dạng, giống cách viết số thông thường, lệnh: Writeln( biểuthức : n : k ); (64) Ở đây n và k là các số tự nhiên, ấn định dùng n cột để in gía trị biểu thức, đó có k cột dành cho phần thập phân Nếu số cần in có ít n chữ số thì nó in dồn bên phải và thêm các ký tự trắng bên trái cho đủ n cột Ví dụ, cho x, y là các biến kiểu thực và: x:=100/4; y:=-123.4824; Hai lệnh sau : Writeln(‘ x=‘, x:6:2); Writeln(‘ y=‘, y:10:3); in lên màn hình: x= 25.00 ( trước số có ký tự trắng) y= -123.482 (trước dấu - có ký tự trắng) Nếu n nhỏ chiều dài số cần in thì số in với đầy đủ các chữ số phần nguyên Ví dụ, thực các lệnh sau : x:=12345.675; Writeln(‘x= ‘, x:0:2); trên màn hình : x=12345.68 Ở đây máy đã làm tròn số bỏ số lẻ cuối cùng b) In kiểu nguyên, ký tự, chuỗi và lôgic có định dạng : Dùng lệnh : Writeln(biểuthức : n); đó n là số nguyên ấn định số cột dùng để in gía trị biểu thức Nếu n lớn độ dài gía trị cần in thì gía trị in dồn bên phải, và thêm các khoảng trắng bên trái cho đủ n cột Nếu n nhỏ độ dài gía trị cần in thì gía trị in nguyên văn Ví dụ: Lệnh Write(5+40:4); in ra: 45 (có ký tự trắng trước số 45) Lệnh Write(5+40:1); in ra:45 (in nguyên văn gía trị 45) Lệnh Write(‘Pascal’ :9); in ra: Pascal (có ký tự trắng trước chữ Pascal) Lệnh Write(‘Pascal’ :2); in ra:Pascal (in nguyên văn) Lệnh Write(‘*’:3); in ra: * (có ký tự trắng trước dấu *) (65) Các chú ý: Nhóm ba lệnh: Write(x); Write(y); Write(j); có tác dụng lệnh: Write(x, y, j); Nhóm ba lệnh: Write(x); Write(y); Writeln(j); có tác dụng lệnh: Writeln(x, y, j); Lệnh: Writeln; không in gì cả, đơn giản là đưa trỏ xuống dòng Ví dụ 7.1: Dưới đây là chương trình cho phép nhập họ tên, mã số sinh viên, in họ tên, mã số sinh viên đó cái khung vẽ các dấu *, hình chẳng hạn : ********************** * Nguyen Van Tuan * * Ma so: 1972508 * ********************** Chương trình cụ thể sau: PROGRAM VIDU71; Uses CRT; Var Ten : String[18]; Maso : String[11]; Begin CLRSCR; Write(‘ Nhap ho va ten: ‘); Readln(Ten); Write(‘ Nhap ma so sv : ‘); Readln(Maso); Writeln; Writeln(‘ ********************** ’); { in 22 dấu * } Writeln(‘*’, Ten:19, ‘*’:2); { in dấu *, in Ten chiếm 19 cột, in tiếp dấu * chiếm cột } Writeln(‘* Ma so:’ , Maso:12, ‘*’:2); { in * Ma so, in Maso chiếm 12 cột, in tiếp dấu * chiếm cột } (66) Writeln(‘**********************’); { in 22 dấu * } Readln; End 7.4 KIỂU LIỆT KÊ và KIỂU ÐOẠN CON 7.4.1 Kiểu liệt kê (enumerated type) : 7.4.1.1 Cách khai báo : Ngoài các kiểu liệu đã có sẵn kiểu nguyên, thực, ký tư, lôgic và kiểu chuỗi, Turbo Pascal còn cho phép người thảo chương có thể tự xây dựng các kiểu liệu Kiểu liệt kê định nghĩa cách sử dụng từ khóa TYPE và liệt kê tất các gía trị kiểu, theo mẫu sau: Type Tênkiểu = (tên1, tên2, , tênN) ; đó tên1, tên2, , tênN là các tên tự đặt theo đúng quy ước đặt tên Ví dụ : Type Phai=(nam, nu) ; Ten_mau = (den, trang, xanh, vang, tim, nau); Theo khai báo này thì Phai là kiểu liệu liệt kê có hai giá trị là nam và nu, Ten_mau là kiểu liệu liệt kê và có sáu giá trị là : den, trang, xanh, vang, tim, nau Khi kiểu liệt kê đã định nghĩa thì có thể khai báo các biến thuộc kiểu liệt kê này từ khóa Var Ví dụ : Var Ph1, Ph2 : Phai; M1, M2 : Ten_mau ; Trong chương trình, ta có thể gán : Ph1:=nam; Ph2:=nu; M1:=den; M2:=trang; (67) Pascal còn cho phép khai báo trực tiếp biến kiểu liệt kê không cần qua giai đoạn định nghĩa Type cách liệt kê các gía trị mà biến có thể nhận Ví dụ : các biến Ph1, Ph2, M1, M2 nói trên có thể khai báo trực tiếp sau: Var Ph1, Ph2 : (nam, nu) ; M1, M2 : ( den, trang, xanh, vang, tim, nau); 7.4.1.2 Các hàm liên quan đến kiểu liệt kê: Hàm ORD(tên) : Trả số thứ tự tên kiểu liệt kê Các gía trị liệt kê đánh số thứ tự Ví dụ: Ord(nam)=0, Ord(xanh)=2 Thông qua hàm Ord, các gía trị liệt kê có thể so sánh với theo quy tắc: gía trị nào có số thứ tự nhỏ thì nhỏ hơn: den < trang < xanh< vang< tim< nau Hàm PRED(tên) và hàm SUCC(tên) : trả gía trị đứng trước và sau tên kiểu liệt kê tương ứng Ví dụ: Pred(nu)=nam Pred(nau)=tim Succ(den)=trang Hàm Tênkiểu(k) : trả giá trị liệt kê có số thứ tự là k Tênkiểu, ví dụ: Phai(0)=nam Ten_mau(2)= xanh Hàm này là hàm ngược hàm Ord 7.4.1.3 Nhập , xuất kiểu liệt kê: Các gía trị liệt kê không thể nhập, xuất trực tiếp lệnh Readln và Write đượ? Ðây là hạn chế kiểu liệt kê, khiến nó không thông dụng (68) Khi muốn nhập hay xuất kiểu liệt kê, ta có thể dùng biến trung gian St kiểu chuỗi Chẳng hạn, muốn nhập màu xanh cho biến M1, ta dùng hai lệnh: Readln(St); If St=‘xanh’ then M1:=xanh; Tương tự, Muốn in màu xanh lên màn hình , ta dùng lệnh : If M1=xanh then Writeln(‘xanh’); 7.4.2 Kiểu đoạn (Subrange type): Kiểu đoạn mô tả cách phạm vi gía trị mà các biến thuộc kiểu đó có thể nhận : TYPE Tênkiểu = hằng1 hằng2; VAR Tênbiến : Tênkiểu; khai báo trực tiếp : VAR Tênbiến : hằng1 hằng2; đó, hằng1< hằng2 là hai thuộc cùng kiểu liệu Kiểu liệu hằng1 và hằng2 có thể là kiểu nguyên, ký tự, lôgic, hay liệt kê Ví dụ: Type Chu_Hoa =‘A’ ’Z’; Tuoi= 200; Var Ch : Chu_hoa; T: Tuoi; Theo khai báo này thì ch là biến kiểu đoạn con, có thể nhận các gía trị là các ký tự từ ‘A’ đến ‘Z’, tương tự, biến T có thể nhận các gía trị là các số nguyên từ đến 200 Cũng có thể khai báo hai biến Ch và T trực cách sau: (69) Var Ch : ‘A’ ’Z’; T : 200; Trong nhiều trường hợp, việc khai báo đoạn có tác dụng tiết kiệm nhớ Tùy theo phạm vi hằng1 hằng2 mà Turbo Pascal cấp phát cho biến số byte tối thiểu Trong ví dụ trên, biến Ch hay T chứa byte Kiểu đoạn còn cho phép kiểm soát gía trị biến có vượt ngoài phạm vi nó hay không Ví dụ, biến T mà gán: T:=201; thì máy báo lỗi "const out of range" Ngoài chạy chương trình mode {$R+}, chương trình dừng biến nhận gía trị vượt khỏi phạm vi Kiểu liệt kê và kiểu đoạn thuộc loại đơn giản và đếm (70) 7.5 CÂU HỎI TRẮC NGHIỆM Câu 1:Cho x, y, z là các biến kiểu thực, lệnh nào là sai: a) x:=y+z; b) Readln(x, y, z); c) x+y:=z; d) Writeln(x+y, z:0:2); Câu 2: Cho x, y là các biến kiểu thực, lệnh nào là đúng : a) Readln(x,5); b) Readln(‘x= ‘, x); c) Readln(x:5:2); d)Readln(x, y); Câu 3: Cho x là biến kiểu thực, sau thực hai lệnh : x:=10 ; Writeln(x); Kết qủa in lên màn hình là : a) 10; b) 10.00; c) 1.0000000000E+01; d)+1.0000000000E+01; Câu 4: Cho biến X kiểu thực và gán X:= 12.41 ; Ðể in lên màn hình sau: X= 12.41 chọn lệnh nào : a)Writeln(X); b) writeln(X:5); c) writeln('X= ', X:5:2); d) writeln(' X=, X:5:2 ' ); Câu 5: Kiểu liệu biểu thức div + / + Ord(‘A’) là : a) nguyên; b) lô gic; c) ký tự ; d) thực; (71) Câu 6: Khai báo kiểu liệt kê sau là sai : Type Mau = (XANH, do, tim, Vang) ; vì : a) Tên trùng với từ khóa; b) Tên XANH viết chữ hoa; c)Tên Vang có chữ V hoa ; d)Tên tim viết chữ thường; Câu 7: Khai báo nào đúng : a) Var x, y = Integer; b) Var x, y of Integer; c) Var x, y := Integer ; d)Var x, y : Integer ; Câu 8: Cho khai báo : Var Ho, ten : String[15]; Lệnh nào sai : a) Write(' Ho ten la : ' ; Ho ; Ten); b) Write(' Ho ten la : ' + Ho + Ten); c) Write(' Ho ten la : ', Ho , Ten) ; d) Write(' Ho ten la : ', Ho + Ten) ; Câu 9: Cho i, j, k là ba biến nguyên, để nhập liệu cho lệnh: Readln( i, j, k) ; cách nhập nào sai : a) ; b) 3,4,5 ; c)    ; d)Câu a), b), c) đúng ; Câu 10: Cho i, j, k là ba biến nguyên, để nhập liệu cho lệnh: Readln( i, j, k) ; cách nhập nào đúng : a) ; b) 3,4,5 ; c) 3  4+1 ; d)3   E  ; Bài Câu lệnh rẽ nhánh YÊU CẦU CỦA BÀI GIẢNG (72) Nắm được: Cú pháp, ý nghĩa và cách sử dụng lệnh If Cú pháp, ý nghĩa và cách sử dụng lệnh Case Các ví dụ mẫu lệnh If và lệnh Case Sự khác lệnh If và lệnh Case 8.1 CÂU LỆNH IF 8.1.1 Câu lệnh IF dạng 1: 8.1.1.1 Cú pháp, lưu đồ và ý nghĩa: Cú pháp : IF Ðiềukiện THEN LệnhP ; Ðiềukiện là biểu thức lôgic cho kết qủa TRUE (đúng) hay FALSE (sai) LệnhP có thể là lệnh đơn giản lệnh có cấu trúc Nếu LệnhP là lệnh ghép, tức là gồm nhiều lệnh, thì nhớ là các lệnh này phải đặt khối: begin và end Ý nghĩa: Tùy theo Ðiềukiện là đúng hay sai mà định có làm LệnhP hay không Nếu Ðiềukiện là đúng thì làm LệnhP chuyển sang lệnh phía Nếu Ðiềukiện là sai thì không làm LệnhP mà chuyển sang lệnh Sơ đồ?cú pháp lệnh IF vẽ hình 8.1 8.1.1.2 Các ví dụ : Ví dụ 8.1: Nhập vào hai số a và b, tìm và in lên màn hình số lớn hai số đó Ta dùng biến phụ đặt tên là Max để chứa gía trị lớn phải tìm Thuật toán gồm hai bước: Bước 1: Gán số thứ vào Max, tức là: (73) Max:=a; Bước 2: Kiểm tra Max nhỏ số thứ hai thì gán số thứ hai vào Max: If Max < b then Max:=b; Bước 3: In gía trị Max lên màn hình Giải thích: Sau bước 1, biến Max có gía trị a Sang bước 2, có thể xảy hai tình : * Hoặc là Max < b , tức b là số lớn nhất, đó gía trị lớn b gởi vào biến Max * Hoặc là Max >= b, tức gía trị Max là lớn nên không phải làm gì Chương trình cụ thể sau: PROGRAM VIDU81; { Tim Max hai so } Var a, b, max : Real; Begin Write(‘ Nhap a va b :’); Readln(a,b); Max :=a ; If Max < b then Max:=b ; Writeln(‘ So lon nhat la: ‘ , Max:6:2); Readln; End Nhận xét: Việc tìm số nhỏ hai số a, b tương tự, ta dùng biến phụ Min chứa gía trị nhỏ nhất, và thực các lệnh sau: Min:=a; If Min > b then Min:=b; Có thể mở rộng thuật toán trên để tìm số lớn ba số nhiều Ðầu tiên ta tìm số lớn hai số a và b, ký hiệu là Max, sau đó tìm số lớn hai số Max và c, ký hiệu là Max Dưới đây là các lệnh chính để tìm số lớn ba số a, b, c : (74) Max:=a; If Max < b then Max:=b; { Max là số lớn a và b } If Max < c then Max:=c; { Max là số lớn a, b và c } Ví dụ 8.2: Nhập vào họ tên và điểm trung bình (DTB) sinh viên Hãy phân loại sinh viên theo DTB sau: Loại là Kém DTB<5, là Tbình  DTB<7, là Khá  DTB<9, là Giỏi DTB  In họ tên, điểm trung bình và phân loại sinh viên Trong chương trình, ta dùng biến phụ đặt tên là Loai để lưu trữ phân loại sinh viên Vì có năm loại cầ? lưu trữ là các chuỗi ‘Kem’, ‘Tbinh’, ‘Kha’, ‘Gioi’, nên biến Loai phải có kiểu liệu là kiểu chuỗi PROGRAM VIDU82; { Phân loại sinh viên } Var Ho_ten: String[18]; DTB: Real; Loai: String[6]; Begin Write(‘ Nhap ho va ten :’); Readln(Ho_ten); Write(‘ Nhap điem trung binh :’); Readln(DTB); { phân loại theo DTB } If DTB< then Loai:=‘Kem’; If (DTB>= 5) and (DTB<7) then Loai:=‘Tbinh’; If (DTB >= 7) and (DTB< 9) then Loai:=‘Kha’; (75) If DTB >= then Loai:=‘Gioi’; Writeln(Ho_ten, #32 , DTB:4:1 , #32 , Loai); { #32 là ký tự trắng } Readln; End Ví dụ 8.3: Nhập vào ba hệ số A, B, C, (A  0) giải và biện luận phương trình bậc hai: Ax2 + Bx + C = Việc đầu tiên là phải tính Delta : Delta = B2 - 4AC Sau đó biện luận theo Delta: Nếu Delta<0 : phương trình vô nghiệm Nếu Delta=0 : phương trình có nghiệm kép : Nếu Delta > 0: phương trình có hai nghiệm : Chương trình cụ thể sau: PROGRAM VIDU83; { Giải phương trình bậc } Var A, B, C, Delta, X1, X2 : Real; Begin Repeat Write( ‘ Nhap he so A khac khong :’); Readln(A); Until A<>0; Write( ‘ Nhap cac he so B, C: ‘); (76) Readln(B, C); Delta:=B*B - 4*A* C; If Delta < then Writeln( ‘ Ptrinh vô nghiệm! ‘); If Delta = then begin X1:=-B/(2*A); Writeln(‘ Có ng kép X1=X2= ‘ , X1:8:2); end; If Delta > then begin X1 := (-B+ Sqrt(Delta) ) / (2*A); X2 := (-B - Sqrt(Delta) ) / (2*A); Writeln(‘ Có hai nghiệm : ’); Writeln(‘X1= ‘ , X1:8:2); Writeln(‘X2= ‘ , X2:8:2); end; Readln; End Trong chương trình có ba lệnh IF xét riêng trường hợp Delta âm, không dương Chú ý Delta=0 thì phải làm hai lệnh: X1:=-B/(2*A); Writeln(‘ Có ng kép X1=X2= ‘ , X1:8:2); nên hai lệnh này phải đặt hai từ khóa begin và end để tạo thành câu lệnh ghép Tương tự, Delta>0 thì phải làm năm lệnh, và đó năm lệnh phải để khối begin và end Chương trình có sử dụng lệnh Repeat Until (sẽ trình bày phần sau) để buộc người dùng phải nhập hệ số A 0, nhập A=0 thì phải nhập lại A cho làm tiếp các lệnh phía (77) 8.1.2 Câu lệnh IF dạng 2: Cú pháp : IF Ðiềukiện THEN LệnhP ELSE LệnhQ ; Chú ý : Trước từ khóa ELSE không có dấu chấm phẩy LệnhP và LệnhQ có thể là lệnh ghép, tức là gồm nhiều lệnh đặt khối begin và end Ý nghĩa lệnh: Tùy theo Ðiềukiện là đúng hay sai mà định làm hai lệnh: LệnhP LệnhQ Nếu Ðiềukiện là đúng thì làm LệnhP, không làm LệnhQ, mà chuyển sang thực lệnh sau LệnhQ Ngược lại, Ðiềukiện là sai thì không làm LệnhP mà làm LệnhQ chuyển sang lệnh sau LệnhQ Ví dụ 8.4: Ðể tìm số lớn hai số a và b, dùng lệnh: If a<b then Max:=b else Max:=a; Chương trình đây nhập vào hai số a và b, tìm và in số nhỏ và số lớn chúng: PROGRAM VIDU84; { Tim so lon nhat va so nho nhat hai so } (78) Var a, b, Max, Min : Real; Begin Write(‘ Nhap a va b :’); Readln(a,b); If a < b then begin Max:= b; Min:= a; end else { trước else không có dấu ; } begin Max:= a; Min:= b; end; Writeln(‘ So lon nhat la: ‘ , Max:6:2); Writeln(‘ So nho nhat la: ‘ , Min:6:2); Readln; End 8.1.3 Câu lệnh IF lồng : Trong câu lệnh IF, LệnhP LệnhQ, hai, lại là câu lệnh IF thì ta có cấu trúc IF lồng Chẳng hạn đây là hai câu lệnh IF ELSE lồng : IF Ðiềukiện1 THEN If Ðiềukiện2 then LệnhP else LệnhQ ELSE (79) LệnhR ; Ví dụ 8.5: Nhập vào họ tên chủ hộ, số điện kế tháng trước (chiso1) và số điện kế tháng này (chiso2), tính tiền điện tháng này cho hộ, biết : Mỗi kw 60 kw đầu tiên có đơn gía là 5đ, Từ kw thứ 61 đến kw thứ 160 có đơn giá 8đ, Từ kw thứ 161 trở lên có đơn gía 10đ Ví dụ, ông A có số điện tháng trước là chiso1=1020 và số điện tháng này là chiso2=1070, lượng điện tiêu thụ tính là Ldtt= 1070-1020=50, lượng điện tiêu thụ < 60 nên số tiền là: Tien = 50*5= 250đ Nếu chiso2=1150 thì Ldtt = 1150-1020=130, lượng điện tiêu thụ vượt qúa 60 kw chưa vượt qúa 160 kw nên tiền điện tính là: Tien=60*5 + (130-60) *8 = 860 đ Nếu chiso2=1234, thì Ldtt = 1234-1020= 214, lượng điện tiêu thụ vượt qúa 160 kw nên tiền điện là: Tien=60*5 + 100*8 + (214-160)*10= 300+800+54*10= 1640 đ Chương trình viết sau: PROGRAM VIDU85; { Tính tiền điện } Var Ho_ten: String[18]; chiso1, chiso2, Ldtt, Tien : Real; Begin Write(‘ Nhap ho va ten :’); Readln(Ho_ten); Write(‘ Nhap số tháng trước, số tháng này: ‘); Readln( chiso1, chiso2); Ldtt:=chiso2- chiso1; If Ldtt<= 60 then Tien:=Ldtt*5 (80) else if Ldtt <=160 then Tien:=60*5+(Ldtt - 60)*8 else Tien:=60*5 + 100*8 + (Ldtt - 160) * 10; Writeln(‘ Họ và tên là ‘, Ho_ten); Writeln(‘ Tiền phải trả là ‘ , Tien:10:2); Readln; End Ví dụ 8.6: Nhập số thực x bất kỳ, tính : Trong Turbo Pascal không có hàm tính bậc ba x Ðể tính Exp(x) và Ln(x) Áp dụng công thức toán học: x = elnx với x>0, ta có: Vậy : Chương trình sau: PROGRAM VIDU86; { Tinh can bac ba cua x } Var x, y : Real; Begin Write(‘ Nhap x :’); ta phải dùng hai hàm (81) Readln(x); { tinh y } If x= then y:=0 else If x> then y:=Exp( 1/3*ln(x) ) else y:= - Exp( 1/3*ln(-x) ); Writeln(‘ gia tri y= ‘ , y:8:4); Readln; End Ví dụ 8.7: Nhập tên ba sinh viên, in các tên đó lên màn hình theo thứ tự đã xếp theo vần A, B, C, Ví dụ, nhập ba tên là MAI, TUAN, BINH, thì in là BINH, MAI, TUAN PROGRAM VIDU87; { Sắp xếp ba tên} Var T1, T2, T3 : String[8]; Begin Write( ‘Nhập tên thứ nhất: ‘); Readln(T1); Write( ‘Nhập tên thứ hai: ‘); Readln(T2); Write( ‘Nhập tên thứ ba: ‘); Readln(T3); Writeln(‘ Các tên thứ tự là:’); IF T1<T2 THEN If T2<T3 then writeln(T1, #32 , T2, #32 , T3) Else { tức T3 <= T2 } if T1<T3 then writeln(T1, #32 , T3, #32, T2) else { tức T3 <= T1 } writeln(T3, #32, T1, #32, T2) ELSE { tức là T2<= T1} If T1<T3 then writeln(T2, #32, T1, #32, T3) (82) Else { tức là T3<= T1} if T2<T3 then writeln(T2, #32, T3, #32, T1) else { tức là T3<= T2 } writeln(T3, #32, T2, #32, T1); Readln; End Lệnh IF chương trình trên lồng nhiều cấp nên phức tạp Khi học cấu trúc mảng ta giải bài toán này gọn Chú y?/strong>: Trong câu lệnh IF lồng nhau, cách xác định từ khóa ELSE nào với từ khóa IF nào là sau: xét ngược từ lên, ELSE luôn với IF gần phía trên nó mà chưa có ELSE để bắt cặp 8.2 CÂU LỆNH CASE 8.2.1 Cú pháp, lưu đồ và ý nghĩa : Trong số trường hợp, phải lựa chọn việc nhiều việc thì các cấu trúc IF lồng tỏ rắc rối, khó viết, khó kiểm tra tính đúng đắn nó Việc dùng cấu trúc CASE có thể khắc phục nhược điểm này Lệnh CASE có hai dạng, chúng khác điểm là dạng có ELSE LệnhQ, còn dạng thì không ( hình 8.3) CASE biểuthức OF CASE biểuthức OF hằng1 : LệnhP1; hằng1 : LệnhP1; hằng2 : LệnhP2; hằng2 : LệnhP2; hằngk : LệnhPk; hằngk : LệnhPk; END; ELSE LệnhQ; END; Dạng Dạng Hình 8.3 : Cú pháp lệnh Case Chú ý là lệnh CASE phải kết thúc END; Các yêu cầu: Kiểu liệu biểuthức có thể là nguyên, ký tự, Lôgic, kiểu liệt kê hay kiểu đoạn Xin nhấn mạnh rằng: biểuthức không là kiểu thực hay kiểu chuỗi, và đây chính là hạn chế lệnh CASE so với lệnh IF (83) Các hằng1, hằng2, , hằngk phải có kiểu liệu phù hợp với kiểu liệu biểuthức Ý nghĩa: Tùy theo gía trị biểuthức nào các hằng1, hằng2, , hằngk mà định thực lệnh nào các lệnhP1, lệnhP2, , LệnhPk Cách thức thực lệnh CASE sau: Bước 1: Tính toán gía trị biểuthức Bước 2: So sánh và lựa chọn: Nếu gía trị biểuthức = hằng1 thì thực LệnhP1, chuyển sang lệnh sau End, ngược lại: Nếu gía trị biểuthức = hằng2 thì thực LệnhP2, chuyển sang lệnh sau End, ngược lại: v.v Nếu gía trị biểuthức = hằngk thì thực LệnhPk, chuyển sang lệnh sau End, ngược lại : a) chuyển sang lệnh sau End ( là dạng 1) b) thực LệnhQ, chuyển sang lệnh sau End (nếu là dạng 2) Hình 8.4 và hình 8.5 là các sơ đồ lệnh CASE vẽ cho trường hợp k=3 Trong hình vẽ , ta ký hiệu: G là gía trị biểuthức H1, H2, H3 là hằng1, hằng2, hằng3 P1, P2, P3, Q là LệnhP1, LệnhP2 , LệnhP3 va?LệnhQ (84) 8.2.2 Các ví dụ : Ví dụ 8.8: Nhập vào họ tên và năm sinh người, cho biết người này thuộc lứa tuổi nào: sơ sinh, nhi đồng, thiếu niên, niên, trung niên hay người lớn tuổi, biết rằng: Sơ sinh có tuổi từ đến Nhi đồng : có tuổi từ đến Thiếu niên có tuổi từ 10 đến 15 Thanh niên có tuổi từ 16 đến 32 Trung niên có tuổi từ 33 đến 50 Người lớn tuổi có tuổi trên 50 (85) Chương trình viết sau: PROGRAM VIDU88; Var Ho_ten: String[20]; Namsinh, Namnay, Tuoi : Integer ; Phanloai : String[14]; Begin Write(‘ Nhập họ và tên: ‘); Readln(Ho_ten); Write(‘ Nhập năm sinh và năm : ‘); Readln(Namsinh, Namnay); Tuoi:=Namnay - Namsinh; If Tuoi< then writeln( ‘Nhập sai ‘) else begin Case Tuoi OF ,1 : Phanloai:= ‘sơ sinh’; : Phanloai:= ‘nhi đong’; 10 15 : Phanloai:= ‘thieu niên’; 16 32 : Phanloai:= ‘thanh nien’; 33 50 : Phanloai:= ‘trung nien’; else Phanloai:= ‘nguoi lon tuoi’; End; { hết Case } Writeln(Ho_ten, #32 , Tuoi, #32 , Phanloai); end; Readln; (86) End Trong ví dụ này, lệnh CASE dựa vào Tuổi để xác định lứa tuổi, kết qủa lưu vào biến Phanloai Ðóng vai trò hằng1 là hai số và viết cách dấu phẩy, và dòng : 0,1: Phanloai:=‘So sinh’ ; có nghĩa là Tuổi thì thực lệnh gán: Phanloai:=‘So sinh’ ; Ðóng vai trò hằng2 là tất các số nguyên phạm vi từ đến 9, và dòng : : Phanloai:= ‘nhi đong’; có nghĩa là Tuổi các số nguyên từ đến thì thực lệnh gán: Phanloai:= ‘nhi đong’; Ví dụ 8.9: Xây dựng thực đơn cho phép lựa chọn bốn việc : tính tổng , tính hiệu, tính tích tính thương hai số x, y nhập từ bàn phím Màn hình cần bốn mục sau cho người lựa chọn : A TÍNH TỔNG HAI SỐ B TÍNH HIỆU HAI SỐ C TÍNH TÍCH HAI SỐ D TÍNH THƯƠNG HAI SỐ Muốn chọn mục nào ta gõ chữ cái đầu mục đó Ví dụ gõ A thì màn hình kết qủa x+y, gõ B thì kết qủa x-y, Ðối với mục D, y khác không thì in kết qủa x/y, còn y=0 thì in câu " Không xác định" Nếu người dùng nhập ký tự khác A, B, C, D, a, b, c, d thì máy lời nhắc : " Không có mục này " Biến Ch kiểu ký tự dùng để lưu chữ cái (mục) mà người dùng đã chọn Tùy theo giá trị Ch mà lệnh CASE định phải làm gì Chương trình viết sau : PROGRAM VIDU89; { Thực đơn } Uses Crt; Var (87) x, y : Real; Ch : Char; Begin Clrscr; Write('Nhap x va y:'); Readln(x, y); Gotoxy(10, 3); Write('A TINH TONG HAI SO'); Gotoxy(10, 5); Write('B TINH HIEU HAI SO'); Gotoxy(10, 7); Write('C TINH TICH HAI SO'); Gotoxy(10, 9); Write('D TINH THUONG HAI SO'); Gotoxy(2,11); Write('-Ban chon muc nao (A, B, C, D) ?:'); Readln(Ch); CASE Ch of 'A', 'a': Writeln('Tong =', x+y :6:2); 'B', 'b': Writeln(' Hieu =', x-y :6:2); 'C', 'c': Writeln(' Tich =', x*y :6:2); 'D', 'd': If y<>0 then Writeln(' Thuong =', x/y:6:2 ) else Writeln(' Khong xac dinh !'); ELSE Writeln(' Khong co muc ', Ch); END; Readln; End Trong chương trình có sử dụng thủ tục : GOTOXY ( m, n) thuộc thư viện CRT, có chức đặt trỏ màn hình vào tọa độ cột thứ m, dòng thứ n trên màn hình Ví dụ lệnh Gotoxy (10, 3); đặt trỏ màn hình vào tọa độ cột 10, dòng Ví dụ 8.10: (88) Nhập vào tháng và năm, cho biết tháng đó năm đó có bao nhiêu ngày Theo dương lịch : Các tháng 4, 6, 9, và 11: có 30 ngày, Các tháng 1, 3, 5, 7, 8, 10 và 12: có 31 ngày, Riêng tháng thì bình thường có 28 ngày, là năm nhuận thì có 29 ngày Cách xác định năm là nhuận sau: * là năm chia hết cho 400 (ví dụ năm 1600, năm 2000) * là năm không chia hết cho 100 và chia hết cho ( ví dụ các năm 1988, 1992, 1996 là năm nhuận) Trong chương trình ta dùng biến lôgic có tên là Nhuan để xác định có phải là năm nhuận hay không PROGRAM VIDU810; { Xác định số ngày tháng } Var Thang, Nam, Songay : Integer ; Nhuan : Boolean; Begin Write(‘Nhập Thang, Nam : ‘); Readln(Thang, Nam); If (Thang<1) or ( Thang>12) then writeln(‘ Nhập sai ’) else begin Case Thang OF 4, 6, 9, 11 : Songay:=30; 1, 3, 5, 7, 8, 10, 12 : Songay:=31; : begin Nhuan:= (Nam mod 400=0) or ( (Nam mod 100<>0) and (Nam mod 4=0) ); (89) If Nhuan= TRUE then Songay:=29 else Songay:=28; end; End; { Hết Case } Writeln(‘ Số ngày là : ‘ , Songay); end; Readln; End Trong ví dụ này, Tháng=2 thì phải làm hai lệnh đặt khối begin và end, đó chính là lệnh ghép: begin Nhuan:= (Nam mod 400=0) or ( (Nam mod 100<>0) and (Nam mod 4=0) ); If Nhuan= TRUE then Songay:=29 else Songay:=28; end; 8.2.3 Câu lệnh CASE lồng : Trong cấu trúc CASE, các LệnhP1, LệnhP2, , LệnhPk hay LệnhQ lại là lệnh CASE thì ta có cấu trúc CASE lồng Ví dụ 8.11: Một xí nghiệp tính tiền thưởng hàng tháng cho công nhân theo công thức : Tiền thưởng= Hệ số * 200 Trong đó Hệ số tính dựa vào kết qủa bình chọn phân loại lao động (loại A, B hay C) và nơi làm việc (cơ sở hay sở 2) người tháng, cụ thể sau : Loại Cơ sở Cơ sở A 2.0 2.5 B 1.5 1.8 C 1.0 1.0 Ví dụ ông X xếp loại A và làm việc sở thì có hệ số thưởng là 2.0, nên tiền thưởng là =2.0*200=400 (90) Viết chương trình nhập họ tên, phân loại lao động và nơi làm việc công nhân, tính tiền thưởng cho người đó PROGRAM VIDU811; { Tính tiền thưởng cho công nhân } Var Ho_ten: String[20]; Loai : Char; Coso : Byte; Heso, Thuong : Real; Begin Write(‘ Nhập họ và tên: ‘); Readln(Ho_ten); Write(‘ Nhập sở làm việc (1,2): ‘); Readln(Coso); Write(‘ Nhập phân loại lao động (A,B,C) : ‘); Readln(Loai); CASE Loai OF ‘A’, ‘a’: Case Coso of 1: Heso:=2.0; 2: Heso:=2.5; end; ‘B’, ‘b’: Case Coso of 1: Heso:=1.5; 2: Heso:=1.8; end; ‘C’, ‘c’: Heso:=1.0; END; { Hết CASE } (91) Thuong:=Heso*200; Writeln(‘Họ và tên Tiền thưởng ‘); Writeln(Ho_ten , Thuong:8:2 ); Readln; End 8.2.4 So sánh lệnh Case với lệnh If : Lệnh If và lệnh Case là các câu lệnh rẽ nhánh, cho phép lựa chọn công việc nhiều công việc lựa chọn Nhưng cấu trúc If tổng quát và mạnh cấu trúc Case vì lệnh If không hạn chế gì cả, còn lệnh Case thì yêu cầu biểu thức và các phải thuộc kiểu liệu đếm được: nguyên, ký tự, lô gic, liệt kê hay đoạn con, không là kiểu thực hay chuỗi Lệnh Case nào có thể thay tương đương các lệnh IF Ví dụ lệnh Case chương trình nói trên ( Ví dụ 8.11 ) có thể thay ba lệnh If sau: If (Loai=‘A’) or (Loai=‘a’) then if Coso=1 then Heso:=2.0 else Heso:=2.5; If (Loai=‘B’) or (Loai=‘b’) then if Coso=1 then Heso:=1.5 else Heso:=1.8; If (Loai=‘C’) or (Loai=‘c’) then Heso:=1.0; Tuy nhiên không phải lệnh If nào thay lệnh Case Việc sử dụng lệnh Case nhiều trường hợp có tác dụng làm rõ ràng và bật bố cục đoạn chương trình, từ đó dễ đọc, dễ hiểu Thông thường, người ta dùng lệnh Case để thay các cấu trúc If lồng có nhiều ( ba, bốn, ) tình rẽ nhánh và điều kiện cho phép Các bạn hãy viết lại các chương trình các ví dụ 8.8, 8.9, 8.10, 8.11 thay lệnh Case các lệnh IF (92) 8.3 CÂU HỎI TRẮC NGHIỆM Câu 1: Lệnh nào sau đây in màn hình số lớn A và B : a) If A > B then write(B) else write(A); b) If A > B then write(A) else write(B); c) If A > B then Readln(A) else Readln(B); d) If A < B then writeln(A) else writeln(B); Câu 2: Cho N là biến kiểu nguyên, chọn câu đúng cú pháp : a) If N < 10 then write (' Nho hon 10 ') ; else write (' Lon hon 10 '); b) If N < 10 Write (' Nho hon 10 ') else then write (' Lon hon 10 '); c) If N < 10 then write (' Nho hon 10 ') else write (' Lon hon 10 '); d) If N < 10 then N := 10 else N > 20 then write (' N > 20 '); Câu 3: Kiểm tra ba số a, b, c lớn thì in số 1, chọn lệnh nào : a) if (a > 1) and ( b > 1) and ( c > 1) then write(1); b) if (a > 1) or (b > 1) or (c > 1) then write(1); c) if a > and b > and c > then write(1); d) if a, b , c > then write(1); Câu 4: Cho i là biến nguyên Sau thực các lệnh : i:=2; Case i of 1: i:=i+1; 2: i:=i+2; 3: i:=i+3; end; Gía trị sau cùng i là : a) b) (93) c) d) Câu 5: Cho N là biến nguyên, sau thực các lệnh: N:= 9; If N< then writeln(‘ So am‘) else Case N mod of 0: Writeln(‘ Chan’); 1: Writeln(‘ Le ‘); end; Kết qủa in lên màn hình là: a) Chan b) Le c) So am d) không in gì Câu 6: Cho hàm số: Nhóm lệnh nào tính đúng y : a) if x > then y:=x ; if x > -1 then y:=Sin(x) else y:= 2*x+1; b) if x <= -1 then y:=2*x +1 else if x <=0 then y:=Sin(x) else y:=x; Câu 7: Giả sử i là biến nguyên, sau thực các lệnh : i:=5; Case i of (94) 1: i:=i+1; 2: i:=i+2; 3: i:=i+3; else i:=2*i; End; thì gía trị sau cùng i là : a) 10 b) c) d) Câu 8: Cho ch biến ký tự, i biến nguyên, sau thực các lệnh: i:= -15; ch:='E'; Case i of 14 : ch:='D'; 15 20: ch:='C'; 21 24: ch:='B'; else ch:='A'; End; thì gía trị sau cùng ch là : a) 'A' b) 'B' c) 'C' d) 'E' Câu 9: Cho ch biến ký tự, i biến nguyên Ðể gán trị cho biến ch, thì lệnh : Case i of (95) 0,1,2 : ch:='A'; : ch:='B'; else ch:='C'; end; tương đương với nhóm lệnh nào : a) If i<0 then ch:=’C’ b) if (i >= 0) and (i<= 2) then ch:='A'; else if i<=2 then ch:=’A’ else if i<=8 then ch:=’B’ else ch:=’C’ ; Câu 10: Khi chạy chương trình : Var S, i : Integer; Begin i := 3; S:= 40; if ( i > ) then S:= * + ( - i ) * else if ( i > ) then S:= * i else S:= 0; End Giá trị sau cùng S là : a) b) 19 c) 40 d) 15 if (i>=3) and (i<=8) then ch:='B' else ch:='C'; (96) Bài Câu lệnh lặp YÊU CẦU CỦA BÀI GIẢNG Nắm được: Cú pháp, ý nghĩa và cách thức hoạt động các lệnh lặp Các ví dụ các lệnh lặp Sự khác các lệnh For, While và Repeat 9.1 CÂU LỆNH LẶP FOR 9.1.1 Câu lệnh FOR dạng 1: 9.1.1.1 Cú pháp , lưu đồ, cách thức hoạt động : Cú pháp: FOR biến := m1 TO m2 DO LệnhP; Yêu cầu: biến phải thuộc kiểu liệu đơn giản đếm được, thường là kiểu nguyên, ký tự hay lô gic, không thể là kiểu thực hay chuỗi m1, m2 là các biểu thức có cùng kiểu liệu với biến, LệnhP có thể là lệnh đơn giản, lệnh có cấu trúc, là lệnh ghép gồm nhiều lệnh đặt khối begin và end Hình 9.1 là sơ đồ khối lệnh For với b là viết tắt biến Cách thức hoạt động FOR: Bước 1: Gán giá trị biến := m1; Bước 2: Nếu biến  m2 thì làm LệnhP, sang bước 3; Nếu biến >m2 thì không làm LệnhP mà chuyển sang lệnh phía Bước : Tăng gía trị biến : biến:=Succ(biến); Quay lại bước Tóm lại, LệnhP làm làm lại, bắt đầu biến=m1, và kết thúc biến =m2+1, thảy là m2-m1+1 lần Vì thế, người ta gọi FOR là vòng lặp có số lần lặp đã biết trước (97) 9.1.1.2 Các ví dụ : Ví dụ 9.1: Bài toán tính tổng : Hãy tính tổng : S= 12 + 22+ 32+ + 102 Thuật toán: Bước 0: gán S:=0; { gán gía trị ban đầ? cho S} Bước 1: gán S:=S+1*1; { S=12 } Bước 2: gán S:=S+2*2; { S=12+22} Bước 3: gán S:=S+3*3; { S=12+22+32} v.v Bước 10: gán S:=S+10*10; { S=12+22+32+ +102} Qúa trình từ bước đến bước 10 gọi là phép cộng dồn vào biến S Tại bước thứ i, lấy gía trị biến S cộng với i2, kết qủa lại gán cho biến S, đó gía trị biến S tăng thêm lượng bằ?g i2 Khi i thay đổi từ đến 10 thì các số 12, 22, 32, , 102 cộng vào S, kết qủa là sau bước thứ 10 gía trị S đúng tổng 12 + 22 + 32 + + 102 Tóm lại, lệnh: S:=S + i*i; làm thảy 10 lầ?, ứng với i=1, 2, , 10 Qúa trình này diễn đạt bằ?g lệ?h FOR, sau: For i:=1 To 10 DO S:=S+ i*i ; (98) Một cách tổng quát, để tính tổng :S= 12 + 22+ 32+ + N2 , đó N là số nguyên dương bất kỳ, ta dùng hai lệnh: S:=0; For i:=1 To N DO S:=S+ i*i ; Dưới đây là chương trình cụ thể : PROGRAM VIDU91; { Tính tổng các bình phương các số tự nhiên <=N} Var N, i : Integer; S : LongInt; Begin Write(‘ Nhập N :’); Readln(N); S:=0; For i:=1 to N S:=S+i*i ; Writeln(‘S= ‘, S); Readln; End Mở rộng bài toán tính tổng: Tính tổng đan dấu : S = 12 - 22 + 32 - 42 + +(-1)N-1 N2 Ta viết: S = 12 + (- 22 ) + 32 + (- 42 ) + +(-1)N-1 N2 Nhận thấy, số hạng thứ i vế phải có gía trị tuyệt đối i2 , mang dấu cộng i lẻ, mang dấu trừ i chẵn Nói cách khác, ta cộng dồn i2 vào S i lẻ, và cộng dồn (- i2 ) vào S i chẵn Việc xác định i lẻ hay chẵn dựa vào hàm Odd(i) hay kết qủa phép toán i Mod Vậy, các lệnh dùng là : S:=0; For i:=1 To N DO if i mod <> then S:=S+ i*i else S:= S- i*i ; (99) Các bạn hãy viết chương trình để tính tổng đan dấu này Ví dụ 9.2: Bài toán tính tích: Tính S= 10! Ta viết S=1*2*3* *10 Thuật toán: Bước 0: gán S:=1; { gán gía trị ban đầ? cho S} Bước 1: gán S:=S*1; { S=1 } Bước 2: gán S:=S*2; { S=1*2} Bước 3: gán S:=S*3; { S=1*2*3} v.v Bước 10: gán S:=S*10; { S=1*2*3* *10 =10!} Nếu ví dụ 1, ta phải cộng dồn vào biến S thì ví dụ này ta phải nhân dồn vào biến S Tại bước thứ i, lấy gía trị biến S nhân với i, lại gán kết qủa cho biến S Khi i thay đổi từ đến 10 thì S tích lũy đủ các thừa số 1, 2, 3, ,10, và gía trị S sau bước thứ 10 đúng 1*2*3* *10 =10! Qúa trình thực từ bước đến bước thứ 10 mô tả câu lệnh For : For i:=1 to 10 DO S:=S * i ; Một cách tổng quát, để tính tích: S= 1*2* *N , đó N là số nguyên dương bất kỳ, ta dùng hai lệnh: S:=1; For i:=1 To N DO S:=S* i ; Dưới đây là chương trình cụ thể : PROGRAM VIDU92; { Tính S=N! } Var N, i : Integer; S : LongInt; Begin (100) Write(‘Nhập số dương N : ‘); Readln(N); S:=1; For i:=1 to N S:=S * i ; Writeln(‘Giai thua = ‘, S); Readln; End Ví dụ 9.3: Bài toán tính lũy thừa: Nhập số tự nhiên N và số thực x bất kỳ, tính S= xN Tương tự tính N!: đầu tiên ta gán S:=1, sau đó bước lặp, ta nhân dồn x vào S lệnh S:=S*x Sau N bước vậy, S nhân với x đúng N lần Vậy hai lệnh cần dùng là: S:=1; For i:=1 TO N DO S:=S*x; Dưới đây là chương trình cụ thể : PROGRAM VIDU93; { Tính S=lũy thừa N x } Var N, i : Byte ; S, x : Real ; Begin Write(‘Nhập hai số x và N : ‘); Readln( x, N); S:=1; For i:= to N S := S * x ; Writeln(‘Luy thua= ‘, S : 6:2); (101) Readln; End Ví dụ 9.4: In bảng các chữ cái từ A đến Z thành bốn cột sau: KÝ TỰ A B MÃ 65 66 KÝ TỰ a 97 b 98 MÃ Yêu cầu in thành trang màn hình, trang 15 dòng Trong chương trình ta dùng biến Dem để đếm số dòng đã in, in xong dòng thì biến Dem cộng thêm Khi Dem = 15, 30, 45, (tức Dem mod 15=0) thì phải làm lệnh Readln; lệnh này dừng màn hình ta gõ Enter in tiếp PROGRAM VIDU94; { In bảng các chữ cái} Uses Crt; Var ch, ch1 : Char; Dem: Integer; Begin CLRSCR; Writeln(‘ KY TU MA KY TU MA’); Dem:=0; For ch:=‘a’ to ‘z’ begin ch1:=Upcase(ch); Writeln( ch1 :3 , Ord(ch1) :6 , ch :6 , Ord(ch) :6 ); Inc(Dem); If Dem mod 15 = then begin (102) Write(‘ Enter để xem tiếp ‘); Readln; end; end; Writeln(‘ HET ‘); Readln; End Chương trình trên là ví dụ cách dùng biến chạy kiểu ký tự (ch) lệnh FOR, ngoài ra, đóng vai trò LệnhP là lệnh ghép, gồm nhiều lệnh đặt khối begin và end 9.1.2 Câu lệnh FOR dạng 2: Cú pháp: FOR biến := m2 DOWNTO m1 DO LệnhP; Cách thức hoạt động FOR dạng 2: Bước 1: gán gía trị biến := m2; Bước 2: Nếu biến  m1 thì làm LệnhP, sang bước Nếu biến<m1 thì không làm LệnhP mà chuyển sang lệnh phía Bước : Giảm gía trị biến : biến:=Pred(biến); Quay lại bước Tóm lại, LệnhP làm làm lại, bắt đầu biến=m2, và kết thúc biến = m1-1, thảy là m2-m1+1 lần (103) Ví dụ 9.5: Ðể tính S= N!, ta có thể viết : S=N*(N-1)*(N-2)* *2*1 Cách viết cho thấy cách tính: đầu tiên gán S:=1, sau đó thực việc nhân dồn S:=S* i với i= N, N-1, , 2, Tức là: S:=1; For i:=N downto S:=S* i; Tương tự , để tính S=xN , ta có thể dùng FOR dạng : S:=1; For i:=N downto S:=S* x; Như vậy, lệnh FOR dạng chất là cách viết khác dạng Thông thường người ta hay dùng lệnh FOR dạng 1, nhiên có khá nhiều tình mà việc dùng lệnh FOR dạng tỏ hiệu qủa, ví dụ sau đây: Ví dụ 9.6 : In các chữ cái theo thứ tự ngược từ Z đến A thành hai dòng : Z, Y, X, , C, B, A z, y, x, , c, b, a Chương trình viết sau: PROGRAM VIDU96; { In các chữ cái theo thứ tự đảo ngược từ z đến a} (104) Var Ch: Char; Begin For ch:=‘Z’ downto ‘A’ write(ch:3 ); Writeln; For ch:=‘z’ downto ‘a’ write(ch :3 ); Writeln; Readln; End 9.1.3 Câu lệnh FOR lồng : Trong cấu trúc FOR, LệnhP là lệnh FOR thì ta có cấu trúc FOR lồng nhau: FOR biến1:= m1 TO m2 DO {1} FOR biến2:=n1 TO n2 DO LệnhP; {2} Cách thức hoạt động lệnh này sau: Ðầu tiên cho biến1:=m1 và làm lệnh dòng {2} Vì dòng {2} là lệnh FOR nên với gía trị biến2=n1, , n2, phải làm LệnhP, kết qủa là LệnhP làm n2-n1+1 lần Bây tăng: biến1:=Succ(biến1), lại làm lệnh FOR dòng {2}, kết qủa lệnhP làm thêm n2-n1+1 lần .v.v Qúa trình trên tiếp tục biến1=m2+1 thì dừng Lệnh FOR {1} làm m2-m1+1 lần lệnh FOR {2}, còn chính lệnh FOR {2} lại làm n2-n1+1 lần LệnhP Vì lệnhP làm thảy là (m2-m1+1)*(n2-n1+1) lần Ví dụ 9.7: In hình chữ nhật đặc đây: (105) Ta thấy dòng gồm m chữ A, tức là chữ A in liên tiếp thảy m lần, việc này làm lệnh : For j:=1 to m write(‘A’); Lệnh Write in m chữ A trên dòng In xong, trỏ nằm cuối dòng đó, vì trước in dòng tiếp theo, cần phải đưa trỏ xuống dòng lệnh: Writeln; Tóm lại, muốn in dòng thứ i, cần phải làm hai lệnh: For j:=1 to m write(‘A’); Writeln; Cả thảy ta phải in n dòng thế, tức là: For i:=1 to n In dòng i ; Thay In dòng i hai lệnh nói trên (đặt khối begin end) , ta có thuật toán để in hình chữ nhật đặc là: For i:=1 to n begin for j:=1 to m write(‘A’); Writeln; end; Các bạn hãy viết chương trình cụ thể cho ví dụ này, đây m và n là hai số nguyên dương nhập từ bàn phím 9.1.4 Các ứng dụng khác lệnh FOR : Lệnh For thông dụng, dễ dùng và giải nhiều bài toán khoa học kỹ thuật và thực tiễn Dưới đây xin nêu hai ứng dụng Ví dụ 9.8: Tìm các số Fibonaci Dãy số Fibonaci { 1, 1, 2, 3, 5, 8, 13, 21, } nhắc nhiều giới khoa học kỹ thuật, nó xây dựng sau: U0=1, U1=1 , Uk=Uk-1 + Uk-2 với k= 2, 3, 4, Gọi U là số hạng thứ k, Uo và U1 là hai số hạng đứng trước U Ðầu tiên ta gán: Uo:=1; (106) U1:=1; Bước 1: tính U:=Uo+U1 và in U Lúc này U=2 chính là U2 Ðể chuẩn bị tính U3, ta cho Uo đóng vai trò U1 và U1 đóng vai trò U, tức là gán: Uo:=U1; U1:=U; Kết qủa là Uo=1 và U1=2 Bước 2: tính U:=Uo+U1 và in U Lúc này U=3 chính là U3 Ðể chuẩn bị tính U4, ta lại cho Uo đóng vai trò U1 và U1 đóng vai trò U, tức là gán: Uo:=U1; U1:=U; Kết qủa là Uo=2 và U1=3 .v.v Tóm lại các lệnh phải lặp lặp lại là: U:=Uo+U1; Uo:=U1; U1:=U; Vì sang bước sau thì gía trị U bị thay đổi nên bước ta phải in U chương trình viết sau: PROGRAM VIDU98; { In N+1 số Fibonaci đầu tiên } Var N, i, U, Uo, U1 : Integer; Begin Write(‘ Nhập N :’); Readln(N); Uo:=1; (107) U1:=1; Writeln( N+1 , ‘ số Fibonaci đầu tiên là :’ ); Write(Uo:3 , U1:3); For i :=2 to N begin U:=Uo+U1; Write(U:3); Uo:=U1; U1:=U; end; Readln; End Ví dụ 9.9: Bài toán tính tiền lãi gửi ngân hàng: Nhập tiền vốn ban đầu, số tháng gửi N và lãi suất hàng tháng Tính số tiền nhận sau tháng gửi biết tiền lãi hàng tháng gộp vào tiền vốn Ví dụ, tiền vốn là100, lãi suất tháng là 2% Sau tháng gửi có số tiền là: Số tiền=100 + 100*0.02 = 102 Sau tháng gửi có số tiền là: Số tiền=102 + 102*0.02 = 104.04 Công thức tính tiền thu sau tháng gửi là: Số tiền := Tiền vốn + Tiền vốn * Lãi suất Số tiền này lại trở thành tiền vốn tháng sau, tức là: Tiền vốn := Số tiền; Qúa trình lặp lặp lại từ tháng đến tháng N Chương trình cụ thể sau: PROGRAM VIDU99; { Tính tiền gửi ngân hàng sau N tháng} (108) Var Tienvon, Laisuat, Sotien : Real; N, i : Byte; Begin Write(‘ Nhập tiền vốn, lãi suất và số tháng gửi : ‘); Readln(Tienvon, Laisuat, N); For i:=1 to N begin Sotien:= Tienvon + Tienvon*Laisuat; Writeln(‘Số tiền sau ‘, i , ‘ tháng =‘ , Sotien:8:2); Tienvon:=Sotien; end; Readln; End 9.2 CÂU LỆNH WHILE 9.2.1 Cú pháp, lưu đồ, cách thức hoạt động : Cú pháp: WHILE Ðiềukiện DO LệnhP ; Ý nghĩa : Chừng nào Ðiềukiện còn đúng thì làm LệnhP , Ðiềukiện sai thì không làm LệnhP mà chuyển sang lệnh phía Cách thức hoạt động WHILE: Bước 1: Nếu Ðiềukiện sai thì chuyển sang lệnh sau LệnhP, ngược lại, Ðiềukiện đúng thì làm LệnhP, quay lại bước (109) Lệnh P gọi là thân vòng lặp WHILE Nếu Ðiềukiện không sai thì LệnhP phải làm hoài, lúc đó ta có vòng lặp vô hạn Trong trường hợp này, để dừng chương trình, hãy gõ đồng thời hai phím Ctrl và Pause ( viết tắt là ^Pause) Ðể tránh các vòng lặp vô hạn, thân vòng WHILE cần có ít lệnh có tác dụng làm biến đổi các đại lượng tham gia Ðiềukiện để đến lúc nào đó thì Ðiềukiện sai và đó vòng lặp kết thúc 9.2.2 Các ví dụ lệnh While : Ví dụ 9.10 : Nhập số tự nhiên N, dùng lệnh WHILE tính S=N!: PROGRAM VIDU910; { Tinh S=N! lệnh WHILE } Var N, i : Integer; S : LongInt; Begin Write(‘ Nhập N > : ‘ ); Readln(N); S:=1; i :=1; {9} While i<= N begin (110) S:=S*i; i:=i+1; {13} end; Writeln(‘ Giai thua = ‘, S); Readln; End Chạy<VD910.EXE> Chép file nguồn <VD910.PAS> Khởi đầu biến i gán gía trị (dòng {9}) Trong vòng lặp WHILE, sau lệnh S:=S*i; biến i tăng lên đơn vị lệnh i:=i+1; (dòng {13}) Khi i=N+1 thì điều kiện i<=N bị sai và lúc đó vòng lặp kết thúc, kết qủa là lệnh S:=S*i; thực đúng N lầ? ứng với i=1, 2, 3, , N Trong chương trình trên, không có dòng lệnh {13}: i:=i+1; thì i luôn luôn nên điều kiện i<=N luôn luôn đúng (vì N  1), và đó vòng lặp vô hạn Sự khác lệnh WHILE so với FOR là chỗ: lệnh FOR, biến i tự động gán gía trị ban đầu và sau bước lặp tự động tăng lên, còn WHILE thì không, ta phải viết các lệnh đó Tất các bài toán giải lệnh FOR thì giải lệnh WHILE Ðặc điểm chung các bài toán dạng này là số lần lặp các vòng lặp đã biết trước Lệnh WHILE đặc biệt thích hợp với các vòng lặp có số lần lặp chưa biết trước, lệnh FOR không giải Ðây chính là điểm mạnh lệnh WHILE Hãy xem ví dụ sau Ví dụ 9.11: Trở lại bài toán tính tiền gửi ngân hàng có tiền lãi hàng tháng gộp vào vốn (ví dụ 9.9) Câu hỏi bây là: cần gửi tối thiểu là bao nhiêu tháng để có số tiền  S cho trước Giả sử tiền vốn là 100, lãi suất hàng tháng là 2%, số tiền cần có là S=108 Ta tính số tiền có sau tháng gửi: Sau tháng gửi: Số tiền=100 + 100*0.02 = 102 Sau tháng gửi: Số tiền=102 + 102*0.02 = 104.04 Sau tháng gửi: Số tiền=104.04 + 104.04*0.02 = 106.1208 Sau tháng gửi: Số tiền=106.1208 + 106.1208*0.02 = 108.2432 Vậy cần gửi N=4 tháng, số tiền có là 108.2431 (111) Qúa trình lặp kết thúc tới tháng đầu tiên có Số tiền  S Chương trình sau: PROGRAM VIDU911; { Tính số tháng gửi ngân hàng để có số tiền S } Var Tienvon, Laisuat, Sotien, S : Real; N : Byte; Begin Write(‘ Nhập tiền vốn, lãi suất và số tiền S cần có: ‘); Readln(Tienvon, Laisuat, S); Sotien:=Tienvon; N:=0; { N là số tháng gửi } While Sotien< S begin N:=N+1; Sotien:= Tienvon + Tienvon*Laisuat ; Tienvon:=Sotien; end; Writeln(‘ Cần gửi ‘, N , ‘ tháng ‘); Writeln(‘ Số tiền có = ‘ , Sotien:6:2); Readln; End Chạy<VD911.EXE> Chép file nguồn <VD911.PAS> Số lần lặp lệnh: While Sotien < S không phải ta ấn định từ trước mà tùy thuộc vào biểu thức Sotien < S là mau bị sai hay chậm bị sai Số lần lặp ít hay nhiều phụ thuộc vào gía trị S nhỏ hay lớn và vào tốc độ tăng nhanh hay chậm số tiền (112) 9.3 CÂU LỆNH REPEAT 9.3.1 Cú pháp, lưu đồ, cách thức hoạt động : Cú pháp: REPEAT LệnhP; UNTIL Ðiềukiện ; Ý nghĩa: Chừng nào Ðiềukiện còn sai thì làm LệnhP, Ðiềukiện đúng thì không làm LệnhP mà chuyển sang lệnh phía Cách thức hoạt động REPEAT: Bước 1: Làm LệnhP, kiểm tra Ðiềukiện, Ðiềukiện đúng thì chuyển sang lệnh phía dưới, ngược lại, Ðiềukiện sai thì quay lại bước LệnhP gọi là thân vòng lặp REPEAT, nó gồm nhiều lệnh thì các lệnh đó không cần phải đặt khối begin va?end Nếu Ðiềukiện không đúng thì LệnhP phải làm hoài, lúc đó ta có vòng lặp vô hạn Trong trường hợp này, muốn dừng chương trình, hãy gõ đồng thời hai phím Ctrl và Pause (^Pause) Ðể tránh các vòng lặp vô hạn, thân lệnh REPEAT cần có ít lệnh có tác dụng làm biến đổi các đại lượng tham gia Ðiềukiện để đến lúc nào đó thì Ðiềukiện đúng và đó vòng lặp kết thúc Các vòng lặp có số lần lặp biết trước có thể giải lệnh REPEAT Ðặc biệt, lệnh WHILE, lệnh REPEAT thích hợp với các vòng lặp có số lần lặp không biết trước 9.3.2 Các ví dụ lệnh Repeat : Ví dụ 9.12: Ðảm bảo tính hợp lý liệu nhập từ bàn phím (113) Khi giải phương trình bậc hai Ax2+Bx+C=0, ta thường giả thiết A 0, tính S=N!, ta thường yêu cầu N Sự hạn chế phạm vi các liệu nhập đảm bảo tính hợp lý chúng và làm giảm bớt các phức tạp biện luận Ðể buộc người sử dụng phải nhập A 0, nhập A=0 thì bắt nhập lại nhập A thôi, ta dùng cấu trúc : Repeat Write(‘Nhập A khác không : ‘); Readln(A); Until A<> 0; Ðể đảm bảo chắn nhập N thỏa điều kiện 0<N<20, ta dùng cấu trúc : Repeat Write(‘ Nhập N (0<N<20) : ‘); Readln(N); If (N<=0) or (N>=20) then write(#7); Until (0<N) and (N<20) ; Lệnh write( chr(7) ) hay write(#7) có công dụng phát tiếng kêu bip để cảnh báo người dùng đã nhập liệu sai yêu cầu Ví dụ 9.13: Tìm bội số chung nhỏ hai số nguyên dương M và N Bài toán này có cách giải khác nhau, đây là cách đơn giản Trước hết, hãy xem cách tìm BSCNN hai số M=5 và N=9 Vì N>M nên ta tìm tập các bội số N :{ 9, 18, 27, 36, 45, } số nhỏ chia hết cho M, đó là số 45 Một cách tổng quát, gọi Max là số lớn M và N Ðầu tiên ta gán : BSCNN:=0; Sau đó làm lệnh BSCNN:=BSCNN+Max ; hoài BSCNN chia hết cho M và N thì dừng Trong chương trình ta dùng lệnh repeat để nhập hai số M, N đảm bảo dương PROGRAM VIDU913; { Tìm BSCNN M và N } Var (114) M, N, Max, BSCNN : Integer; Begin Repeat Write(‘ Nhập M và N dương :’); Readln(M, N); Until (M>0) and (N>0); If N>M then Max:=N else Max:=M; BSCNN:=0; Repeat BSCNN:=BSCNN + Max; Until (BSCNN mod N=0) and (BSCNN mod M=0) ; Writeln(‘ Bội số chung nhỏ nhất= ‘, BSCNN) ; Readln; End Chạy <VD913.EXE> Chép file nguồn <VD913.PAS> Ví dụ 9.14: Thiết kế để chạy nhiều lần chương trình Trong Turbo Pascal, lần muốn chạy chương trình ta phải gõ cặp phím Ctrl và F9 (viết tắt là ^F9), điều này bất tiện cần chạy chương trình nhiều lần ứng với các liệu thử khác Cấu trúc sau đây cho phép ta chạy chương trình số lần theo ý muốn: REPEAT { Các lệnh chương trình} Write(‘ Tiếp tục không (Y/N) ? :’); Readln(Traloi); {5} UNTIL (Traloi =‘N’) or ( Traloi=‘n’); Ở đây, Traloi là biến kiểu ký tự (Char); Sau thực xong {các lệnh chương trình }, muốn chạy tiếp thì ta gõ phím Y  , muốn dừng thì gõ N (115) Chú ý : lệnh Readln(Traloi); dòng thứ {5} có thể thay bằng: Traloi:=Readkey; Hàm Readkey thuộc thư viện CRT cho kết qủa là ký tự gõ từ bàn phím, nó khác lệnh Readln(Traloi) chỗ là nhập ký tự ta không cần phải Enter Chương trình đây cho phép thực số lần việc : in tam giác cân đặc có chiều cao m (0<m<20) : PROGRAM VIDU914; { In tam giác cân đặc } Uses CRT; Const =‘*’; Var k, j, m: integer; Traloi : Char ; Begin REPEAT {9} Clrscr; Repeat {11} Write(‘ Nhập m (0<m<20) : ‘); Readln(m); If (m <= 0) or ( m>=20) then write(#7); Until (m>0) and ( m<20) ; Writeln(sao :m); { in đỉnh } {15} (116) { In hai cạnh bên tam gíac } For k:=1 to m-2 begin Write(chr(32): m-k-1); { in m-k-1 ký tự trắng} For j:=1 to 2*k+1 Write(sao); { in 2k+1 dấu *} Writeln; end; For k:=1 to 2*m-1 Write(sao); {in cạnh đáy} Writeln; Write(‘ Tiếp tục không (Y/N) ?: ‘); Readln( Traloi); UNTIL (Traloi=‘N’) or ( Traloi=‘n’); {28} End Chạy<VD914.EXE> Chép file nguồn <VD914.PAS> Chương trình 9.14 là ví dụ hai câu lệnh Repeat lồng nhau, điều này xảy thân lệnh Repat lại chứa lệnh Repeat khác: lệnh Repeat thứ nhất, từ dòng {9} đến dòng {28}, chứa lệnh Repeat thứ hai từ dòng {11} đến dòng {15} 9.3.3 So sánh các lệnh For, While và Repeat: Lệnh For dùng cho các vòng lặp có số lần lặp đã biết trước Lệnh While hay Repeat tổng quát lệnh For, dùng cho tất các loại vòng lặp, thường dùng cho các vòng lặp có số lần lặp chưa biết trước Lệnh While và Repeat khác điểm sau: lệnh While kiểm tra điều kiện trước, đúng thực các lệnh ghi thân nó ( lệnhP ), còn lệnh Repeat thực lệnhP kiểm tra điều kiện Vì thế, lệnh Repeat thực các lệnh ghi thân nó ít lần Ngoài ra, lệnh While kết thúc điều kiện sai, lệnh Repeat kết thúc điều kiện đúng (117) 9.4 CÂU HỎI TRẮC NGHIỆM Câu 1: Cho S và i là biến nguyên Khi chạy đoạn chương trình : s:=0; for i:=1 to 10 s := s+i; writeln(s); Kết in lên màn hình là : a) s = 11 b) s = 55 c) s = 100 d) s = 101 Câu 2: Cho S, i và N>0 là các biến nguyên Ðể tính S = N!, chọn câu nào : a) S := 1; For i := to N S := S * i; b) S := 0; For i := to N S := S * i; c) S := 1; For i := to N S := S * N; d) S := 1; For i:= to N S := S + i; Câu 3: Cho S = 12 + 22 + + 1002 Nhóm lệnh nào tính sai Giá trị S: a) S:=0; FOR i:=1 TO 100 DO S := S + i*i; b) S:=0; FOR i:=1 TO 100 DO S := S + SQR(i); c) S:=0; FOR i:=100 DOWNTO DO S := S + i*i; d) S:=1; FOR i:=1 TO 100 DO S := S + i*i; Câu 4-Khi chạy chương trình : Var S, i, j : Integer; Begin S := 0; for i:= to for j:= to S := S + ; End Giá trị sau cùng S là : a) b) 12 (118) c) d) Câu 5: Cho S và i biến kiểu nguyên Khi chạy đoạn chương trình : S:= 0; i:= 1; while i<= begin S:= S + i; i:= i + 2; end; Giá trị sau cùng S là : a) b) c) 11 d) Câu 6: Khi chạy chương trình : Var S, i : Integer; Begin S:= 0; i:= 1; Repeat S:= S + i * i; i:= i + 1; Until i > ; End Giá trị sau cùng S là : a) b) 14 c) 16 d) 30 Câu 7: Cho i là biến nguyên Khi chạy đoạn chương trình : i := 5; Repeat i := i + 1; Until i > ; (119) Giá trị sau cùng i là : a) b) c) d) Câu 8: Cho m, n, i là các biến nguyên Khi chạy đoạn chương trình : m:=4; n:=5; i:=5; Repeat i:=i+1; Until (i Mod m = 0) and (i Mod n = 0); Giátrị sau cùng i là : a) 20 b) c) d) Câu 9: Cho chương trình : Var A : Real; Begin While A = begin write ('nhap A # 0:'); Readln (A); end; End Ðể lệnh Readln(A) thực ít lần, phải điền vào chỗ lệnh nào các lệnh đây ? : a) A:=0; b) A:=1; c) A:=-1; d) A <> 0; Câu 10: Giảsử các khai báo biến hợp lệ Ðể tính S = 10!, chọn câu nào : (120) a) S := 1; i := 1; b) S := 1; i := 1; while i<= 10 S := S * i; while i<= 10 i := i + 1; i := i + 1; S := S * i; c) S := 0; i := 1; while i<= 10 begin d) S := 1; i := 1; while i<= 10 begin S := S * i; S := S * i; i := i + 1; i := i + 1; end; end; (121) 9.5 BÀI TẬP Câu 1) In bảng mã ASCII thành hai cột : Mã Ký tự , yêu cầu hiển thị trang , (mỗi trang 22 dòng) dừng lại chờ ta gõ Enter trang kế tiếp, hết Câu 2) Nhập số nguyên dương N Tính : Câu 3) Nhập số n nguyên đảm bảo cho n dương ( Nếu nhập n  thì chương trình phải bắt nhập laị ), tính : S1 = 12 + 32 + 52 + 72 + + (2n+1)2 Câu 4) Nhập số nguyên dương n Tính : S4 = 1.2.3 + 2.3.4 + 3.4.5 + + n(n+1)(n+2) Câu 5) Nhập số nguyên dương n Tính : Câu *6) Nhập số x thực và số n nguyên  1, tính gần đúng ex theo công thức : Câu 7) Nhập n, k nguyên đảm bảo phải dương và k<= n Tính tổ hợp chập k n theo công thức : Câu 8) Cho dãy Fibonaci xác đinh sau: F0=0, F1=1, Fn = Fn-1 + Fn-2 , với n >= (122) Hãy nhập số nguyên N>0 và tính S= F0 + F1 + F2 + + Fn Câu 9) Tìm và in lên màn hình tất các số nguyên phạm vi từ 10 đến 99 cho tích hai chữ số nó thì hai lầ? tổng hai chữ số nó Ví dụ : số N=36 có hai chữ số là và 6, và 3*6 = 2*(3+6) Tương tự số 44 Câu 10) Nhập N nguyên đảm bảo lớn Tính tổng các số lẻ  N Ví dụ : N=5 thì tổng S=1+3+5 = 9, N=8 thì S=1+3+5+7=16 Câu 11) Nhập số thực A đảm bảo 0<A< 2, tìm số n nhỏ thỏa mãn : Câu 12) Nhập vào tuổi cha và tuổi đảm bảo cho tuổi cha lớn hai lần tuổi Hỏi sau bao nhiêu năm thì tuổi cha hai lần tuổi Ví dụ tuổi cha là 30, tuổi là 5, sau 20 năm tuổi cha là 50 gấp đôi tuổi 25 Câu 13) Tìm bội số chung nhỏ hai số nguyên dương m, n nhập từ bàn phím Suy ước số chung lớn chúng ( Hd : BSCNN * USCLN = m* n ) Câu 14) Nhập m, n nguyên ( < m, n < 20 ) In lên màn hình tam giác cân có chiều cao m, và hình chữ nhật có chiều dài n, chiều rộng là m : Bài 10 Kiểu liệu mảng YÊU CẦU CỦA BÀI GIẢNG Nắm được: Cách khai báo và sử dụng mảng chiều và hai chiều Các bài toán mảng 10.1 MẢNG MỘT CHIỀU 10.1.1 Mảng và cách khai báo mảng : Khái niệm : (123) Mảng là tập gồm nhiều phần tử có cùng chung kiểu liệu Mỗi phần tử mảng có đại lượng xác định vị trí tương đối phần tử đó so với các phần tử khác mảng, gọi là so? Các yếu tố để xác định mảng gồm có: Tên mảng Kiểu liệu chung các phần tử mảng Kiểu liệu số và phạm vi số Kiểu liệu các phần tử mảng là kiểu liệu mà biến có thể có Tuy nhiên, kiểu liệu số thì không là kiểu thực hay kiểu chuỗi, nó có thể là kiểu đếm : nguyên, ký tự, lôgic, liệt kê hay đoạn Khai báo mảng chiều : Mảng chiều, còn gọi là dãy, hay đơn giản là mảng, có thể khai báo theo hai cách : Cách 1: Khai báo trực cách sau : VAR Tênmảng : Array[m1 m2] of Tênkiểudữliệu ; Ở đây m1, m2 là hai hằ?g xác định phạm vi số, chúng có chung kiểu liệu,?và m1 m2 Ví dụ: Cho khai báo đây: Var A : Array[0 10] of Real; Hten: Array[1 5] of String[18]; B: Array[‘a’ ’d’] of Integer; Theo khai báo trên, ta có ba mảng: Mảng thứ tên là A, gồm 11 phần tử cùng kiểu Real, ứng với các số 0, 1, 2, , 10, đó là: A[0], A[1], A[2], , A[10] Mảng thứ hai tên là HTen gồm phần tử cùng kiểu liệu là String[18] ứng với các số từ đến 5: Hten[1], Hten[2], Hten[3], Hten[4], Hten[5] Mảng thứ ba tên là B, gồm phần tử cùng kiểu Integer ứng với các số ‘a’, ‘b’, ‘c’, ‘d’: (124) B[‘a’], B[‘b’], B[‘c’], B[‘d’] Ðể có hình ảnh mảng, mảng A, ta hình dung có dãy nhà tầng, tên gọi là dãy A, gồm 11 phòng liên tiếp giống hệt đánh số thứ tự từ 0,1, 2, , đến 10 : A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 Tương tự, mảng B giống dãy nhà B tầng có phòng đánh số thứ tự là các chữ a, b, c, d : Ba Bb Bc Bd Cách : Khai báo qua kiểu liệu mới, gồm hai bước: Bước 1: Ðịnh nghĩa kiểu liệu mảng : TYPE Tênkiểumảng = Array[m1 m2] of Tênkiểudữliệu; Bước 2: Khai báo biến có kiểu liệu là kiểu mảng: VAR Tênmảng : Tênkiểumảng ; Ví dụ, các mảng A, B và Hten trên ta có thể khai báo theo cách 2, sau: Type Mang1 = array[0 10] of Real; Mang2 = array[1 5] of String[18]; Mang3 = array[‘a’ ’d’] of Integer; Var A : Mang1; Hten: Mang2; B: Mang3; Khai báo mảng có gán trị ban đầu: Pascal cho phép vừa khai báo mảng vừa gán gía trị ban đầu cho các phần tử mảng, chẳng hạn đây: (125) Const X : array[1 5] of Integer = (12, 14, 16, 18, 20) ; Khi đó X là mảng gồm phần tử cùng kiểu nguyên và có giá trị X[1]=12, X[2]=14, X[3]=16, X?4]=18, X[5]=20 Mặc dù từ khóa đây là Const song X lại dùng là biến mảng, tức là các phần tử X có thể thay đổi gía trị Ví dụ, chương trình ta có thể gán: X[1]:= 2; X[2]:=5+20; 10.1.2 Truy xuất các phần tử mảng: Các xử lý trên mảng quy xử lý phần tử mảng Ðể xác định phần tử mảng, ta dùng cách viết : Tênmảng[ số phầ? tử ] Ví du : có thể gán : A[0]:= 15.8; A[1]:= 2*A[0]; Hten[3]:= ‘Nguyen Thi Loan’; B[‘a’]:=100; Chỉ số phần tử có thể là biến, hằng, hay biểu thức Ví dụ, cho i là biến kiểu nguyên, đó ta có thể dùng các lệnh: i:=6; A[i]:=100.25; Hai lệnh trên tương đương với lệnh: A[6]:=100.25; Nếu biến i có giá trị là thì lệnh : A[ i div +1] := 4.5; tương đương với lệnh: A[4]:=4.5; vì biểu thức i div +1 có gía trị là Khi nhập liệu cho các phần tử mảng , ta có thể dùng câu lệnh For, While hay Repeat (126) Ví dụ, nhập liệu cho các phần tử mảng A: For i:=0 to 10 begin Write(‘Nhập phần tử thứ ‘ , i , ‘: ‘); Readln(A[i]); end; (dùng While) : i:=0; While i<= 10 begin Write(‘Nhap phần tử thứ ‘, i, ‘: ‘); Readln(A[i]); i:=i+1; end; Tương tự để nhập liệu cho các phần tử mảng B, ta viết: For ch:=‘a’ to ‘d’ begin Write(‘Nhap phần tử thứ ‘, ch, ‘: ‘); Readln(B[ch]); end; Ðể in các gía trị mảng A lên màn hình, ta viết : For i:=0 to 10 Write(A[i]:6:2); Các gía trị mảng A in liên tiếp trên cùng dòng Còn muốn in phần tử trên dòng, ta thay lệnh Write bằ?g Writeln Tương tự, mảng B in lên màn hình lệnh : For ch:=‘a’ to ‘d’ Write(B[ch]); Chú ý : Turbo Pascal cho phép gán mảng này cho mảng khác (127) Nếu X, Y là hai biến mảng cùng kiểu mảng thì lệnh: X := Y; có nghĩa là lấy gía trị phần tử mảng Y gán cho phần tử tương ứng mảng X Ví dụ, cho khai báo: Var X, Y : Array[1 10] of Real; Khi đó, lệnh: X := Y; tương đương với lệnh : For i:=1 to 10 X[i] :=Y[i]; 10.1.3 Các bài toán mảng : Ví dụ 10.1: Ðếm số lần xuất gía trị x dãy A1, A2, , An Ví dụ gía trị x=6 xuất lần dãy 6 Ta dùng biến Dem kiểu nguyên để đếm số lần xuất x Ðầu tiên ta gán Dem:=0, sau đó duyệt phần tử A1, A2, , An, có phần tử x thì tăng biến Dem lên đơn vị Kết qủa là biến Dem có gía trị đúng số phần tử x Hai lệnh chính thuật toán là: Dem:=0; For i:=1 to N If A[i]=x then Dem:=Dem+1; Ví dụ, đếm dãy số A có bao nhiêu số 0, ta viết: Dem:=0; For i:=1 to N if A[i]=0 then Dem:=Dem+1; Writeln(‘ Có ‘, Dem , ‘ số không ‘); Nhận xét: Ðẳng thức A[i]=x ( hay A[i]=0 ) là điều kiện để biến Dem tăng thêm 1, bài toán trên có thể mở rộng là: hãy đếm số phần tử mảng A thỏa mãn điều kiện cho trước Trong lệnh For trên, thay đẳng thức A[i]=x A[i] thỏa điều kiện , ta thuật toán tổng quát : Dem:=0; For i:=1 to N If A[i] thỏa điều kiện then Dem:=Dem+1; Chương trình sau nhập mảng A có N phần tử, in mảng A lên màn hình, và đếm xem mảng A có bao nhiêu số dương : PROGRAM VIDU101; (128) { Ðếm số dương mảng} Type Kmang = Array[1 20] of Real; Var A: Kmang; i, N, Dem : Integer; Begin Repeat Write(‘ Nhập số phần tử N : ‘); Readln(N); Until (N>0) and ( N<21); { nhập mảng } For i:=1 to N begin Write(‘Nhập A[‘ , i , ‘ ]: ‘); Readln( A[i] ); end; { In mảng A} Writeln(‘ Mảng A là : ’); For i:=1 to N Write(A[i]:3:0); Writeln; { đếm số dương } Dem:=0; For i:=1 to N If A[i]>0 then Dem:=Dem+1; Writeln(‘ Số số dương = ‘ , Dem ); Readln; (129) End Chạy<VD101.EXE> Chép tập tin nguồn <VD101.PAS> Ví dụ 10.2: Tìm số lớn dãy A1, A2, , An Trong bài 8, ta đã cách tìm số lớn hai số, ba số Có thể mở rộng thuật toán đó để tìm số lớn n số : Gọi Max là biến chứa số lớn phải tìm, thì : Bước 1: Gán Max:=A[1]; Bước 2: Nếu Max<A[2] thì gán Max:=A[2]; Bước 3: Nếu Max<A[3] thì gán Max:=A[3]; Bước n: Nếu Max<A[n] thì gán Max:=A[n]; Khởi đầu, Max gán giá trị A[1] Sang bước 2, Max so sánh với A[2] để chọn số lớn A[1], A[2] và lưu vào biến Max Sang bước 3, Max tiếp tục so sánh với A[3] để tìm số lớn A[1], A[2], A[3], v.v Kết qủa, sau bước n, biến Max chứa số lớn dãy A[1], A[2], , A[n] Quá trình trên mô tả hai lệnh: Max:=A[1]; For i:=2 to n if Max<A[i] then Max:=A[i]; Nhận xét: Trong lệnh For trên, biến i chạy 2, kết qủa đúng cho i chạy Không thiết phải gán giá trị ban đầu cho Max là A[1], mà có thể gán cho Max phần tử tùy ý mảng, ví dụ phần tử A[n] chẳng hạn, đó biến i lệnh For phải chạy Ví dụ 10.3: Bài toán xếp mảng tăng dần (hay giảm dần) Cho dãy A[1], A[2], , A[n], nói A là dãy tăng A[1]  A[2]  A[n], tương tự, A là dãy giảm A[1] A[2]  A[n] Dãy đồng A[1]=A[2]= =A[n] là trường hợp đặc biệt, vừa là dãy tăng, vừa là dãy giảm Ví dụ: Dãy 3 5 6 là dãy tăng (130) Dãy 9 5 0 là dãy giảm Dãy 3 6 là dãy không tăng không giảm Bài toán đặt là: cho dãy A[1], A[2], , A[n] bất kỳ, hãy thực các hoán đổi các gía trị các phần tử mảng A để A lập thành dãy tăng Ví dụ, cho dãy A có phần tử A[1]=9, A[2]=7, A[3]=5, A[4]=8, và A[5]= 2, cần thực các hoán đổi nào để có A[1]=2, A[2]=5, A[3]=7, A[4]=8 và A[5]=9 Có phương pháp xếp mảng khác nhau, đây xin giới thiệu phương pháp, chưa phải là hay đơn giản và dễ hiểu cho người lập trình, đó là phương pháp lựa chọn trực tiếp (Straight selection sort) Ý tưởng phương pháp là sau: Bước 1: Tìm số nhỏ các phần tử A[1], A[2], , A[n] và để vào vị trí đầ? tiên A[1] Bước 2: Tìm số nhỏ các phần tử A[2], A[3], , A[n] và để vào vị trí thứ hai A[2] .v.v Bước n-1: Tìm số nhỏ hai phần tử A[n-1], A[n] và để vào vị trí n-1 Sau bước này thì A[n] là gía trị lớn Chẳng hạn, xét dãy A có phần tử: {5,3,4,1}: Bước 1: Nếu A[1]>A[2] thì đổi A[1] với A[2], được: {3,5,4,1} Nếu A[1]>A[3] thì đổi A[1] với A[3]: không đổi Nếu A[1]>A[4] thì đổi A[1] với A[4], được: {1,5,4,3} Bước 2: Nếu A[2]>A[3] thì đổi A[2] với A[3], được: {1,4,5,3} Nếu A[2]>A[4] thì đổi A[2] với A[4], được: {1,3,5,4} Bước 3: Nếu A[3]>A[4] thì đổi A[3] với A[4], được: {1,3,4,5} Sau ba bước, dãy A đã xếp xong Tại bước thứ i (i chạy từ đến ), ta phải so sánh A[i] với A[j] (j chạy từ i+1 đến 4), A[i]>A[j] thì hoán đổi các gía trị A[i] và A[j], nói cho gọn là đổi chỗ A[i] với A[j] Qúa trình trên thể hai vòng lặp For : For i:=1 to For j:=i+1 to if A[i]>A[j] then Ðổi chỗ A[i] và A[j] ; (131) Mảng A trên có phần tử, trường hợp tổng quát mảng A có N phần tử thì lệnh For thứ có biến i chạy từ đến N-1, và lệnh For thứ hai có biến j chạy từ i+1 đến N, tức là : For i:=1 to N-1 For j:=i+1 to N if A[i]>A[j] then Ðổi chỗ A[i] và A[j] ; Việc đổi chỗ các gía trị A[i] và A[j] tiến hành cách dùng biến Z trung gian cùng kiểu liệu với A[i] và A[j] Ðầu tiên gởi tạm gía trị A[i] vào biến Z, sau đó đưa gía trị A[j] vào A[i], và cuối cùng đưa gía trị Z vào A[j], tức là phải làm ba lệnh : Z:=A[i]; A[i]:=A[j]; A[j]:=Z; Tóm lại, thuật toán xếp dãy A tăng viết sau: For i:=1 to N-1 For j:=i+1 to N if A[i]>A[j] then begin { Ðổi chỗ A[i] và A[j] } Z:=A[i]; A[i]:=A[j]; A[j]:=Z; end; Trong đó N là số phần tử dãy A còn Z là biến trung gian có cùng kiểu liệu với các phần tử mảng A Chương trình đây tìm số lớn mảng A và dãy A tăng dần: PROGRAM VIDU103; { Tìm Max và dãy A tăng dần } Uses CRT; Type Kmang = array[1 20] of Real; (132) Var i, j, N : Integer; A: Kmang; z, Max : Real; Begin Clrscr; Repeat Write(‘ Nhập số phần tử N : ‘); Readln(N); Until (N>0) and ( N<21); For i:=1 to N { nhập mảng } begin Write(‘Nhập A[‘, i, ‘]: ‘); Readln(A[i]); end; { Tìm số lớn } Max :=A[1]; For i :=1 to N if Max< A[i] then Max:=A[i]; Writeln(‘ Số lớn là: ’ , Max : 4:1); { xếp dãy tăng } For i:=1 to N-1 For j:=i+1 to N If A[i]>A[j] then begin {23} { đổi chỗ A[i] và A[j] } z:=A[i]; A[i]:=A[j]; (133) A[j]:=z; end; Writeln(‘ Dãy đã?sắp tăng là : ‘); For i:=1 to N Write(A[i]:3:0); Readln; End Chạy<VD103.EXE> Chép tập tin nguồn <VD103.PAS> Chú ý 1: Muốn dãy A giảm dần thì chương trình trên cần thay dòng {23}: If A[i] > A[j] then dòng : If A[i] < A[j] then Tức là thay dấu lớn > dấu nhỏ < Chú ý : Sắp xếp phận dãy Gọi m và h là hai số nguyên cho 1<= m< h<= N, đó A[m], A[m+1], , A[h] là dãy dãy A Muốn dãy A[m], A[m+1], , A[h] tăng (hay giảm) mà không làm ảnh hưởng đến các phần còn lại dãy A, ta dùng lệnh sau: For i:= m to h-1 For j:=i+1 to h if A[i]>A[j] then begin { Ðổi chỗ A[i] và A[j] } Z:=A[i]; A[i]:=A[j]; A[j]:=Z; end; Ví dụ 10.4: Kiểm tra mảng có thỏa tính chất không (134) Ta thường gặp bài toán kiểm tra xem phần tử mảng A có thỏa mãn điều kiện không, ví dụ mảng A có phải là dãy tăng không, có phải là dãy đối xứng không, có phải là cấp số cộng không, Mảng A thỏa tính chất xét phần tử nó thỏa điều kiện xác định nào đó, ngược lại, mảng A không thỏa tính chất xét có phần tử nó không thỏa điều kiện này Hai trạng thái thỏa hay không thỏa thể hai gía trị TRUE hay FALSE biến Kiemtra kiểu lôgic Ðầu tiên ta gán giả định Kiemtra:= TRUE, sau đó ta xét phần tử A, cần có phần tử không thỏa điều kiện thì gán Kiemtra:=FALSE Vậy hai lệnh cần dùng là: Kiemtra:=TRUE; For i:=1 to N if A[i] không thỏa điều kiện then Kiemtra:= FALSE; Việc xác định điều kiện là tùy bài toán cụ thể Ví dụ: Kiểm tra xem A có phải là dãy đối xứng không ? Dãy 5 là đối xứng Dãy là không đối xứng vì A[3] khác A[5] Như vậy, dãy N phần tử A1, A2, , An là đối xứng A1=An, A2=An-1, , An=A1, tức Ai = An-i+1 với i=1, 2, , n Ðẳng thức : Ai = An-i+1 chính là điều kiện mà phần tử dãy A phải thỏa để A là dãy đối xứng Giả thiết biến Kiemtra đã khai báo kiểu Boolean Trong chương trình ta dùng các lệnh sau: Kiemtra:=TRUE; For i:=1 to N if A[i]<>A[N-i+1] then Kiemtra:=FALSE; If Kiemtra=TRUE then writeln(‘ Dãy A đối xứng’) else Writeln( ‘Dãy A không đối xứng ‘); Trong thuật toán trên, lệnh For có thể thay lệnh While, tốc độ nhanh song khó hiểu hơn: Kiemtra:=TRUE; i:=1; (135) While ( i <=N ) and ( Kiemtra=TRUE) if A[i]<>A[N-i+1] then Kiemtra:=FALSE else i:=i+1; If Kiemtra=TRUE then writeln(‘ Dãy A đối xứng’) else Writeln( ‘Dãy A không đối xứng ‘); Bạn đọc hãy viết chương trình cho ví dụ này Chú ý Câu lệnh : If Kiemtra=TRUE then writeln(‘ Dãy A đối xứng’) else Writeln( ‘Dãy A không đối xứng ‘); hoàn toàn tương đương với lệnh : If Kiemtra then writeln(‘ Dãy A đối xứng’) else Writeln( ‘Dãy A không đối xứng ‘); Ví dụ 10.5: Tính gía trị đa thức : P = ao + a1x + a2x2 + + anxn đó số nguyên n, số thực x và các hệ số a0, a1, , an nhập từ bàn phím Ta viết : P= aoU0 + a1U1 + a2U2 + + anUn , đó : U0=1; Ui = xi = xi-1 *x = Ui-1*x với i=1,2, , N Như vậy, tính gía trị U bước i-1 thì tính gía trị U bước i lệnh U:= U*x, sau đó ta việc cộng dồn biểu thức ai*U vào P lệnh P:= P+ ai*U Chương trình viết sau : PROGRAM VIDU105; { Tính gía trị đa thức bậc N } Var i, N : Integer; (136) A: Array[0 20] of Real; x, P, U : Real; Begin Repeat Write(‘ Nhập N và x : ‘); Readln(N, x); Until (N>0) and ( N<21); For i:=0 to N { nhập mảng các hệ số} begin Write(‘Nhập hệ số A[‘, i, ‘]: ‘); Readln(A[i]); end; U:=1; P:=A[0]; For i:=1 to N begin U:=U*x; P:=P+A[i]*U; end; Writeln(‘ P=‘, P:6:2); Readln; End Chạy<VD105.EXE> Chép tập tin nguồn <VD105.PAS> 10.2 MẢNG HAI CHIỀU (MA TRẬN) 10.2.1 Khai báo mảng hai chiều: (137) Mảng hai chiều, còn gọi là ma trận, là mở rộng trực tiếp mảng chiều Ta có hai cách khai báo Cách 1: Khai báo trực tiếp : VAR Tênmảng : Array[n1 n2 , m1 m2] of Tênkiểudữliệu; đó n1, n2 là các có cùng kiểu liệu và n1 n2, chúng xác định phạm vi số thứ nhất, gọi là số dòng Tương tự m1, m2 là các có cùng kiểu liệu và m1 m2, chúng xác định phạm vi số thứ hai, gọi là số cột Giống mảng chiều, kiểu liệu các số có thể là kiểu đếm được: nguyên, ký tự, lô gic, liệt kê hay đoạn con, không là kiểu thực hay chuỗi Ví dụ, cho khai báo : Var X : array[1 2, 3] of Real; Y : array[‘a’ ’c’ , 3] of String[15]; Kết ta nhận hai mảng hai chiều: Mảng X gồm phần tử cùng kiểu liệu thực: X[1,1], X[1,2], X[1,3] X[2,1], X[2,2], X[2,3] Mảng Y gồm phần tử cùng kiểu chuỗi String[15] : Y[‘a’,1], Y[‘a’,2], Y[‘a’, 3] Y[‘b’,1], Y[‘b’,2], Y[‘b’, 3] Y[‘c’,1], Y[‘c’,2], Y[‘c’, 3] Có thể ví X là nhà hai tầng, tầng có ba phòng giống Các tầng đánh số từ đến 2, tầng, các phòng đánh số từ đến Tương tự, Y là nhà ba tầng, các tầng đánh số là ‘a’, ‘b’, ‘c’, tầng có ba phòng đánh số là 1, 2, Cách 2: Biến mảng khai báo thông qua kiểu mảng đã định nghĩa trước đó bằ?g từ khóa TYPE, tức là: TYPE Tênkiểumảng= Array[n1 n2 , m1 m2] of Tênkiểudliệu; VAR (138) Tênmảng : Tênkiểumảng ; Ví dụ: Hai mảng X và Y nói trên có thể khai báo theo hai bước sau: Type Kmang1 = array[1 2, 3] of Real; Kmang2 = array[‘a’ ’c’ , 3] of String[15]; Var X : Kmang1; Y : Kmang2; Chú ý: - Có thể xem mảng hai chiề? là mảng chiều mà phần tử nó lại là mảng chiều Hai mảng X, Y nói trên có thể khai báo sau: Type Kmang1 = array[1 2] of array[1 3] of Real; Kmang2 = array[‘a’ ’c’] of array[1 3] of String[15]; Var X : Kmang1; Y : Kmang2; Hiểu theo cách này thì X là mảng gồm hai phần tử X[1] và X[2] mà phần tử này lại là mảng gồm phần tử : X[1] là mảng có phần tử kiểu thực X[1][1], X[1][2], X[1][3] X[2] là mảng có phần tử kiểu thực X[2][1], X[2][2], X[2][3] Ðiều tương tự áp dụng cho biến mảng Y Hai cách viết X[i][j] và X[i,j] cùng phần tử Khai báo và gán giá trị ban đầu: Có thể khai báo và gán giá trị cho mảng hai chiều, chẳng hạn: Type (139) Kmang1 = array[1 2, 3] of Real; Const X : Kmang1 = ( (1.5, 2.5, 3.5), (5.0, 6.5, 7.0) ); Khi đó X là mảng hai chiều có phần tử cùng kiểu thực và có giá trị là: X[1,1]=1.5, X[1,2]=2.5, X[1,3]=3.5 X[2,1]=5.0, X[2,2]=6.5, X[2,3]=7.0 Cần nhấn mạnh mặc dù từ khóa đây là Const song X và các phần tử X có thể dùng các biến, tức là các phần tử X có thể thay đổi giá trị 10.2.2 Các thao tác trên ma trận : Ðể xác định phần tử mảng hai chiề?, ta viết: Tênbiếnmảng[chỉ số 1, số 2] Ví dụ: X[1,1]:=12.5; X[2,1]:=X[1,1]+15; Y[‘a’,1]:=‘Tran Thi Mai’; Ðể nhập liệu cho mảng hai chiều, ta phải dùng hai vòng lặp duyệt theo hai số, chẳng hạn muốn nhập liệu cho mảng X, ta viết: For i:=1 to For j:=1 to begin Write(‘nhập phần tử hàng ‘, i, ‘ cột ‘, j , ‘: ‘); Readln(X[i, j]); end; Tương tự, lệnh nhập liệu cho mảng Y viết là: For ch:=‘a’ to ‘c’ For j:=1 to begin (140) Write(‘nhập phần tử hàng ‘, ch , ‘ cột ‘, j , ‘: ‘); Readln(X[ch, j]); end; đó ch là biến kiểu ký tự, còn i và j là các biến nguyên Ðể in mảng X lên màn hình, trình bày giống cách viết ma trận, hàng in trên dòng, ta dùng lệnh : For i:=1 to begin For j:=1 to write(X[i, j]:3:1); { in hàng thứ i} Writeln; { xuống dòng, chuẩn bị in hàng } end; 10.2.3 Các ví dụ ma trận : Vì ma trận là mảng chiều các mảng chiều nên nhiều bài toán mảng mở rộng tự nhiên cho ma trận Ví dụ 10.6: Tính tổng hai ma trận Nhập vào hai ma trận A, B cấp NxM Tính ma trận C là tổng hai ma trận A và B, in ma trận C lên màn hình Công thức tính các phần tử ma trận C= A+B : C[i,j ] = A[i, j] + B[i, j] với i=1, , N, và j=1, , M Chương trình sau: PROGRAM VIDU106; { Tính tổng hai ma trận } Uses CRT; Var A, B, C : Array[1 10, 10] of Real; i, j , N, M : Integer; Begin (141) Clrscr; Repeat Write(‘Nhập số hàng N, số cột M : ‘); Readln(N, M); Until ( N>0) and ( N<11) and ( M>0) and (M<11); For i:=1 to N For j:=1 to M begin Write(‘Nhập A[‘ , i, ‘,’ , j , ‘]: ‘); Readln(A[i,j]); end; { nhập B và tính C luôn} For i:=1 to N For j:=1 to M begin Write(‘Nhập B[‘ , i, ‘,’ , j , ‘]: ‘); Readln(B[i,j]); C[i, j]:=A[i, j] + B[i, j]; end; { In ma trân A lên màn hình } Writeln(‘ Ma tran A la :’); For i:=1 to N begin For j:=1 to M write(A[i, j]:3:0); Writeln; end; (142) { In ma trân B lên màn hình } Writeln(‘ Ma tran B la :’); For i:=1 to N begin For j:=1 to M write(B[i, j]:3:0); Writeln; end; { In ma trân C lên màn hình } Writeln(‘ Ma tran C la :’); For i:=1 to N begin For j:=1 to M write(C[i, j]:3:0); Writeln; end; Readln; End Chạy chương trình <VD106.EXE> Chép tập tin nguồn <VD106.PAS> Ví dụ 10.7: Tìm số lớn (số nhỏ nhất) ma trận A: Giả sử A là ma trận N hàng, M cột, và Max là biến chứa số lớn phải tìm Khởi đầ? ta gán A[1,1] cho Max, sau đó duyệt tất các phần tử ma trận, phần tử nào lớn Max thì lưu nó vào Max, tức là: Max:=A[1,1]; For i:=1 to N For j:=1 to M if Max< A[i, j] then Max:=A[i, j]; Writeln(‘ Số lớn là ’, Max); (143) Ví dụ 10.8 : Tìm số lớn (hay số nhỏ nhất) hàng (hay cột) ma trận A: Hàng i ( 1 i N ) ma trận A có dạng : A[i,1], A[i,2], , A[i,M] Nếu xem i là cố định thì đó là mảng chiều có M phần tử, nên số lớn hàng i tìm các lệnh: Max:=A[i, 1]; For j:=1 to M if Max< A[i, j] then Max:=A[i, j]; Writeln(‘Sln hàng ‘, i, ‘ là: ‘, Max) ; Vì có thảy N hàng nên công việc trên phải làm N lần ứng với i=1, 2, , N, tức là: For i:=1 to N begin { tìm số lớn hàng i } Max:=A[i, 1]; For j:=1 to M if Max< A[i, j] then Max:=A[i, j]; Writeln(‘Sln hàng ‘, i, ‘ là: ‘, Max) ; end; Ví dụ 10.9: Kiểm tra ma trận vuông A có đối xứng không ? Ma trận vuông A gọi là đối xứng nó không thay đổi ta đổi cột thành hàng và đổi hàng thành cột Nói cách khác, ma trận A là đối xứng và A[i,j] =A[j,i] với i=1, , N và với j=1, , N Ví dụ, cho hai ma trận đâỵ: thì A là đối xứng, còn B không đối xứng vì B[1,2]  B[2,1] Chỉ cần có cặp i, j cho A[i,j]<>A[j,i] thì A là ma trận không đối xứng Vậy các lệnh kiểm tra tính đối xứng ma trận A là: Kiemtra := TRUE; (144) For i:=1 to N For j:=1 to N if A[i, j]<>A[j, i] then Kiemtra:=FALSE ; If Kiemtra=TRUE then writeln(‘ Ðối xứng ‘) else writeln(‘ Không đối xứng ‘); Trong đó Kiemtra là biến kiểu lôgic Nhận xét rằ?g hai lệnh For trên quét qua tất các phần tử ma trận nên có nửa số lần lặp là thừa Thật vậy, đường chéo chính chia ma trận làm hai phần: nửa trái và nửa phải Các phầ? tử trên đường chéo chính thì đối xứng với chính nó nên không cần phải kiểm tra Nếu phầ? tử nửa bên trái phần tử đối xứng với nó nửa bên phải thì ma trận rõ ràng là đối xứng Vì cần duyệt kiểm tra các phần tử nửa bên trái đường chéo chính là đủ (vùng tam giác) Thuật toán tốt đề nghị là : Kiemtra := TRUE; For i:=2 to N For j:=1 to i-1 if A[i, j]<>A[j, i] then Kiemtra:=FALSE ; If Kiemtra=TRUE then writeln(‘ Ðối xứng ‘) else writeln(‘ Không đối xứng ‘); Hai câu lệnh For trên còn nhược điểm là: xảy A[i,j]<>A[j, i] rồi, lẽ có thể dừng lại và kết luận không đối xứng thì các vòng For tiếp tục, i chạy đến N và j đến i-1 Sử dụng câu lệnh While khắc phục nhược điểm này Chỉ cần xảy A[i,j]<>A[j,i] lần là biến Kiemtra gán gía trị FALSE, đó điều kiện Kiemtra=TRUE bị sai và hai vòng lặp kết thúc Kiemtra:=TRUE; (145) i:=2; While (Kiemtra=TRUE) and (i<= N) begin j:=1; While ( Kiemtra=TRUE) and ( j<=i-1) if A[i, j] <> A[j, i] then Kiemtra:=FALSE else j:=j+1; i:=i+1; end; If Kiemtra=TRUE then writeln(‘ Ðối xứng ‘) else writeln(‘ Không đối xứng ‘); Chương trình đây thực các công việc sau: Nhập vào ma trận vuông A cấp N và in ma trận A lên màn hình Ðếm ma trận A có bao nhiêu số Tìm số lớn A Tìm số nhỏ hàng A Kiểm tra xem A có phải là ma trận đối xứng không PROGRAM VIDU109; Uses CRT; Type Matran = Array[1 10, 10] of Real; Var A : Matran; i, j , N, Dem : Integer; (146) Max, Min : Real; Kiemtra: Boolean; Begin Clrscr; Repeat Write(‘Nhập cấp N : ‘); Readln(N); Until ( N>0) and ( N<11) ; For i:=1 to N For j:=1 to N begin Write(‘Nhập A[‘, i, ‘,’ , j , ‘]: ‘); Readln(A[i,j]); end; { In ma trân A lên màn hình } Writeln(‘ Ma tran A la : ’); For i:=1 to N begin For j:=1 to N write(A[i, j]: :0); Writeln; end; { Ðếm số số } Dem:=0; For i:=1 to N For j:=1 to N if A[i, j]=0 then Inc(Dem); Writeln(‘ Có ‘, Dem, ‘ số không’); (147) { Tìm số lớn ma trận } Max:=A[1,1]; For i:=1 to N For j:=1 to N if Max < A[i,j] then Max:=A[i,j]; Writeln(‘ Số lớn ma trận= ‘, Max : 4:1); { Tìm số nhỏ hàng ma trận } For i:=1 to N begin Min:=A[i,1]; For j:=1 to N if Min > A[i,j] then Min:=A[i,j]; Writeln(‘ Số nhỏ hàng ‘, i , ‘ là: ‘, Min : 4:1); end; { Kiểm tra ma trận có đối xứng không} Kiemtra:=True; For i:=1 to N For j:=1 to i-1 if A[i ,j]<>A[j ,i] then Kiemtra:=False; If Kiemtra=True then Writeln(‘ Ðối xứng’) else Writeln(‘ Không đối xứng’) ; Readln; End (148) 10.3 CÂU HỎI TRẮC NGHIỆM Câu 1: Chọn khai báo đúng : a) Var A: array[1 10] of integer; b) Var A= array[1 10] of integer; c) Var A:= array[1 10] of integer; d) Var A: array[1,10] of integer; Câu 2: Cho khai báo: Var A: Array[1 4] of Real; i : Integer ; Ðể nhập liệu cho A, chọn câu nào : a) For i:=1 to Write(‘ Nhập A[‘, i, ‘]:’); Readln(A[i]); b) For i:=1 to Readln(‘ Nhập A[‘, i, ‘]:’); c) For i:=1 to Begin Write(‘ Nhập A[‘, i, ‘]:’); Readln(A[i]); End; d) Write(‘ Nhập A:’); Readln(A); Câu 3: Cho khai báo biến : Var A : array[1 5] of Integer; Chọn lệnh đúng : a) A[1] := 4/2 ; b) A[2] := -6 ; c) A(3) := ; d) A := 10 ; (149) Câu 4: Trong khai báo sau còn bỏ trống chỗ, vì chưa xác định kiểu liệu biến Max : Var A: Array[‘a’ ’d’] of Real ; Ch : Char ; Max : ; Muốn biến Max lưu gía trị lớn mảng A thì cần khai báo biến Max kiểu gì vào chỗ : a) Char b) Integer c) String d) Real Câu 5: Cho khai báo: Var A: Array[1 4] of Integer ; i : Integer ; Sau thực các lệnh : For i:=1 to A[i]:= i; For i:=1 to A[i]:= A[i]+1; thì mảng A có gía trị là : a) A[1]=1, A[2]=2, A[3]=3, A[4]=4 b) A[1]=2, A[2]=3, A[3]=4, A[4]=5 c) A[1]=0, A[2]=1, A[3]=2, A[4]=3 d) A[1]=1, A[2]=1, A[3]=1, A[4]=1 Câu 6: Khai báo nào đúng : a) Var A : array[1 n,1 m] of integer; (150) b) Const n=2; m=3; Var A: array[1 n,1 m] of integer; c) Var n, m : integer ; A: array[1 n,1 m] of integer; d) Var A: array[3, 2] of Integer; Câu 7: Cho khai báo : Var A : array[1 2,1 3] of Real; i, j : integer; Ðể nhập liệu cho ma trận A, chọn : a) Write(‘ Nhập A:’); Readln(A) ; b) For i:=1 to Readln(A[i, j]); c) For i:=1 to d) For i:=1 to For j:=1 to begin write(‘Nhập A[‘, i, j, ‘]:’); For j:=1 to write(‘Nhập A[‘, i, j, ‘]:’); readln(A[i, j]); readln(A[i, j]); end; Câu 8: Cho khai báo : Var A : array[1 2,1 3] of Real; i, j : integer; Max : Real; Ðể tìm số lớn ma trận A, chọn câu nào : a) Max:=A[1,1]; If Max < A[i,j] then Max:=A[i,j]; b) Max:=A[1,1]; For i:=1 to if Max < A[i,j] then Max:=A[i,j]; (151) c) A[1,1]:=Max ; d) Max:=A[1,1]; For i:=1 to For i:=1 to For j:=1 to For j:=1 to if Max< A[i,j] then A[i,j]:=Max; if Max < A[i,j] then Max:=A[i,j]; Câu 9: Khi chạy chương trình : Var A : array[1 2,1 3] of integer; i, j, S : integer; Begin A[1,1]:= ; A[1,2]:= -1 ; A[1,3]:= -4 ; A[2,1]:= -9 ; A[2,2]:= ; A[2,3]:= ; S:=0; for i:=1 to for j:=1 to If A[i,j] < then S:=S+1; Write(S); End Kết qủa in gía trị S là : a) b) -9 c) d) Câu 10: Cho X1, X2, Xn là mảng số thực Ðể tính : (152) ta có đoạn chương trình sau gồm ba lệnh, lệnh còn bỏ trống : S:=0; For i:=1 to N S := S + X[i]; Hãy điền lệnh thích hợp vào chỗ : a) Write ('S=', S); b) Readln (S); c) d) S := S/N; 10.4 BÀI TẬP Câu 1) Nhập số tự nhiên n và dãy số thực x1, x2, , xn Tìm số lớn và số nhỏ dãy Ðếm dãy có bao nhiêu số dương, bao nhiêu số âm, bao nhiêu số ? Loại nào nhiều ? Câu 2) Nhập dãy số nguyên x1, x2, , xn In riêng các số chẵn và các số lẻ, loại trên dòng Câu 3) Nhập số nguyên dương N, xây dựng dãy số nguyên x0, x1, , xn đó xi là số Fibonaci thứ i: x0=1, x1=1, xi =xi-1 + xi-2 với i  In dãy x lên màn hình Câu 4) Nhập dãy số x1, x2, , xn Tính : Câu 5) Nhập dãy số x1, x2, , xn In đảo ngược dãy đó, ví dụ cho dãy 8, in ra: Sắp xếp dãy tăng dần, in dãy Sắp xếp dãy giảm dần, in dãy Câu 6) Nhập hai dãy số x1, x2, , xn và y1, y2, , yn Xây dựng dãy thứ ba z1, z2, , zn là tổng hai dãy trên (zi= xi + yi), in ba dãy lên màn hình, dãy trên dòng (153) Câu 7) Cho hai đa thức : Pn(x) = anxn + an-1 xn-1 + + a1 x + a0 (an  ) Qm(x) = bmxm + bm-1 xm-1 + + b1 x + b0 (bm  ) Gọi R(x) = Pn(x) + Qm(x) Nhập các số tự nhiên n và m, các hệ số và bj hai đa thức Pn(x) và Qm(x), in bậc và các hệ số đa thức R(x) Câu 8) Nhập x thực, n nguyên dương và mảng các hệ số a0, a1, , an , tính gía trị đa thức : P = anxn + an-1 xn-1 + + a1 x + a0 theo sơ đồ Hoocner : P=( ( (anx + an-1) x+ an-2)x + + a1 )x + a0 Ví dụ : P = 2x4 + 3x3 - 4x2 +7x + = (((2x + 3)x - )x + 7)x + Câu 9) Nhập dãy số x1, x2, , xn , cho biết dãy có đối xứng không?, dãy có lập thành cấp số cộng không? Ví dụ dãy 5 là đối xứng, dãy là cấp số cộng Câu 10) Nhập dãy số x1, x2, , xn , cho biết dãy thuộc loại nào: tăng, giảm hay không tăng, không giảm ? Câu 11) Nhập dãy số nguyên dương x1, x2, , xn Tách dãy x thành hai dãy: dãy A gồm các số chẵn, dãy B gồm các số lẻ, xếp dãy A tăng dần, dãy B giảm dần, in hai dãy A và B trên hai dòng khác Nối hai dãy A và B theo thứ tự đó thành dãy và gán trở lại vào dãy x, in dãy x Ví dụ nhập dãy x={ 5, 7, 0, 2, 1, 6, 4, } thì dãy A={ 0, 2, 4, 6}, dãy B={ 9, 7, 5, 1}, và x={ 0, 2, 4, 6, 9, 7, 5, 1} Câu 12) Nhập hai số m, n và hai ma trận Am,n và Bm,n In các ma trận A, B, C=A+2B và D=A-B lên màn hình Câu 13) Nhập và in ma trận Am,n Tìm số nhỏ và số lớn ma trận Tính tổng tất các phần tử ma trận (154) Ðếm ma trận có bao nhiêu số dương, bao nhiêu số 0, bao nhiêu số âm Câu 14) Nhập và in ma trận Am,n Tìm và in số lớn hàng ma trận Tìm và in số lớn cột ma trận Tìm và in số nhỏ trên đường chéo chính ma trận Câu 15) Nhập và in ma trận vuông An,n A có phải là ma trận đối xứng không A có phải là ma trận đơn vị không? (A là đối xứng Aij=Aji với i,j =1, , n A là ma trận đơn các phần tử trên đường chéo chính và các phần tử còn lại 0) Bài 11 Ôn tập lệnh lặp và mảng YÊU CẦU CỦA BÀI GIẢNG Nắm được: Các phương pháp giải các bài tập nâng cao lệnh lặp và mảng Cách truy xuất phần tử chuỗi, các hàm và thủ tục liên quan đến chuỗi, các ví dụ chuỗi 11.1 CÁC VÍ DỤ NÂNG CAO VỀ CÂU LỆNH LẶP Phần này trình bày cách vận dụng các câu lệnh lặp để giải số bài toán tiêu biểu mức khó Thông qua các ví dụ, người học tìm thấy tư liệu có ích để giải các bài tập tương tự, nâng cao thêm bước kỹ lập trình Ví dụ 11.1: Nhập x và n, tính gần đúng Sinx theo công thức: Ta viết : S= U0 - U1 + U2 - U3 +U4 - +(-1)N UN , đó : U0 = x (155) v.v Như vậy, Uk sai khác Uk-1 thừa số C có thể tính trực x và theo k : Thành ra, lưu số hạng U bước trước thì tính số hạng U bước sau lệnh : U:=U*C; , và vì sang bước sau thì gía trị U thay đổi nên bước ta phải cộng trừ U vào tổng S Việc cộng hay trừ U vào tổng S giải nhờ biến dau gọi là biến chứa dấu U, biến này nhận gía trị là +1 hay -1 ứng với phép cộng hay trừ U vào tổng S Ðầu tiên ta gán: dau:= -1; Tại bước lặp ta cộng U đã nhân với dau vào S, đảo dấu để chuẩn bị cho bước các lệnh: S:= S+ dau * U; dau:= -dau ; Thành bước trước dau=-1 thì bước sau dau=+1 và ngược lại Kết qủa là lệnh S:= S+ dau * U; cộng hay trừ U vào S theo luật đan dấu Câu lệnh lặp dùng đây là lệnh FOR vì số lần lặp N nhập từ bàn phím tức là đã biết trước Chương trình cụ thể sau: PROGRAM VIDU11_1; { Tính gần đúng Sinx } Var N, k, dau : Integer; x, U, S, C : Real; Begin (156) Write(‘Nhập số dương N : ‘); Readln(N); Write(‘Nhập số thực x : ‘); Readln(x); U:=x; S:=x ; { Gán gía trị ban đầu U0 cho S ngay} dau:= -1; For k:=1 to N begin C:= x*x/ ( 2*k*(2*k+1) ); U:= U*C; S:=S+ dau*U; dau:= - dau; end; Writeln(‘ Giá trị Sin = ‘, S:8:4); Readln; End Chạy <VD11_1.EXE > Chép tập tin nguồn <VD11_1.PAS> Khi chạy chương trình, nhập N=6 và x=1.5708 (=  /2) thì cho kết qủa Sinx= 1.0000 ; Nếu nhập N=6 và x=3.1416 (=  ) thì cho kết qủa Sinx = 0.0000 Ví dụ 11.2: Tính gần đúng số e với sai số cho trước Cho công thức : ( vế phải là tổng vô hạn ) Hãy tính gần đúng e2 cách lấy tổng ( hữu hạn ) các số hạng đầu chuỗi gặp số hạng đầu tiên có gía trị tuyệt đối nhỏ số epsilon (EPS) dương khá bé cho trước, tức là : (157) với n là số cho: Ta viết : S = Uo +U1 + +Un , đó : Uo=1 .v.v Tương tự ví dụ 11.1, ta dùng biến U để lưu số hạng bước lặp k=0, 1, 2, Tại bước, ta kiểm tra nếu U  EPS thì cộng U vào tổng S, tính U cho bước cách nhân U với thừa số 2/k Qúa trình kết thúc gặp số hạng U đầu tiên có  U < EPS Vì số vòng lặp là không biết trước nên câu lệnh lặp dùng là WHILE Chương trình viết sau : PROGRAM VIDU11_2; { Tinh e2 theo sai số EPS dương khá bé cho trước} Var k : Integer; S, U, EPS : Real; Begin Repeat Write(‘Nhap sai so > : ‘); Readln(EPS); Until EPS >0; k :=0; S :=0; (158) U :=1; While ABS(U) >= EPS DO begin S:=S +U; k:=k+1; U:=U* 2/ k; end; Writeln(‘ S= ‘ , S:8:4 , ‘ tính đến số hạng k= ‘, k); Readln; End Chạy < VD11_2.EXE> Chép tập tin nguồn <VD11_2.PAS> Khi chạy chương trình, nhập EPS=0.001 thì cho kết qủa S=7.3887 , tính đến số hạng k=10 Ví dụ 11.3: Nhập số nguyên dương N, in các chữ số N theo thứ tự đảo ngược Ví dụ N= 15742 in 24751 Cách làm sau: Tách và in hàng đơn vị N hai lệnh: k:= N mod 10; { k=2 } Write(k: 3); Bỏ hàng đơn vị, giữ lại các chữ số từ hàng chục trở lên: N:= N div 10; { N=1574 } Lặp lại qúa trình trên N=0 Số lần lặp là không biết trước mà tùy thuộc vào việc nhập số N có ít hay có nhiều chữ số, nên ta phải dùng lệnh Repeat hay While PROGRAM VIDU11_3; { In đảo ngược các chữ số N } Var (159) N, k: LongInt ; Begin Repeat Write(‘ Nhập N : ‘); Readln(N); Until (N>0); Writeln( N, ‘ in đảo ngược thành :’); Repeat k:= N mod 10; Write(k: 3); N:=N div 10; Until N=0; Readln; End Chạy <VD11_3.EXE> Chép tập tin nguồn <VD11_3.PAS> Ví dụ 11.4: Kiểm tra số tự nhiên N có phải số nguyên tố không Số N là số nguyên tố nó chia hết cho và chính nó Ví dụ các số 2, 3, 5, 7, 11, 13, 17, 19, 21, 23 là số nguyên tố Xuất phát từ địng nghĩa, ta kiểm tra N không chia hết cho tất các số từ 2, 3, 4, , đến N-1 thì N là nguyên tố, ngược lại, cần N chia hết cho số k nào đó tập { 2, 3, 4, , N-1} thì N không phải số nguyên tố PROGRAM VIDU11_4; { Kiểm tra số N có phải số nguyên tố không } Var N, k: integer; Kiemtra: Boolean ; Begin (160) Repeat Write(‘ Nhập N : ‘); Readln(N); Until (N>0); If N =1 then Kiemtra:= False else { xét N > 1} begin Kiemtra:= True; k:=1; Repeat k:= k+1; Until N mod k=0 ; If k<N then Kiemtra:= False; end; If Kiemtra=True then Writeln(N, ‘ là số nguyên tố ‘) else Writeln(N, ‘ không phải số nguyên tố ‘); Readln; End Chạy <VD11_4.EXE> Chép tập tin nguồn <VD11_4.PAS> Chương trình có đoạn cần giải thích rõ thêm: Repeat k:= k+1; Until N mod k=0 ; If k<N then Kiemtra:= False; (161) Vòng lặp trên kết thúc gặp số k đầu tiên (nhỏ nhất) thỏa điều kiện N mod k=0 Lúc đó, k<N thì có nghĩa N chia hết cho số k khác N nên N không phải số nguyên tố Nếu k=N thì chứng tỏ N chia hết cho N và không chia hết cho các số 2, 3, , N-1 nên N là số nguyên tố Nhận xét: Vì số chẵn (trừ số 2) không phải số nguyên tố nên chương trình có thể cải tiến kiểm tra các số lẻ thôi 11.2 CÁC VÍ DỤ NÂNG CAO VỀ MẢNG Ví dụ 11.5: Nhập danh sách N (N<50) học sinh gồm họ tên và điểm thi môn toán Hãy phân loại các học sinh sau : loại giỏi điểm toán  9, loại khá  điểm toán< 9, loại trung bình  điểm toán< 7, và loại kém điểm toán< In danh sách lên màn hình, người trên dòng, gồm họ tên, điểm toán và phân loại Yêu cầu danh sách thứ tự theo trật tự giảm điểm toán Ðếm xem có bao nhiêu em có điểm toán 10 ? PROGRAM VIDU11_5; Uses CRT; Type Kmang1 = Array[1 50] of String[18]; Kmang2 = Array[1 50] of Real; Var i, j, N, Dem10 : Integer; Hoten, Loai: Kmang1; Dtoan : Kmang2; St: String[18]; z: Real; Begin Clrscr; Repeat Write(‘ Nhập số lượng học sinh : ‘); Readln(N); (162) Until (N>0) and ( N<51); For i:=1 to N { nhập danh sách hs } begin Write(‘Nhập họ và tên hs thứ ‘, i , ‘ : ‘); Readln(Hoten[i]); Write(‘Nhập điểm toán hs thứ ‘, i , ‘ : ‘); Readln(Dtoan[i]); end; { xếp giảm theo điểm toán} For i:=1 to N-1 For j:=i+1 to N If Dtoan[i]<Dtoan[j] then begin { hoán đổi Dtoan và họ tên } z:=Dtoan[i]; Dtoan[i]:=Dtoan[j]; Dtoan[j]:=z; St:=Hoten[i]; Hoten[i]:=Hoten[j]; Hoten[j]:=St; end; { Phân loại } For i:=1 to N If Dtoan[i] >= then Loai[i]:=‘Gioi’ else If Dtoan[i] >=7 then Loai[i]:=‘Kha’ else (163) If Dtoan[i]>=5 then Loai[i]:=‘Trung binh’ else Loai[i] :=‘Kem’; Writeln(‘ Danh sách hs đã giảm theo Ðtoán là: ‘); For i:=1 to N Writeln(Hoten[i]: 18, #32, Dtoan[i]:5:1, #32, Loai[i]) ; { Ðếm số em điểm 10} Dem10 := 0; For i:=1 to N if Dtoan[i]=10 then Dem10 :=Dem10 +1; Writeln(‘ Số em điểm 10 là :’ , Dem10); Readln; End Chạy <VD11_5.EXE> Chép tập tin nguồn <VD11_5.PAS> Trong chương trình, ta sử dụng ba mảng: Hoten, Loai và Dtoan với quy ước phần tử thứ i các mảng này chứa các thông tin cùng người: đó là học sinh thứ i danh sách Vì thế, xếp mảng Dtoan giảm dần, có đổi chỗ Dtoan[i] với Dtoan[j] thì tương ứng phải đổi chỗ Hoten[i] với Hoten]j] Ví dụ 11.6: Nhập các ký tự từ bàn phím, đổi thành chữ thường là chữ hoa, và lưu vào mảng, qúa trình kết thúc nhập ký tự trắng Cho biết có bao nhiêu ký tự đã nhập, đó có bao nhiêu chữ a, b, c, d loại PROGRAM VIDU11_6; { Ðếm ký tự a, b, c, d } Var Kytu : Array[1 20] of Char ; N, i, Max : Integer; ch : Char; (164) Dem : Array[‘a’ ’d’] of Integer; Begin i:=0; Repeat i:=i+1; Write(‘Nhập ký tự thứ ‘ , i , ‘: ‘); Readln(ch); { đổi chữ thường } If ch IN [‘A’ ’Z’] then ch:=Chr( Ord(ch) + 32 ); Kytu[i]:= ch; Until ( ch= #32) or (i=20); N:=i; { Ðếm các chữ a, b, c, d } For ch:=‘a’ to ‘d’ Dem[ch]:=0; For i:=1 to N begin ch:=Kytu[i]; If ch IN [‘a’ ’d’] then Dem[ch] := Dem[ch]+1; {24} end; Writeln(‘ Số ký tự đã nhập là :’ , N ); For ch:=‘a’ to ‘d’ writeln(‘ Số chữ ‘, ch, ‘=‘, Dem[ch]); Readln; End Chạy <VD11_6.EXE> Chép tập tin nguồn <VD11_6.PAS> Trong chương trình, câu lệnh dòng {24}: (165) If ch IN [‘a’ ’d’] then Dem[ch] := Dem[ch]+1; tương đương với lệnh ghép sau: begin If ch =‘a’ then Dem[‘a’] := Dem[‘a’]+1; If ch =‘b’ then Dem[‘b’] := Dem[‘b’]+1; If ch =‘c’ then Dem[‘c’] := Dem[‘c’]+1; If ch =‘d’ then Dem[‘d’] := Dem[‘d’]+1; end; Dùng bốn lệnh này thì dễ hiểu song bài toán không phát triển ta phải đếm nhiều loại ký tự, chẳng hạn đếm chữ a, đếm chữ b, , đếm chữ z Ví dụ 11.7: Nhập ma trận A cấp NxM, đếm xem hàng có bao nhiêu số 0, hàng nào có nhiề? số Ta khai báo Dem là mảng gồm N phầ? tử với quy ước Dem[i] lưu số lượng số hàng i Tìm Max là số lớn mảng Dem Những hàng i nào có Dem[i] =Max là hàng có nhiều số không Dưới đây là chương trình cụ thể : PROGRAM VIDU11_7 ; { Tìm ma trận các hàng có nhiều số } Type Kmang= Array[1 10, 10] of Real; Var A : Kmang; i, j, N, M : Integer; Dem : Array[1 10] of Integer ; Max : Integer ; Begin Repeat (166) Write(‘Nhập số hàng N, số cột M : ‘); Readln(N, M); Until ( N>0) and ( N<11) and ( M>0) and (M<11); For i:=1 to N For j:=1 to M begin Write(‘Nhập A[‘, i, ‘,’ , j , ‘]: ‘); Readln(A[i,j]); end; { In ma trân A } Writeln(‘ Ma tran A la:’); For i:=1 to N begin For j:=1 to M Write(A[i, j]:4:0); Writeln; end; { Ðếm số hàng} For i:=1 to N begin Dem[i]:=0; For j:=1 to M if A[i, j]=0 then Inc(Dem[i]); Writeln(‘Số số hàng ‘, i, ‘ là: ‘ , Dem[i]); end; { Tìm số lớn mảng Dem } Max:=Dem[1]; For i:=1 to N (167) if Max< Dem[i] then Max:=Dem[i]; Writeln(‘ Số 0/hàng nhiều = ‘, Max); { Tìm các hàng có nhiều số nhất} If Max =0 then writeln(‘ Không hàng nào có số ‘) else For i:=1 to N if Dem[i]=Max then writeln(‘ Hàng nhiều số là ‘, i:3 ); Readln; End Chạy <VD11_7.EXE> Chép tập tin nguồn <VD11_7.PAS> Ví dụ 11.8: Hoán đổi hai hàng h và k ma trận A Hàng h có dạng : A[h,1], A[h,2], , A[h,M] Hàng k có dạng : A[k,1], A[k,2], , A[k,M] Việc đổi hàng h và hàng k quy việc đổi chỗ cặp phần tử: A[h,1] với A[k,1], A[h,2] với A[k,2], , A[h,M] với A[k,M], tức là đổi chỗ A[h,j] và A[k,j] với j=1, 2, , M: For j:=1 to M begin { đổi chỗ A[h,j] với A[k,j] } z:=A[h,j]; A[h,j]:=A[k,j]; A[k,j]:=z; end; Ở đây z là biến trung gian cùng kiểu liệu với các phần tử ma trận A Các bạn hãy viết chương trình cho ví dụ này (168) 11.3 KIỂU CHUỖI KÝ TỰ 11.3.1 Chuỗi và khai báo biến chuỗi : Một dãy các ký tự đặt cặp nháy đơn gọi là chuỗi, hay đơn giản là chuỗi Dưới đây là ba chuỗi : ‘Ngon ngu Pascal’ ‘Tin hoc 1998’ ‘12345678’ Chuỗi không có ký tự nào ‘‘ (chỉ gồ? hai dấu nháy đơn liên tiếp) gọi là chuỗi rỗng Số ký tự có chuỗi gọi là độ dài chuỗi Chuỗi ‘ABCD’ có độ dài 4, chuỗi ‘Pascal’ có độ dài là Chuỗi rỗng có độ dài không Biến nhận gía trị là các chuỗi gọi là biến kiểu chuỗi Cách khai báo sau: Var Tênbiếnchuỗi : String[N] ; hoặc: Tênbiếnchuỗi : String ; đó N là nguyên (0  N  255) ấn định số ký tự tối đa mà biến có thể nhận và gọi là độ dài tối đa biến chuỗi Nếu không có thị [N] thì chuỗi có độ dài tối đa là 255 ký tự Ví dụ, cho khai báo : Var St : String[17]; Diachi : String; Khi đó St là biến chuỗi có độ dài tối đa là 17 ký tự, còn biến Diachi có độ dài tối đa là 255 ký tự Cần phân biệt độ dài với độ dài tối đa biến chuỗi: độ dài tối đa xác định khai báo là khả có thể chứa biến chuỗi, còn độ dài chuỗi là số ký tự thực có chuỗi Nếu gán: St := ‘Nguyen Thi Mai’; Diachi := ‘Quan 1, Thanh Ho Chi Minh’; thì biến St có độ dài là 14 ký tự, mặc dù khả nó có thể chứa tới 17 ký tự Tương tự, biến Diachi có độ dài là 29 ký tự còn độ dài tối đa cho phép là 255 (169) Khi gán cho biến chuỗi chuỗi dài độ dài tối đa nó thì các ký tự thừa bị bỏ qua Ví du, gán: St := ‘Quan 1, Thanh Ho Chi Minh’; thì gía trị biến St là St=‘Quan 1, Thanh pho’ Trong nhớ máy, biến chuỗi chiếm số byte bằ?g độ dài tối đa nó cộng thêm Byte đầu tiên, gọi là byte 0, chứa ký tự có mã độ dài thực chuỗi, byte còn lại chứa ký tự Cấu trúc biến St nói trên có dạng: N g u y e n T h i M a i Ðộ dài N (=14) biến St và ký tự byte (ký hiệu là St[0]) liên quan với sau: N = Ord ( St[0] ) St[0]= Chr( N ) Turbo Pascal có sẵn hàm Length(chuỗi) cho độ dài thực chuỗi mà không cần phải dùng đến byte Ví dụ : Length(St)=14 Chú ý Cũng có thể khai báo chuỗi thông qua việc định nghĩa kiểu liệu từ khóa Type Chẳng hạn có thể khai báo chuỗi St nói trên theo cách sau: Type KStr17 = String[17]; Var St : KStr17 ; Khi biến chuỗi dùng làm đối số hàm hay thủ tục thì nó cần phải khai báo theo cách này ( trừ các biến chuỗi có kiểu String ) 11.3.2 Truy nhập vào phần tử chuỗi : Giống mảng, phần tử chuỗi truy nhập thông qua tên chuỗi và số phần tử Gọi N =Length(St), đó ký tự thứ i (i=1, 2, , N) St ký hiệu là St[i] Ví dụ, cho : St :=‘ABC’; (170) thì N=3 và St[1]=‘A’, St[2]=‘B’, St[3]=‘C’ Lệnh St[1]:=‘a’; biến đổi St thành St=‘aBC’ Như ký tự St[i] dùng biến kiểu ký tự, và chuỗi có thể xem là mảng các ký tự Chẳng hạn để in chuỗi ta có thể in ký tự sau: For i:=1 to Length(St) write(St[i]); Ðiều này cho thấy chuỗi là kiểu liệu có tính cấu trúc Nhưng mặt khác, chuỗi lại có thể xem là gía trị nhất, vì có thể nhập và in chuỗi trực tiếp các lệnh: Readln(St); Write(St); Ðặc điểm này cho thấy chuỗi còn là kiểu liệu có tính đơn giản 11.3.3 Các thao tác trên chuỗi : Phép cộng (nối) chuỗi: Khi cộng hai chuỗi, ta chuỗi gồm các ký tự hai chuỗi ban đầu ghép lại.Ví dụ : ‘tin’ + ‘hoc’ =‘tinhoc’ ‘1234’+ ‘5678’ = ‘12345678’ Phép so sánh chuỗi: Khi so sánh hai chuỗi, ta so sánh cặp ký tự hai chuỗi từ trái qua phải Nếu phát cặp ký tự khác thì chuỗi nào chứa ký tự nhỏ nhỏ Ví dụ: ‘Hong’ > ‘Han’ vì ‘o’ > ‘a’ ‘thanh’ > ‘thao’ vì ‘n’ > ‘o’ Nếu so sánh hết chiều dài chuỗi ngắn mà không có cặp nào khác thì chuỗi ngắn nhỏ hơn, ví dụ: ‘an’ < ‘anh’ ‘chu’ < ‘chung’ Hai chuỗi chúng cùng độ dài và các ký tự các vị trí tương ứng thì (171) 11.3.4 Các hàm liên quan đến chuỗi : Hàm Length(St) : cho độ dài chuỗi St Ví dụ: Length(‘ABCD’)=4 vì chuỗi ‘ABCD’ có ký tự Chuỗi rỗng có độ dài Hàm Pos(S, St): Cho vị trí đầu tiên tìm thấy chuỗi S chuỗi St, không tìm thấy thì hàm cho kết qủa Ví dụ: Pos(‘Ab’, ‘cdAb3Abm’) = 3, Pos(‘Ab’, ‘1bA3b’) = Hàm Copy(St, k, m) : cho m ký tự St tính từ vị trí k Ví dụ: Copy (‘ABCDEF’, 4, 2) =‘DE’ Nếu k> Length(St) thì kết qủa là chuỗi rỗng Nếu m> số ký tự đứng sau kể từ vị trí k thì hàm Copy lấy các ký tự từ vị trí k đến hết chiều dài St, ví dụ : Copy (‘ABCD’, 3, 10) = ‘CD’ Hàm Concat( St1, St2, , Stn) : Ghép nối các chuỗi St1, St2, , Stn theo thứ tự đó thành chuỗi Vậy : Concat( St1, St2, , Stn) = St1+St2+ +Stn 11.3.5 Các thủ tục liên quan đến chuỗi : Thủ tục Delete(St, k, m) : Xóa m ký tự biến chuỗi St vị trí thứ k Ví dụ, sau thực các lệnh: St:=‘ TurboPascal’; Delete(St, 1, 5); thì gía trị St=‘Pascal’ vì ký tự đầu đã bị xóa Nếu k > Length(St) thì không xóa gì Nếu m > số ký tự đứng sau kể từ vị trí k thì xóa hết từ vị trí k đến cuối chuỗi (172) Ví dụ, sau thực ba lệnh : St:=‘Turbo Pascal’; Delete(St, 10, 20); Write(St); thì in chữ Turbo Pas vì St đã bị xóa ký tự cuối nên còn St=‘Turbo Pas’ Thủ tục Insert(S, St, k) : Chèn chuỗi S vào biến chuỗi St vị trí k Ví dụ, cho : St:=‘ABCD’; Sau thực lệnh: Insert(‘**’, St, 3); thì St bị biến đổi thành St=‘AB**CD’ Nếu k> Length(St) thì S nối vào cuối St Ví dụ, sau thực hai lệnh : St:=‘XYZ’; Insert(‘ABC’, St, 6); thì St=‘XYZABC’ Thủ tục Str(x, St): Biến đổi số nguyên hay thực x thành kiểu chuỗi và gán cho biến chuỗi St Ví dụ, sau thực lệnh : Str(4752, St); thì kết qủa là St= ‘4752’ Số x có thể định dạng in màn hình Lệnh Str(4752 : 6, St); cho kết qủa St=‘ 4752’ (trước số 4752 có ký tự trắng) Nếu x là biến thực và gía trị x=34.95 thì lệnh : Str(x :7:3, St); cho kết qủa St=‘ 34.950’ (trước số 34.950 có ký tự trắng) Thủ tục Val(St, x, k ): (173) Biến đổi chuỗi số St thành số nguyên hay thực và gán cho biến nguyên hay thực x Số nguyên k dùng để phát lỗi: đổi thì k=0, ngược lại, gía trị k là vị trí có lỗi chuỗi St Ví dụ, cho ba biến n, k, j kiểu nguyên và biến x kiểu thực, sau thực các lệnh : St:=‘385’; Val(St, n, j); Val(‘12.59’, x, k); thì n=385, j=0, x=12.59 và k=0 Nếu gán St := ‘3a7’; và thực lệnh: Val(St, n, k); thì gía trị n không xác định còn k=2 là vị trí chữ a chuỗi St, đó không đổi số 11.3.6 Các ví dụ chuỗi: Ví dụ 11.9: Ðổi chuỗi chữ hoa hay chữ thường Ðể đổi chuỗi St thành chữ hoa, ta đổi ký tự chuỗi đó chữ hoa, tức là : For i:=1 to Length(St) St[i]:=Upcase(St[i]); Tương tự, để đổi chuỗi St thành chữ thường, ta đổi ký tự chuỗi St chữ thường: For i:=1 to Length(St) if ( St[i]>=‘A’) and (St[i]<=‘Z’) then St[i]:=Chr( Ord(St[i]) + 32) ; Ví dụ 11.10: Chuẩn hóa chuỗi ký tự Cho chuỗi St có nhiều ký tự trắng thừa đầu, cuối và các từ, St=‘ nguyen van tuan ‘ Chuẩn hóa chuỗi St là xóa hết các ký tự trắng thừa đầu và cuối, và hai từ giữ lại đúng ký tự trắng, St =‘nguyen van tuan’ a) Xóa các ký tự trắng đầu chuỗi : Ðể xóa ký tự trắng đầu chuỗi St, ta dùng lệnh: If St[1]=#32 then Delete(St,1,1); (174) Muốn xóa hết các ký tự trắng đầu chuỗi ta dùng lệnh: While St[1]=#32 Delete(St,1,1); Diễn giải: chừng nào ký tự đầu tiên St còn là ký tự trắng thì xóa nó ký tự đầu tiên là khác trắng Sở dĩ phải dùng vòng lặp While là vì số ký tự trắng đầu chuỗi là không biết trước b) Xóa các ký tự trắng cuối chuỗi : Tương tự, muốn xóa tất các ký tự trắng cuối chuỗi St, ta dùng lệnh: While St[ length(St) ]= #32 Delete(St, length(St), 1); Diễn giải: chừng nào ký tự cuối cùng St còn là khoảng trắng thì xóa nó ký tự cuối cùng là khác trắng c) Xóa các ký tự trắng thừa hai từ chuỗi : Muốn xóa các ký tự trắng thừa để hai từ còn đúng ký tự trắng ta làm sau: tìm St chỗ nào có hai ký tự trắng thì xóa một, và lặp lại thao tác trên St không còn chỗ nào có hai ký tự trắng liên tiếp Tức là : k:=Pos(‘ ‘, St); { ‘ ‘ là ký tự trắng } While k > begin Delete(St, k, 1); k:=Pos(‘ ‘, St); end; Ví dụ 11.11 : đếm chuỗi St có bao nhiêu chữ pascal Vì chữ pascal có ký tự, nên ta so sánh cụm ký tự St với chuỗi pascal, vị trí 1: Dem:=0; For i:=1 to Length(St) if Copy (St, i, 6) =‘pascal’ then Inc(Dem); Writeln(‘ Số chữ pascal là ‘ , Dem); Ví dụ 11.12: Tìm kiếm và thay (175) Tìm chuỗi St xem có chứa chữ ‘basic’ không, có thì thay chữ ‘pascal’, không có thì in câu ‘không có’ Ví dụ St=‘ngon ngu basic duoc dung bien’, sau thay ta St = ‘ngon ngu pascal duoc dung bien’ Ta dùng hàm Pos để tìm xem St có chứa chữ ‘basic’ không Thủ tục Delete xóa chuỗi ‘basic’ khỏi St, và thủ tục Insert chèn chuỗi ‘pascal’ vào St vị trí xét: PROGRAM VIDU11_12 ; { Tìm chữ basic và thay chữ pascal } Var St: String; k: Integer; Begin Write(‘ Nhập chuỗi St :’); Readln(St); k:= Pos(‘basic’ , St); If k> then begin Delete(St, k, 5); { xóa chữ basic } Insert(‘pascal’ , St, k); { chèn chữ pascal } Writeln(‘ St = ‘, St); end else Writeln( St, ‘ không có chữ basic ‘) ; Readln; End Chạy <VD11_12.EXE> Chép tập tin nguồn <VD11_12.PAS> Ví dụ 11.13: Tính tổng các bình phương các chữ số số tự nhiên N Ví dụ N= 325 thì T=32+22+52 = 38 (176) PROGRAM VIDU11_13 ; { Tính tổng các bình phương các chữ số số N} Var N, T : Longint; i, j , k : Integer; St : String[40]; Begin Write(‘Nhập số N : ‘); Readln(N); Str( N, St ); { Ðổi số N chuỗi gởi vào St } T:=0; For i:=1 to Length(St) begin Val ( St[i], j, k ); {Ðổi St[i] số gởi vào j} T:=T+ j*j; end; Writeln(‘ Tổng= ‘, T); Readln; End Chạy <VD11_13.EXE> Chép tập tin nguồn <VD11_13.PAS> Ví dụ 11.14: Tách từ chuỗi in riêng trên dòng: Cho St=‘ ngon ngu pascal ‘, cần in : ngon ngu pascal Phương pháp: (177) Bước 1: -Chuẩn hóa chuỗi St thành St=‘ngon ngu pascal’ -Thêm ký tự trắng vào cuối để St=‘ngon ngu pascal ‘ Bước 2: -Tìm k là vị trí ký tự trắng đầu tiên, in k-1 ký tự đầu tiên, đó chính là từ thứ nhất, xóa k ký tự đầu tiên, kết qủa St=‘ngu pascal ‘ Lặp lại qúa trình trên St không còn ký tự trắng nào Chương trình cụ thể sau: PROGRAM VIDU11_14 ; { Tách các từ và in riêng trên các dòng } Uses Crt; Var St: String; Tu : String[10]; k: Integer; Begin Clrscr; Write( ‘Nhập chuỗi St :’); Readln(St); { Chuẩn hóa chuỡi St } While St[1]=#32 Delete(St,1,1); While St[ length(St) ]=#32 Delete(St, length(St) ,1); k:=Pos(‘ ‘, St); { ‘ ‘ là ký tự trắng } While k > begin Delete(St, k, 1); k:=Pos(‘ ‘, St); end; (178) Writeln(‘ Chuỗi đã chuẩn hóa là : ’ , St); Writeln( ‘ Tách và in từ trên dòng: ‘); St:=St + #32; { thêm ký tự trắng vào cuối St} k:=Pos(#32, St); While k>0 begin Tu:=Copy(St, 1, k-1); Writeln(Tu); Delete(St, 1, k); k:=Pos(#32, St); end; Readln; End Chạy <VD11_14.EXE> Chép tập tin nguồn <VD11_14.PAS> Ví dụ 11.15 : Ðể kết thúc phần này xin giới thiệu chương trình tạo dòng chữ ‘DAI HOC QUOC GIA TP.HCM’ chạy ngang màn hình từ phải qua trái Chương trình kết thúc ta nhấn phím Tại vị trí dòng 10, cột 10, ta in chuỗi St ngừng giây lát nhờ thủ tục Delay Sau đó ta xóa ký tự đầu tiên St lại in St vị trí dòng 10, cột 10 Kết qủa là ta có cảm giác chuỗi St dịch sang phải cột Lặp lại các thao tác trên ta thấy chuỗi St chạy sang phải Ðể St không bị ngắn dần và tạo cảm giác các chuỗi St chạy nối đuôi nhau, thì trước xóa St[1] ta nối St[1] vào cuối St Dưới đây là chương trình cụ thể: Chú ý hàm Keypressed trả gía tri logic là TRUE có phím trên bàn phím bấm Thủ tục Delay(k) ngừng chương trình thời gian là k/1000 giây Hai hàm và thủ tục này thuộc thư viện CRT PROGRAM VIDU11_15 ; { Tạo chữ chạy ngang màn hình} Uses Crt; (179) Var St: String[80]; Begin St:=‘DAI HOC QUOC GIA TP.HCM ‘ ; TextMode(C40); TextBackground(green); TextColor(yellow); Clrscr; Repeat Gotoxy(10,10); Write(St); Delay(500); St:=St+ St[1]; { nối ký tự đầu vào cuối chuỗi} Delete(St, 1, 1); { Xóa ký tự đầu} Until Keypressed; TextMode(C80); End (180) 11.4 CÂU HỎI TRẮC NGHIỆM Câu 1: Cho biến SS kiểu lô gic Lệnh nào làm SS có gía trị là TRUE : a) SS := 'a' < 'A'; b) SS := 'A' = 'a'; c) SS := 'an' < 'a'; d) SS := 'PASCAL' < 'pascal'; Câu 2: Cho khai báo : Var Ho, ten : String[15]; -Lệnh nào sai : a) Write('Ho ten la : ' ; Ho ; Ten); b) Write('Ho ten la : ' + Ho + Ten); c) Write('Ho ten la : ', Ho , Ten); d) Write('Ho ten la : ', Ho + Ten); Câu 3: Cho khai báo : Var Chuoi : string[10]; x : real; -Lệnh nào đúng : a) Chuoi := Str(x:5:2) ; b) Str(x:5:2, Chuoi); c) Chuoi := x ; d) x := Chuoi ; (181) Câu 4: Cho St là biến chuỗi, sau thực hai lệnh : St:= Copy( 'PASCAL VERSION 5.5' , 8, 7) ; Write(St); -Kết qủa in lên màn hình là: a) VERSION 5.5 b) VERSION c) PASCAL d) 5.5 Câu 5: Cho St là biến chuỗi, sau thực bốn lệnh: St:=’ABCDEF’; Delete(St, 3, 2); Insert(‘XYZ’, St, 2); Write(St); -Kết qủa in lên màn hình là: a) ABXYZEF b) AXYZBCDEF c) AXYZ d) AXYZBEF Câu 6: Cho i và x là hai biến kiểu nguyên Khi thực lệnh : VAL('1234', x, i); -Gía trị x và i là bao nhiêu : a) x = , i = 1234 b) x = 1234 , i = (182) c) x = 1234 , i = d) x = , i = Câu 7: Cho các biến St chuỗi và k nguyên Sau gán: St:='Sinh vien Tin hoc hoc Tin hoc'; k := Pos('Tin', ST) ; -Gía trị k là : a) k=13 b) k=11 c) k=26 d) k=23 Câu 8: Khi chạy chương trình : Var St : string; i, L : integer; Begin St :='Hom thuc tap'; L:=Length(St); For i := to L If (St[i] >= 'a') and (St[i] <= 'z') then St[i]:= Upcase (St[i]); Write (St); End -Chương trình in : a) Hom Nay Thuc Tap b) hom thuc tap c) Hom thuc tap (183) d) HOM NAY THUC TAP Câu 9: Khi chạy chương trình : Var St : String; i,L : integer; Begin St:='ABCD'; L := Length(St); For i:= L Downto write (St[i]); End -Chương trình in : a) DCAB b) ABCD c) 4321 d) DCBA Câu 10: Cho St là biến chuỗi và St:=’AAABAAB’; Sau thực hai lệnh : While St[1]=’A’ Delete(St,1,1); Write(St); Kết qủa in là: a) AABAAB b) BAAB c) BB d) AAA (184) 11.5 BÀI TẬP I Bài tập nâng cao lệnh lặp : Câu Nhập x thực, n nguyên  , tính gần đúng cosx : Câu *2 Nhập số nguyên dương N, cho biết số đó có bao nhiêu chữ số, và chữ số lớn là bao nhiêu Ví dụ: số N = 1275 có bốn chữ số, chữ số lớn là Câu Tính gần đúng giá trị Ln(x) , < x  , với sai số ss = 0.01, cách bỏ các số hạng có trị tuyệt đối < ss : Câu Tìm và in lên màn hình tất các số nguyên dương có ba chữ số (trong phạm vi từ 100 đến 999) cho tổng các bình phương các chữ số nó 25 Ví dụ :số N=304 có ba chữ số là 3, và 4, và 32+02+42 = 25 Tương tự số 500 Câu Nhập số N nguyên dương, tính : Câu *6 Nhập ngày, tháng, năm sinh bạn Từ đầu năm sinh đến ngày tháng năm sinh bạn có bao nhiêu ngày? Ví dụ, sinh ngày 17/2/1977 thì từ đầu năm 1977 đến ngày đó có 48 ngày Câu Nhập số N nguyên dương, tính S là tổng N số nguyên tố đầu tiên Ví dụ N=3 thì S=2+3+5=10 II Bài tập nâng cao mảng: Câu *8) Tìm số dương nhỏ dãy x1, x2, , xn Câu *9) Sắp xếp dãy x1, x2, , xn cho các số dương đứng trước theo thứ tự giảm dần, đến các số còn lại ( số âm và số 0) theo thứ tự tăng dần Ví dụ, nhập dãy 3, 0, 4, -5, 2, -1, 7, 0, -6, thành: 7, 4, 3, 2, -6, -5, -1, 0, Câu *10) Nhập dãy số nguyên dương x1, x2, , xn Tìm bội số chung nhỏ chúng Ví dụ dãy có bội số chung nhỏ là 60 (185) Câu *11) Nhập dãy số nguyên dương x1, x2, , xn Vẽ biểu đồ ngang và biểu đồ đứng cho dãy các dấu * Ví dụ dãy { 3, 5, 6, 2} có biểu đồ ngang và biểu đồ đứng sau: Câu 12) Nhập và in ma trận Am,n Cho biết hàng và hàng có giống không, không thì hãy hoán đổi hàng và hàng Ví dụ: ma trận bên trái đây có hàng và hàng không trùng nhau, sau hoán đổi hai hàng ta ma trận bên phải: Câu *13) Nhập và in ma trận Am,n Hãy hoán đổi các hàng ma trận A cho các phần tử cột lập thành dãy tăng Câu *14) Nhập và in ma trận Am,n Cho biết hàng nào A lập thành dãy tăng Cho biết hàng nào A lập thành dãy đối xứng Câu *15) Nhập và in ma trận Am,n Tìm số dương nhỏ ma trận Câu *16) Nhập và in ma trận Am,n các số nguyên dương Tìm bội số chung nhỏ tất các phần tử ma trận Câu 17) Nhập vào số nguyên N ( 1< N < 11) và ma trậ? vuông A cấp N có các phần tử là các số nguyên Tính : đó Aij là phần tử hàng i cột j ma trận A (186) -Tìm số lớn khu vực tam giác kể từ đường chéo phụ trở ngược lên góc trên bên trái ma trận A Ví dụ, ma trận bên, khu vực tam giác có số lớn là Dùng cấu trúc mảng, nhập danh sách N (0<N<50) sinh viên gồm Tên, Phái (nam/ nữ), và Ðiểm thi, phân loại đậu, rớt sau : Nếu Ðiểm thi  : Ðậu Nếu Ðiểm thi < 4.5 : Rớt Nếu 4.5 Ðiểm thi< 5: là nam thì Rớt, là nữ thì Ðậu In danh sách đã theo trật tự tăng Tên (sắp xếp theo thứ tự a,b,c, ), gồm các thông tin Tên, Phái, Ðiểm thi, và phân loại Câu *19) Dùng cấu trúc mảng, nhập danh sách N (0<N<50) chủ hộ gồm họ tên, số điện kế tháng trước và số điện kế tháng này Tính tiền điện cho hộ theo đơn gía: 100 kw đầu tiên có đơn gía 500đ/kw 50 kw có đơn gía là 600 đ/kw từ kw thứ 151 trở lên có đơn gía là 900 đ/kw In danh sách lên màn hình liệt kê người gồm họ tên, lượng điện tiêu thụ tháng và số tiền điện phải trả In tổng số tiền điện tất các hóa đơn III Bài tập chuỗi ký tự : Câu 20) Nhập chuỗi St, in St theo thứ tự đảo ngược Ví dụ : St = ‘ABCD’, in ‘DCBA’ Câu 21) Nhập chuỗi St, xây dựng chuỗi St1 gồm các ký tự St đảo ngược thứ tự Ðổi chuỗi St thành chữ hoa và?đổi chuỗi St1 thành chữ thường Ví dụ cho St=‘AbcD12’, thì St1=‘21DcbA’, sau đổi ta St= ‘ABCD12’ và St1=‘21dcba’ Câu 22) Nhập chuỗi St, kiểm tra chuỗi có đối xứng không Ví dụ: các chuỗi ‘BCD1DCB’ và ‘ABCCBA’ là đối xứng, còn ‘ABCDBA’ là không đối xứng Câu 23) Nhập chuỗi St, đếm xem chuỗi có bao nhiêu chữ a không phân biệt viết hoa hay viết thường, và cho biết vị trí các chữ a đó Ví dụ St=‘Anh van la quan trong’ có chữ a các vị trí 1, 6, 10, 14 Câu *24) Nhập chuỗi St, cho biết St có bao nhiêu ký số ‘0’, ‘1’, ‘2’, , ‘9’ loại Ví dụ St=‘13163’, in ra: có ký số 1, có ký số 3, có ký số 6, các loại khác không có (187) Câu 25) Nhập chuỗi St, xóa bỏ các ký tự trắng thừa đầu và cuối chuỗi, và cho hai từ có đúng ký tự trắng, đổi chuỗi thành chữ thường, riêng các chữ đầu từ thành chữ hoa Ví dụ : St =‘ Hom nAy tHUC taP ‘ In ra: ‘Hom Nay Thuc Tap’ Câu *26) Nhập chuỗi St, đếm xem St : có bao nhiêu chữ cái A,B,C, ,Z có bao nhiêu chữ số 0,1, 2, 3, , có bao nhiêu ký tự trắng có bao nhiêu các ký tự khác Trong bốn loại trên thì loại nào nhiều ? Câu 27) Nhập hai chuỗi St và St1 Cho biết chuỗi St1 xuất lần St, và các vị trí nào? Ví dụ St=‘pas12pas34’, chuỗi St1 =‘pas’ xuất lần các vị trí 1, Câu 28) Nhập ba chuỗi St, St1, St2 tìm xem chuỗi St có chứa chuỗi St1 không ?, có thì thay St1 St2 Ví du: cho St=‘ABC1234E’, St1=‘1234’ và St2 =‘*’ Sau thay ta St=‘ABC*E’ Câu 29) Nhập mảng gồm N tên các sinh viên Hãy chuẩn hóa tất các tên này, đổi chữ hoa hết, xếp và in lên màn hình theo thứ tự a, b, c, Ví dụ nhập năm tên: lan, an, anh, thanh, bich, in : AN, ANH, BICH, LAN, THANH Câu *30) Nhập chuỗi St gồm nhiều từ Giả thiết St có không qúa 20 từ, từ dài không qúa 10 ký tự Xây dựng mảng A chứa các từ St, với A[i] chứa từ thứ i St Sắp xếp và in các từ mảng A theo trật tự giảm độ?dài từ Ví dụ cho St=‘ Thanh da Nang’ thì : A[1]=‘Thanh’, A[2]= ‘pho’, A[3]=‘Da’, A[4]=‘Nang’ In ra: Thanh Nang Da Câu 31) Nhập số nguyên dương N, đổi số nhị phân (hệ đếm 2) tương ứng Ví dụ : N = 15, đổi 1111 Câu 32) Nhập số nguyên dương N, đổi số thập lục phân (hệ đếm 16) tương ứng : Ví dụ : N = 59, đổi 3B Bài 12 Chương trình con: hàm và thủ tục YÊU CẦU CỦA BÀI GIẢNG Nắm được: Khái niệm, cách khai báo thủ tục và hàm (188) Ðặc điểm giống và khác thủ tục và hàm Khái niệm tham số hình thức và tham số thực Các ví dụ thủ tục và hàm 12.1 KHÁI NIỆM VỀ CHƯƠNG TRÌNH CON Chương trình (subprogram) là đoạn chương trình có chức giải vấn đề chuyên biệt mà chương trình chính cần phải thực số lần ứng với các gía trị khác tham số Chẳng hạn, phải tính loạt các gía trị e1, e2, e3, , e10 thì ta nên viết chương trình có nhiệm vụ tính ex với x la đối số & đặt tên là EXP(x) Mỗi cần tính các gía trị e1, e2, , e10 , ta cần gọi tên chương trình đó thay x giá trị cụ thể 1, 2, ,10 Tương tự thế, cần nhập liệu cho hai ma trận A và B, thay vì phải viết hai đoạn chương trình nhập riêng cho A và cho B thì ta cần viết chương trình có nhiệm vụ nhập liệu cho ma trận X Sau đó chương trình chính, để nhập liệu cho A, ta gọi chương trình đó thay X A, và để nhập liệu cho B, ta gọi chương trình đó thay X B Như chương trình thay cho hay nhiều đoạn chương trình có chất giống Việc sử dụng chương trình không có tác dụng làm cho chương trình chính bớt rườm rà, bớt dài dòng mà còn đặc biệt có ý nghĩa việc tổ chức chương trình Khi phải giải bài toán lớn, người ta tìm cách chia nó thành nhiều bài toán nhỏ Mỗi bài toán nhỏ giải riêng rẽ chương trình dễ dàng phải kiểm tra lỗi và kiểm tra thuật toán Việc còn lại là ghép các chương trình này để tạo thành chương trình lớn, đó là chương trình chính Số lệnh thân chương trình chính không nhiều, chủ yếu là các lời gọi chương trình con, vì người thảo chương dễ có cái nhìn tổng quan toàn chương trình trước xem xét chương trình cách chi tiết Ðiều này tương tự dây chuyền sản xuất công nhiệp, người ta lắp ráp các sản phẩm ( xe máy, ô tô, ti vi, ) từ các phụ tùng và các bán sản phẩm chế tạo sẵn từ nơi khác chuyển đến mà không cần phải tìm hiểu xem họ đã chế tạo nào Có hai loại chương trình là hàm và thủ tục Sự khác hàm và thủ tục là chỗ: hàm luôn luôn trả gía trị thông qua tên hàm và đó có thể sử dụng hàm sử dụng biểu thức, còn thủ tục thì không trả giá trị nào qua tên thủ tục và nó sử dụng lệnh đơn giản 12.2 HÀM (Function) 12.2.1 Các đặc trưng hàm: Các yếu tố đặc trưng cho hàm gồm có: Tên hàm Kiểu liệu các tham số Kiểu liệu gía trị hàm (189) Ví dụ : Hàm Sqrt(x): cho hai x Tên hàm là Sqrt, tham số x là nguyên hay thực còn gía trị hàm kiểu thực, ví dụ Sqrt(4)=2.0 Hàm Chr(k): cho ký tự có mã là k Tên hàm là Chr, tham số k kiểu nguyên còn gía trị hàm kiểu ký tự, ví dụ Chr(65)=‘A’ Hàm Odd(k): cho True hay False tùy theo k là lẻ hay chẵn Tên hàm là Odd, tham số k kiểu nguyên và gía trị hàm kiểu lôgic? ví dụ Odd(4)=False Hàm Copy( St, k, n): cho chuỗi gồm n ký tự St tính từ vị trí k Tên hàm là Copy, có ba tham số là St kiểu chuỗi, k và n kiểu nguyên, và gía trị hàm kiểu chuỗi? ví dụ Copy(‘ABCD’, 2, 3) = ‘BCD’ Hàm Readkey : không có tham số, gía trị hàm kiểu ký tự, hàm nhận ký tự gõ từ bàn phím Tóm lại, hàm có thể không có tham số có đến nhiều tham số, hàm luôn trả gía trị Các tham số luôn luôn phải để cặp nháy đơn ( ), có nhiều tham số thì chúng phải phân cách dấu phẩy Mỗi gọi hàm (call) ta phải cho các tham số các gía trị cụ thể phù hợp với kiểu liệu tham số Ví dụ: For k:=1 to 10 S := S+ Sqrt(k); y:= 3* Sqr(2) - Sin(pi/4) ; Write( Chr(65) ); Cần phân biệt hai trạng thái các tham số: trạng thái dùng để mô tả hàm và trạng thái để gọi hàm Khi khai báo hàm, các tham số mang tính tượng trưng, nên gọi là tham số hình thức, còn gọi hàm, các tham số phải là các biến hay các gía trị cụ thể nên gọi là các tham số thực Ví dụ, viết Sqrt(x) thì x là tham số hình thức, nó đại diện cho gía trị nào đó Còn gọi hàm y:=Sqrt(4); thì là tham số thực 12.2.2 Khai báo hàm tự viết: Tất các hàm có sẵn Turbo Pascal gọi là các hàm chuẩn, chúng có thể sử dụng mà không cần phải khai báo Tuy nhiên số lượng các hàm chuẩn thường không đáp ứng yêu cầu đa dạng người sử dụng, cho nên thảo chương, ta thường phải tự xây dựng thêm các hàm Các hàm tự viết cần phải khai báo, theo cú pháp sau: Function Tênhàm(tênthamsố: kiểuthamsố : kiểugíatrị ; { Các khai báo dùng hàm } Const (190) Type Var Begin {Các lệnh hàm} End; Tên hàm và tên tham số phải đặt theo đúng quy tắc tên Thông thường tên hàm nên đặt cho gợi nhớ gía trị mà nó chứa Tên tham số mức khai báo này mang tính tượng trưng nên gọi là tham số hình thức Nếu có nhiều tham số hình thức thuộc cùng kiểu liệu thì chúng viết phân cách dấu phẩy, ví dụ: Function F(x, y : Integer) :Real; đây hai tham số x và y cùng kiểu Integer Nếu các tham số có kiểu liệu khác thì phải khai báo riêng và dùng dấu chấm phẩy để phân cách, ví dụ: Function F( x: Integer ; y: Real): Real; đây tham số x có kiểu Integer, còn tham số y có kiểu Real Như đã nói, hàm là chương trình nên nó có đầ? đủ các thành phần chương trình bình thường, tức là có thể có khai báo (Const), khai báo kiểu liệu (Type) và khai báo biến (Var) Thân hàm là các lệnh đặt hai từ khóa Begin và End , kết thúc dấu chấm phẩy ";" không phải là dấu chấm Chú ý Trong hàm không có khai báo sử dụng thư viện chuẩn (Uses) 12.2.3 Cấu trúc chương trình Pascal có hàm tự viết: Một chương trình có chứa hàm tự viết gọi là chương trình chính, còn hàm gọi là chương trình Khai báo hàm tự viết phải để sau phần khai báo biến VAR và trước BEGIN thân chương trình chính Tóm lại cấu trúc chương trình có chứa hàm tự viết là sau: PROGRAM TênCtchính; Uses { khai báo dùng thư viện chuẩn} Const { khai báo hằng} Type { khai báo kiểu liệu mới} Var { khai báo biến ctrình chính} (191) Function Tênhàm(tênthamsố: kiểuthamso? : kiểugíatrị; { Các khai báo Const, Type, Var dùng hàm } Begin {Các lệnh hàm} End; BEGIN { Các lệnh chương trình chính} END 12.2.4 Kiểu liệu tham số và gía trị hàm: Kiểu liệu kết qủa hàm không the?là mảng (array), ghi (record), tập hợp (set) hay tập tin (file) Khai báo hàm đây là sai: Function F( x: Integer) : array[1 10] of Real; Kiểu liệu kết qủa hàm có thể là các kiểu đơn giản, chuỗi, hay trỏ Nếu là kiểu liệt kê, đoạn hay chuỗi (trừ kiểu String) thì phải định nghĩa trước thông qua từ khóa Type Ví dụ, các khai báo sau là sai: Function F( x: Real) : String[20]; Function F( x: Real) : 31; Mà phải định nghĩa kiểu trước : Type Str20= String[20]; Ngay = 31; khai báo: Function F( x: Real) : Str20; Function F( x: Real) : Ngay; Tuy nhiên, với kiểu String thì khai báo sau là đúng: Function F( x: Real) : String; (192) Kiểu liệu tham số hàm và thủ tục thì không hạn chế Nhưng là kiểu chuỗi (trừ kiểu String) hay kiểu tự xây dựng thì phải định nghĩa trước từ khóa Type Ví dụ, khai báo sau là sai: Function F( x : array[1 10] of Real) : Integer ; Function F( St : String[20]) : Char ; Mà phải định nghĩa kiểu trước : Type Kmang =Array[1 10] of Real; Kstr20= String[20]; khai báo: Function F( x : Kmang) : Integer ; Function F( St : Kstr20) : Char ; Tuy nhiên, với kiểu String thì khai báo sau là đúng: Function F( St : String) : Boolean ; 12.2.5 Các ví dụ : Ví dụ 12.1: Nhập dãy các số thực x1, x2, , xn, tính tổng : Phân tích: Giả sử đã có hàm Canba(z) tính bậc ba z, tức là : đó, tổng S tính sau: S:=0; For i:=1 to N S:=S + Canba( x[i] ); Ở đây hàm Canba tính N lần ứng với các tham số thực sư?là các gía trị x[i], i=1, , N Vấn đề còn lại là phải viết hàm tính ba z Hàm này có tên là Canba, tham số z kiểu thực, và gía trị hàm kiểu thực, nó xây dựng sau: FUNCTION Canba( z: Real) :Real; { Hàm tính bậc ba z} (193) Var F: Real; Begin If z=0 then F:= 0; If z>0 then F:= exp( 1/3*Ln(z) ); If z<0 then F:= - exp( 1/3*Ln(-z) ); Canba:=F ; End; Ðặt đoạn khai báo hàm trên đây vào trước phần thân chương trình chính, ta chương trình đầy đủ sau đây: PROGRAM VID12_1; Var x : Array[1 20] of Real; S : Real; N, i : integer; FUNCTION Canba( z: Real) :Real; { Hàm tính bậc ba z} Var F: Real; Begin If z=0 then F:= 0; If z>0 then F:= exp( 1/3*Ln(z) ); If z<0 then F:= - exp( 1/3*Ln(-z) ); Canba:=F ; End; BEGIN { vào chương trình chính} Repeat (194) Write(‘ nhap N: ‘); Readln(N); Until ( N>0) and ( N<21); S:=0; For i:=1 to N begin Write(‘nhap x[‘, i, ‘]:’); Readln(x[i]); S:=S + Canba( x[i] ); end; Writeln(‘ S= ‘, S:8:2); Readln; END Chạy <VD12_1.EXE> Chép tập tin nguồn <VD12_1.PAS> Ví dụ 12.2: Nhập chuỗi St, đổi tất các ký tự chuỗi thành chữ thường, chẳng hạn St=‘ABcdE2’ thì đổi thành ‘abcde2’ Giả sử đã có hàm Chuthuong(ch) đổi ký tự ch từ chữ hoa chữ thường, ví dụ Chuthuong(‘A’)=‘a’, đó để đổi tất các ký tự chuỗi St chữ thường ta dùng lệnh: For i:=1 to Length(St) St[i]:= Chuthuong(St[i]); Như vậy, ta phải viết hàm Chuthuong(ch) có tham số ch kiểu ký tự và gía trị hàm kiểu ký tự, và đặt khai báo hàm này vào trước phần thân chương trình chính, sau: PROGRAM VIDU12_2; Var St : String; N, i : integer; FUNCTION Chuthuong( ch: Char):Char; { Hàm đổi chữ hoa chữ thường} (195) Var C: Char; Begin If ( ch>=‘A’ ) and ( ch<=‘Z’) then C:=Chr( ord(ch)+32 ) else C:=ch; Chuthuong:=C; End; BEGIN { vào chương trình chính} Write(‘ Nhập chuỗi chữ hoa St : ‘); Readln(St); N:=Length(St); For i:=1 to N St[i]:=Chuthuong( St[i] ); Writeln(‘ St = ‘, St); Readln; END Chạy<VD12_2.EXE> Chép tập tin nguồn <VD12_2.PAS> Ví dụ 12.3: Nhập số N nguyên dương và số thực x bất kỳ, tính: Ta viết : Vậy việc tính S quy việc tính các số hạng Ui thực phép cộng dồn Ui vào S (196) Ðể tính Ui ta nhận thấy tử số (x+i)i có dạng tổng quát là zk còn mẫu số (2i-1)! có dạng tổng quát là k! Thành ra, đã có hai hàm : * Hàm Lt(z, k) tính zk, tức là Lt(z, k)=zk * Hàm Gt(k) tính k!, tức là Gt(k)=k! thì việc tính S thực các lệnh: S:= Lt(Pi, 2)/4; For i:=1 to N S :=S + Lt(x+i, i)/Gt(2*i -1); Trong lệnh gán đầu tiên, hàm Lt(z, k) tính ứng với các tham số thật là z=Pi và k=2 Trong lệnh For, bước lặp ta có i là số xác định, và hàm Lt(z, k) tính ứng với các tham số thật là z=x+i và k=i Tương tự, hàm Gt(k) tính ứng với k=2*i-1 Dưới đây là chương trình cụ thể : PROGRAM VIDU12_3; Var S, x : Real; N, i : Integer ; Function Lt(z : Real ; k: Byte) : Real ; { hàm tính Lt=zk } Var j : Byte; Q: Real; Begin Q:=1; For j:=1 to k Q:=Q*z; Lt:=Q; End; Function Gt( k: Byte) : Real; { hàm tính Gt= k!} (197) Var i : Byte; Q: Real; Begin Q:=1; For i:=1 to k Q:=Q* i; Gt:=Q; End; BEGIN { Chương trình chính } Repeat Write(‘ Nhập N và x :’); Readln(N, x); Until ( N>0); S:= Lt(Pi, 2)/4; For i:=1 to N S:= S + Lt(x+i, i)/Gt(2*i -1); Writeln(‘S= ‘, S:10:4); Readln; END Chạy<VD12_3.EXE> Chép tập tin nguồn <VD12_3.PAS> 12.2.6 Các chú ý viết hàm: Ta chọn chương trình là hàm cần nhận lại gía trị thông qua tên hàm, nhờ đó có thể dùng tên hàm các biểu thức Ví dụ, vì Gt(4) là gía trị nên ta có thể viết : k:= Gt(4) - ; Write( ‘ Giai thừa là ‘, Gt(4) ); Vì tên hàm chứa gía trị hàm nên thân hàm phải có ít lệnh gán : TênHàm:= Biểuthức ; (198) Thông thường ta dùng biến trung gian để tính gía trị hàm , xong xuôi gán biến trung gian đó cho tên hàm trước kết thúc hàm Ở ví dụ 12.1, hàm Canba ta dùng biến F để tính gía trị hàm, sau cùng gán Canba:=F; trước kết thúc hàm Về phong cách lập trình, hàm nên tránh dùng các lệnh nhập hay in liệu (Readln, Write) Các tham số hình thức chính là các liệu phục vụ cho các tính toán hàm, chúng có gía trị cụ thể gọi hàm Việc nhập liệu hay in kết qủa thường để thân chương trình chính 12.3 THỦ TỤC (Procedure) 12.3.1 Thủ tục và cách khai báo: Giống hàm, thủ tục là chương trình con, song thủ tục khác hàm chỗ: hàm luôn trả gía trị thông qua tên hàm thì thủ tục lại không trả về?một gía trị nào thông qua tên gọi nó Một thủ tục thực chất là nhóm các lệnh xếp theo trình tự định có tác dụng giải nhiệm vụ cụ thể, và đặt cái tên để gọi Trong đời sống hàng ngày, ta thường nghe nói đến thủ tục nhập học sinh viên, thủ tục mua bán nhà đất, thủ tục xuất cảnh, thủ tục nhập cảnh,.v.v thủ tục đó là dãy có trình tự các công việc phải làm Thủ tục Readln(x, y, z) có nhiệm vụ nhập các gía trị từ bàn phím cho các biến x, y, z Thủ tục Write(x, y, z) in gía trị x, y, z Thủ tục Gotoxy(x, y) định vị trỏ vào toạ độ cột x, dòng y trên màn hình Thủ tục Clrscr thì đơn giản là xóa màn hình v.v Như thủ tục có thể không có tham số có từ đến nhiề? tham số Khi gọi thực thủ tục, ta viết tên thủ tục đó và thay các tham số hình thức các tham số thực sự, kết thúc dấu chấm phẩy ";" Ví dụ, a, b là hai biến đã khai báo chương trình thì để nhập liệu cho hai biến a, b ta viết : Readln(a, b); Ðể in biểu thức 4+5*6 lên màn hình, ta viết : Write(4+5*6); Ðể đặt trỏ vào vị trí cột 8, dòng trên màn hình ta viết: Gotoxy(8, 2); Như vậy, lời gọi thủ tục là lệnh đơn giản Do thủ tục không trả gía trị nào thông qua tên gọi nó nên tên thủ tục không thể đứng các biểu thức Ví dụ các lệnh sau là sai cú pháp: St1 := Delete( St, 1, 1); Write( Val(‘123’, x, k) ); (199) vì Delete và Val là hai thủ tục không phải là hai hàm Ngoài các thủ tục chuẩn đã có sẵn Turbo Pascal, người thảo chương có thể tự xây dựng các thủ tục phải khai báo theo cú pháp sau: Procedure Tênthủtục( tênthamsố : kiểuthamsố ) ; { Các khai báo Const, Type, Var dùng thủ tục } Begin {Các lệnh thủ tục } End; Ðoạn khai báo trên phải đặt sau phầ? khai báo VAR và trước BEGIN thân chương trình chính 12.3.2 Các ví dụ thủ tục : Ví dụ 12.4: Giải và biện luận phương trình ax+b= với a=4.5, b=13.5, và với các cặp a, b tạo a=-1, a=0, a=1, b=0, b=1, b=2 Ta viết thủ tục có nhiệm vụ giải và biện luận phương trình ax+b=0 với hai tham số a, b tùy ý, và gọi thực thủ tục này 10 lần ứng với các gía trị cụ thể a, b cho gỉa thiết PROGRAM VIDU12_4; { Giải phương trình AX+B=0 thủ tục} Uses Crt; Var i, j: integer; Procedure Giaipt (a, b: Real); Begin Writeln(' -Giải phương trình : ' , a:4:1, 'x+' , b:4:1, '=0'); If a<>0 then Writeln(' Nghiem x=', -b/a:4:2) else if b<>0 then Writeln(' Vo nghiem') else (200) Writeln(' Vo so nghiem'); End; BEGIN { Thân chương trình chính } Clrscr; Writeln(' KẾT QỦA GIẢI CÁC P.TRÌNH:' ) ; Giaipt (4.5, 13.5); For i:=-1 to For j:=0 to Giaipt (i, j); Readln; END Chạy<VD12_4.EXE> Chép tập tin nguồn <VD12_4.PAS> Khi gọi Giaipt (4.5, 13.5); là ta yêu cầu máy thực thủ tục Giaipt với tham số a=4.5 và b=13.5 Hai vòng lặp For xác định cặp gía trị i, j cụ thể, và lần lại gọi thực thủ tục Giaipt với tham số a=i, b=j tương ứng : For i:=-1 to For j:=0 to Giaipt (i, j); Do tách riêng việc giải phương trình ax+b=0 thành thủ tục nên số lệnh thân chương trình chính giảm đi, bật thuật toán chính chương trình Ở đây, ta chọn chương trình Giaipt là thủ tục không phải là hàm vì phương trình ax+b=0 có thể vô nghiệm vô số nghiệm (khi a=0) Thành ta không tìm gía trị thích hợp để gán cho tên hàm Vậy kết qủa giải phương trình phải xuất chương trình con, đó là công việc thủ tục Ví dụ 12.5: Nhập vào mảng A1, A2, ,An, xếp dãy tăng in dãy lên màn hình Có thể chia bài toán thành ba công việc lớn sau: a-Nhập dãy A1, A2, ,An, b-Sắp xếp dãy A1, A2, ,An, tăng c-In dãy A1, A2, ,An, lên màn hình (201) Mỗi công việc a, b, c thuộc lãnh vực riêng nên có thể xây dựng thành các thủ tục độc lập với Ðể liên kết chúng lại, chương trình chính, ta cần gọi tên các thủ tục này theo thứ tự a, b, c với các tham số thích hợp Khi thiết kế thủ tục xếp dãy tăng, có việc phải làm nhiều lần là đổi chỗ hai phần tử A[i] và A[j] nên có thể xây dựng thành thủ tục gọi tên là Ðổi chỗ, nó lại là chương trình thủ tục xếp Chương trình cụ thể sau: PROGRAM VIDU12_5; { Sắp xếp dãy A tăng dần thủ tục } Uses CRT; Type Kmang = Array[1 20] of Real; Var N : Integer; A: Kmang; Procedure Nhap(Var X: Kmang ; N: Integer ; ten: Char ); Var i : Integer; Begin For i:=1 to N { nhập mảng X } begin Write(‘Nhập ‘, ten , ‘[‘ , i , ‘]: ‘); Readln(X[i]); end; End; Procedure SapTang( Var X : Kmang ; N: Integer); { Sắp dãy X tăng} Var i, j : Integer; (202) Procedure Doicho(Var u, v : Real) ; { hoán vị các gía trị u và v} Var Tam: Real; Begin Tam:=u; u:=v; v:=Tam; End; { Hết Doicho } Begin { Vào Saptang } For i:=1 to N-1 For j:=i+1 to N If X[i]>X[j] then Doicho(X[i], X[j]) ; End; { Het Saptang } Procedure Inday( Chugiai: String ; X: Kmang ; N: Integer); { In dãy X lên màn hình } Var i : Integer; Begin Writeln(Chugiai); For i:=1 to N write(X[i]:5:1); writeln; End; BEGIN { chương trình chính } Clrscr; Repeat Write(‘ Nhập số phần tử N : ‘); Readln(N); (203) Until (N>0) and ( N<21); Nhap( A, N, ‘A’ ); Inday( ‘ Dãy chưa là: ‘, A, N); SapTang( A, N); Inday( ‘ Dãy đã tăng là: ‘ , A, N); Readln; END Chạy<VD12_5.EXE> Chép tập tin nguồn <VD12_5.PAS> Thủ tục Nhap có ba tham số hình thức là X, N và ten, nhiệm vụ nó là nhập liệu cho mảng X gồm N phần tử Tương tự, thủ tục Saptang có nhiệm vụ xếp N phần tử dãy X thành dãy tăng Thủ tục Inday in N phần tử dãy X sau đã in lời giải thích chứa tham số chugiai Thủ tục Saptang chứa thủ tục là Doicho, có nhiệm vụ hoán vị các gía trị hai biến u, v Doicho là chương trình thủ tục Saptang Khi tham số đượ? khai báo chương trình con, nó có thể có không có từ khóa Var đằng trước Ví dụ thủ tục Saptang, tham số X sau từ khóa Var, còn tham số N thì không X gọi là tham số biến còn N gọi là tham số trị Sự khác hai loại tham số này trình bày kỹ phần sau (204) 12.4 CÂU HỎI TRẮC NGHIỆM Câu 1: Khai báo đầu thủ tục nào đúng: a) Procedure TT(x :Integer):Real; b) Procedure TT(x: Integer ; x: Real); c) Procedure TT(x); d) Procedure TT(x :Integer ; Var a:Real) ; Câu 2: Khai báo đầu hàm nào đúng: a) Function F( x: real ); b) Function F( x: integer) : Real; c) Function F(x) : Real; d) Function F( St: String[20]) : Integer ; Câu 3: Khai báo đầu chương trình nào đúng: a) Function F : Boolean ; b) Procedure TT : Integer ; c) Proceduce TT( k : Integer ) d) Function F ( ch: Char) ; Câu 4: Cho khai báo biến và khai báo đầu hàm F: Var x, S : Real; n: Integer ; FUNCTION F( y: Real; m : Integer) : Real; - Lời gọi hàm nào đây là đúng : a) S:= F(n, x); (205) b) S:= F( x, n); c) S:= F( n); d) S:= F( x); Câu 5: Cho khai báo biến và khai báo đầu thủ tục TT sau: Var x, S : Integer ; ch : Char ; Procedure TT(y : Integer; kytu : char); -Lệnh gọi thủ tục nào đúng : a) S := TT(x, ch) ; b) TT(ch, x) ; c) TT ; d) TT(x, ch) ; Câu 6: Khi chạy chương trình : Procedure TINHS; Var i, S : integer; Begin S:=1; For i:=1 to S:=S*i; Write(S); End; BEGIN TINHS; END -Kết qủa in : (206) a) 12 b) c) 24 d) Câu 7: Cho khai báo hàm : Function F( x : Integer) : Integer; Begin F:=x*x; End; Gía trị F(2+1) là : a) b) c) d) Câu 8: Cho khai báo hàm : Function F( x, y : Integer) : Integer; Begin If x< y then F:=x else F:=y; End; Gía trị F(9, 0) là : a) b) c) (207) d) Câu 9: Cho khai báo hàm : Function F( k : Integer) : Integer; Begin F:=2*k+1; End; Gía trị hàm F( F(1) ) là : a) b) c) d) Câu 10: Khi chạy chương trình : Procedure TT( a : Integer) ; Begin Repeat a:= 2* a ; Until a>15 ; Write(a); End; BEGIN TT(2) ; END -Kết in là: a) (208) b) 16 c) 32 d) 12.5 BÀI TẬP Câu 1) Viết hàm tính k! với k nguyên dương Nhập n, k ( n  k ) từ bàn phím, sử dụng hàm đó tính số tổ hợp chập k n theo công thức : Câu 2) Xây dựng hàm LT(x, k) để tính lũy thừa xk số thực x với k nguyên dương Nhập số x thực và số N nguyên >0, sử dụng hàm Lt(x,k) tính : Câu 3) Sử dụng hai hàm Lt(x,k) =xk và Gt(k)=k! tính gần đúng: đó các số n nguyên dương, x thực nhập từ bàn phím Câu *4) Nhiệt độ F (Fahrenheit), và nhiệt độ C (Cecius) liên hệ theo công thức : Viết chương trình, nhập vào dãy các độ F1, F2, , Fn tùy ý , xếp dãy này theo trật tự tăng, Fi đó hãy tính và in lên màn hình các độ C tương ứng, trình bày thành hai cột : ÐỘ F ÐỘ C Sau đó, nhập vào dãy các độ C1, C2, , Cn tùy ý , xếp dãy này theo trật tự tăng, Ci đó hãy tính và in lên màn hình các giá trị độ F tương ứng, trình bày thành hai cột : ÐỘ C ÐỘ F Yêu cầu, chương trình có hai hàm, và hai thủ tục : Hàm tính độ C theo độ F Hàm tính độ F theo độ C (209) Thủ tục xếp dãy tăng Thủ tục in lên màn hình Câu 5) Viết hàm tìm bội số chung nhỏ hai số nguyên dương a và b Nhập vào N số nguyên dương A1, , An, dùng hàm nói trên tìm bội số chung nhỏ N số đó Câu *6) Cho hàm F(x) = x3 - Viết chương trình nhập vào hai số thực a, b và số nguyên n : 10 < n < 50 Tính tích phân xác định hàm F(x) trên đoạn [a,b] theo công thức hình thang sau : đó : và yi = F( a + ih ) Yêu cầu : có hàm tính gía trị F(x) theo tham số x Bài 13 Chương trình (tiếp theo) YÊU CẦU CỦA BÀI GIẢNG Nắm : Khái niệm tham số trị và tham số biến Ðặc điểm truyền tham số thông qua tham số trị và tham số biến Khái niệm biến toàn cục và biến địa phương Phạm vi tác dụng các khai báo chương trình Pascal Khái niệm đệ quy 13.1 THAM SỐ TRỊ VÀ THAM SỐ BIẾN Trong khai báo đầu chương trình con, các tham số hình thức có từ khóa Var đứng trước gọi là tham số biến, ngược lại, không có từ khóa Var trước thì gọi là tham số trị Ví dụ, khai báo hàm tính lũy thừa zk, ta viết : (210) Function Lt(z : Real ; k: Byte) : Real; thì z và k là các tham số trị hình thức Còn theo khai báo thủ tục Doicho : Procedure Doicho(Var u, v : Real) ; thì u và v là các tham số biến hình thức 13.1.1 Tham số trị : Tham số trị hình thức cấp ô nhớ riêng chương trình gọi và bị xóa bỏ chương trình chạy xong Nó coi biến địa phương, nhận gía trị ban đầu là tham số thực chuyển đến từ chương trình chính qua lời gọi chương trình Sau đó chương trình có thể thay đổi giá trị tham số trị hình thức bên chương trình con, song điều đó không làm thay đổi gía trị tham số thực Trong lời gọi chương trình các tham số trị thực có thể là biến, hằ?g hay biểu thức Ví dụ, muốn tính S= 43, ta viết : S:= Lt(4, 3); : x:=4; S:= Lt(x, 2+1); đó x là biến kiểu thực Cách thức hoạt động lệnh S:= Lt(x, 2+1); là sau: Ðầu tiên các tham số hình thức z và k khởi tạo giá trị ban đầu z:=x; và k:=2+1; kết qủa là z=4 và k=3 Kế đó các lệnh hàm Lt tính toán zk và gán kết qủa cho tên hàm, nên Lt=43 Gía trị này gán tiếp cho S Trước và sau thực chương trình con, gía trị tham số thực x không bị thay đổi, x có gía trị là Vậy, các biến truyền vào chương trình dạng tham số trị thì không bị thay đổi Nói cách khác, thay đổi tham số trị hình thức chương trình không làm thay đổi gía trị tham số thực tương ứng truyền vào từ chương trình chính 13.1.2 Tham số biến : Trong lời gọi chương trình các tham số biến thực có the?là biến, không the?là hằ?g hay biểu thức (211) Ví dụ, các lệnh sau đây là sai : Doicho(3, 4); { Sai vì và là các hằng} Doicho(a+1, b); { Sai vì a+1 là biểu thức} Giả sử chương trình chính có hai biến thực a, b có gía trị a=4 và b=3 Ðể hoán đổi gía trị a và b ta dùng lệnh: Doicho(a, b); Vì u và v là các tham số biến hình thức nên chương trình đồng u với a và đồng v với b Mọi thay đổi tham số u chương trình là thay đổi chính biến a, tương tự, thay đổi tham số v là thay đổi chính biến b Kết qủa là trước gọi thủ tục Doicho(a,b) thì a=3, b=4, sau thực thủ tục xong thì a=4, b=3 Vậy, các biến truyền vào chương trình dạng tham số biến thì thay đổi theo tham số biến hình thức tương ứng chương trình Thông thường, ta dùng tham số biến muốn nhận lại gía trị sau thực chương trình Bây ta hiểu thủ tục Saptang thì N là tham số trị còn X là tham số biến: Procedure SapTang( Var X : Kmang ; N: Integer); N là số phần tử mảng X thì không cần thay đổi, còn mảng X thì lại cần thay đổi để trở thành dãy tăng Nếu ta bỏ từ khóa Var trước X đi, tức là: Procedure SapTang( X : Kmang ; N: Integer); thì lệnh : Saptang(A, N); không làm thay đổi dãy A Thực chất truyền tham số các tham số biến là truyền địa Chương trình dùng các ô nhớ chính các biến đượ? truyền vào dạng tham số biến Ví dụ 13.1: Trong chương trình đây, thủ tục TT có hai tham số a và b : a là tham số trị còn b là tham số biến Hãy xem thay đổi gía trị hai biến x, y chương trình chính trước và sau gọi thủ tục TT: PROGRAM VIDU13_1; Var x, y: Integer; PROCEDURE TT( a : integer ; Var b : integer); (212) Begin a:=a+6; b:=b+8; Writeln(‘a= ’, a); Writeln(‘b= ’, b); End; BEGIN x:=4; y:=7; TT(x,y); {14} Writeln(‘x= ’, x); {15} Writeln(‘y= ’, y); {16} Readln; END Chạy<VD13_1.EXE> Chép tập tin nguồn <VD13_1.PAS> Trước gọi thủ tục TT thì x=4, y=7 Khi gọi thủ tục TT(x, y); thì các tham số hình thức a, b gán a:=x; b:=y; nên a=4, và b=7 Các lệnh thủ tục a:=a+6; và b:=b+8; làm thay đổi các tham số a và b : a=10, b=15, và đó hai lệnh: Writeln(‘a= ’, a); in a = 10 Writeln(‘b= ’, b); in b = 15 Thực xong thủ thục TT, máy trở lại chương trình chính làm tiếp các lệnh {15} và {16} : Writeln(‘x= ’, x); in x = Writeln(‘y= ’, y); in y =15 Như vậy, x truyền vào chương trình thông qua tham số trị a nên thay đổi a chương trình không ảnh hưởng gì đến x Ngược lại, biến y truyền vào chương trình thông qua tham số biến b nên thay đổi b thủ tục TT kéo biến y thay đổi theo (213) Tính chất trên đây tham số biến cho phép khai thác thêm các khả thủ tục và hàm Ta biết thủ tục không trả gía trị nào thông qua tên nó, còn hàm thì trả gía trị qua tên hàm Song chương trình hoàn toàn có thể trả hai hay nhiều gía trị thông qua các tham số biến, ví dụ 13.2 Ví dụ 13.2: Chương trình sau nhập vào hai cạnh a, b hình chữ nhật và sử dụng thủ tục để tính diện tích và chu vi PROGRAM VIDU13_2; { Tính diện tích S và chu vi L HCN theo cạnh a, b} Var a,b, S, L: Real; Procedure TINH( c1, c2 : Real ; Var DT, CV : Real); { Tính diện tích DT và chu vi CV theo hai cạnh c1 và c2} Begin DT:=c1*c2; CV:=2*(c1+ c2); End; BEGIN Write(‘ Nhập hai cạnh a, b: ‘); Readln(a,b); TINH(a, b, S, L); {12} Writeln(‘Dien tích= ’, S:4:1); Writeln(‘Chu vi = ’, L:4:1); Readln; END Chạy <VD13_2.EXE> Chép tập tin nguồn <VD13_2.PAS> Vì thủ tục TINH cần phải trả hai gía trị diện tích và chu vi nên ta khai báo hai tham số biến là DT và CV Trong chương trình chính, ta khai báo hai biến tương ứng là S và L Sau nhập hai cạnh a, b và gọi thủ tục : (214) TINH(a, b, S, L); {12} thì c1:=a; c2:=b; biến S đồng với DT, biến L đồng với CV Thành ra, tính diện tích DT và chu vi CV thì S và L tính ( S=DT, L=CV ) Khi thực xong thủ tục TINH, các tham số c1, c2, DT, CV không tồn nhớ nữa, song hai biến S và L còn tồn kết thúc chương trình Vì thế, chương trình chính, ta in S và L, không in DT và CV 13.2 PHẠM VI TÁC DỤNG CỦA CÁC KHAI BÁO 13.2.1 Biến toàn cục và biến địa phương : Một chương trình có chứa hàm hay thủ tục gọi là chương trình chính, thủ tục hay hàm gọi là chương trình Vì chương trình là chương trình nên chương trình có khai báo biến, khai báo hằng, v.v., có khai báo chương trình riêng nó, Các biến khai báo chương trình chính gọi là biến toàn cục (global variable), chúng dùng nơi kể từ lúc khai báo kết thúc chương trình Các biến khai báo chương trình gọi là biến địa phương (local variable) Sở dĩ gọi là địa phương vì chúng có tác dụng chương trình nơi nó khai báo mà thôi Các tham số trị hình thức chương trình là biến địa phương Các biến địa phương tồn thời gian chương trình thực hiện, chương trình thực hiên xong thì các biến địa phương bị xóa khỏi nhớ Trong ví dụ 12.5 ( Bài 12 ), biến N và A là các biến toàn cục, còn biến Tam là biến địa phương thủ tục Doicho, nó có tác dụng thủ tục Doicho mà thôi Tương tự, biến j là biến địa phương thủ tục Saptang Mỗi thủ tục Nhap, Saptang và Inday có biến địa phương tên là i, chúng trùng tên song nhớ chúng là ba ô nhớ khác nhau, có phạm vi tác dụng khác Ví dụ 13.3 : Xét chương trình đây : Program VIDU13_3; {1} Var {2} x: Integer; {3} Procedure TTUC1; {4} Var {5} y: Integer; Begin y:=x+5; Writeln(y); {6} {7} {8} {9} (215) End; {10} { hết TTUC1 } BEGIN {11} x:=10; {12} TTUC1; {13} Writeln(y); {14} { lệnh này bị lỗi} Readln; END {15} {16} Chương trình gồm 16 dòng đánh số từ {1} đến {16} Biến x là toàn cục nên có phạm vi tác dụng từ dòng {3} đến dòng {16} Biến y là biến địa phương TTUC1 nên có phạm vi tác dụng từ dòng {6} đến dòng {10} Lệnh Writeln(y); dòng {9} in số 15, còn lệnh Writeln(y); dòng {14} lại bị lỗi Thật vậy, sau thực lệnh {12} gán x:=10; dòng {13} gọi TTUC1 và điều khiển chuyển đến dòng {4} Các dòng {5} {6} cấp ô nhớ cho biến y địa phương, dòng {8} gán y:=x+5; nên y=15 và dòng {9} in gía trị 15 y Ðến đây, TTUC1 kết thúc và biến y bị xóa khỏi nhớ, điều khiển trả cho lệnh {14} chương trình chính, vì y đã bị xóa nên không thể in được, và máy báo lỗi 13.2.2 Phạm vi tác dụng các khai báo : Hình 13.1 Phạm vi tác dụng hay tầm tác dụng biến (hay hằng, kiểu liệu, chương trình con) là khu vực mà đó nó có thể sử dụng được, ngoài khu vực đó nó bị xem là chưa khai báo (216) Ðể diễn tả phạm vi tác dụng biến nói riêng, các khai báo nói chung, kể khai báo chương trình con, ta đưa khái niệm gọi là mức: mức là chương trình chính, mức là các chương trình chương trình chính, mức là các chương trình các chương trình mức 1, v.v Hình vẽ 13.1 mô tả chương trình có hai chương trình A và B mức 1, chương trình A lại có hai chương trình A1 và A2 mức Việc xác định phạm vi tác dụng các biến (hay hằng, kiểu liệu, chương trình con) dựa trên các nguyên tắc sau: Các biến khai báo mức (chương trình chính) có phạm vi tác dụng là toàn chương trình Các biến khai báo mức nào có phạm vi là vùng giới hạn mức đó, kể các mức cao nằm mức này Ví dụ: các biến khai báo thủ tục A dùng thủ tục A, A1 và A2, không dùng chương trình chính và thủ tục B Các biến khai báo thủ tục B dùng thủ tục B không dùng chương trình chính và các thủ tục A, A1 và A2 -Có thể khai báo hai (hay nhiều) biến trùng tên các mức khác chúng là hai biến khác có phạm vi tác dụng khác Nếu hai biến trùng tên lại nằm hai mức có phạm vi bao trùm thì biến mức thấp tạm bị che khuất làm việc mức cao Ví dụ : Nếu chương trình chính và thủ tục B có khai báo hai biến trùng tên là x, thì thủ tục B có biến x địa phương B là có tác dụng, còn biến x chương trình chính tạm thời bị che Ra khỏi thủ tục B, biến x địa phương B bị xóa và biến x toàn cục hoạt động lại bình thường Ví dụ 13.4: Xét chương trình sau: Program VIDU13_4; {1} Var {2} x: Integer; {3} Procedure B; Var {4} {5} x: Integer; {6} Begin {7} x:=5; {8} Writeln(x); {9} (217) End; {10} BEGIN {11} x:=10; {12} B; {13} Writeln(x); Readln; END {14} {15} {16} Chạy<VD13_4.EXE> Chép tập tin nguồn <VD13_4.PAS> Khi chạy chương trình kết qủa in là : 10 Ðầu tiên lệnh {12} gán cho biến x chương trình chính gía trị x=10 Lệnh {13} gọi thủ tục B Vì thủ tục B có biến địa phương tên x nên biến x toàn cục tạm thời ngưng hoạt động và lệnh {8} gán cho biến x địa phương gía trị x:=5 Lệnh {9} in gía trị biến x địa phương là số Khi trở lại chương trình chính thì biến x địa phương bị xóa khỏi nhớ và biến x toàn cục hoạt động trở lại, lệnh {14} in gía trị biến x toàn cục là số 10 Phạm vi các chương trình xác định tương tự Câu hỏi là thủ tục A2 có thể gọi đâu ? Vì thủ tục A2 khai báo thủ tục A nên nó biết đến bên thủ tục A, nghĩa là: Có thể gọi thủ tục A2 từ vị trí thân thủ tục A, thân thủ tục A1,và thân A2 (gọi đệ quy) Tóm lại phạm vi thủ tục A2 là toàn thủ tục A Tương tự, phạm vi thủ tục A1 là toàn thủ tục A Phạm vi thủ tục A hay B là toàn chương trình, kể thủ tục A, A1, A2 và B Ðể hiểu rõ thêm phạm vi các biến, cách thức xây dựng và sử dụng các thủ tục và hàm, ta xét ví dụ sau : Ví dụ 13.5: (218) Nhập hai ma trận A, B cấp MxN, tính ma trận hiệu C=A-B, in ba ma trận lên màn hình Cho biết ma trận nào gồm toàn số Phân tích: Có bốn việc chính phải làm: Nhập hai ma trận A và B Về chất, đây là loại công việc nên có thể viết thành thủ tục để gọi hai lần Tính ma trận C=A-B Ðây là việc chuyên biệt có thể viết thành thủ tục để chương trình sáng sủa In ba ma trận A, B và C Về chất đây là loại công việc nên có thể viết thành thủ tục và gọi ba lần Kiểm tra xem ma trận nào toàn số ? : Câu trả lời là gía trị lôgic đúng hay sai (True hay False), phải viết dạng hàm và gọi ba lần ứng với các đối số là A, B và C Chương trình sau: PROGRAM VIDU13_5; { Tính hiệu hai ma trận } Uses CRT; Type Kmatran = Array[1 10, 10] of Integer ; Var N, M : Integer; A, B, C: Kmatran; Procedure Nhap(Var X: Kmatran ; ten: Char ); Var i, j : Integer; Begin For i:=1 to M { nhập mảng X } For j:=1 to N begin Write(‘Nhập ‘, ten , ‘[‘ , i, ‘,’ , j , ‘]: ‘); (219) Readln(X[i,j]); end; End; { Hết Nhập} Procedure InMatran( Chugiai: String ; X: Kmatran); { In ma trân X lên màn hình } Var i, j : Integer; Begin Writeln(Chugiai); For i:=1 to M begin For j:=1 to N write(X[i,j]:4 ); Writeln; end; End; { Hết In Ma trận} Procedure Tinh( Var X: Kmatran; A , B : Kmatran); { Tính ma trận X=A-B} Var i ,j : Integer; Begin For i:=1 to M For j:=1 to N X[i,j]:=A[i,j]-B[i,j]; End; { Hết Tính } Function Bang0( X : Kmatran) : Boolean ; { Kiểm tra ma tran X gồm toàn số ? } Var (220) i, j : Integer; Ktra: Boolean; Begin Ktra:=TRUE; For i:=1 to M For j:=1 to N if X[i,j] <> then Ktra:=FALSE; Bang0:=Ktra; End; { Hết hàm Bằng 0} BEGIN { chương trình chính } Clrscr; Repeat Write(‘ Nhập số hàng, số cột M, N : ‘); Readln(M, N); Until (N>0) and ( N<11) and ( M>0) and ( M<11) ; Nhap( A, ‘A’ ); Nhap( B, ‘B’ ); Tinh(C, A, B); InMatran( ‘ Ma trận A là: ‘ , A); InMatran( ‘ Ma trận B là: ‘ , B); InMatran( ‘ Ma trận C là: ‘ , C); If Bang0(A) =TRUE then writeln(‘ A toàn số ‘); If Bang0(B) =TRUE then writeln(‘ B toàn số ‘); If Bang0(C) =TRUE then writeln(‘ C toàn số ‘); Readln; END (221) Chạy<VD13_5.EXE> Chép tập tin nguồn <VD13_5.PAS> Trong các chương trình ví dụ trên, hai biến M và N sử dụng tự nhiên mà không cần phải khai báo dạng tham số vì chúng là các biến toàn cục, phạm vi chúng là toàn chương trình Rõ ràng không sử dụng thủ tục và hàm thì chương trình trên viết dài dòng 13.2 PHẠM VI TÁC DỤNG CỦA CÁC KHAI BÁO 13.2.1 Biến toàn cục và biến địa phương : Một chương trình có chứa hàm hay thủ tục gọi là chương trình chính, thủ tục hay hàm gọi là chương trình Vì chương trình là chương trình nên chương trình có khai báo biến, khai báo hằng, v.v., có khai báo chương trình riêng nó, Các biến khai báo chương trình chính gọi là biến toàn cục (global variable), chúng dùng nơi kể từ lúc khai báo kết thúc chương trình Các biến khai báo chương trình gọi là biến địa phương (local variable) Sở dĩ gọi là địa phương vì chúng có tác dụng chương trình nơi nó khai báo mà thôi Các tham số trị hình thức chương trình là biến địa phương Các biến địa phương tồn thời gian chương trình thực hiện, chương trình thực hiên xong thì các biến địa phương bị xóa khỏi nhớ Trong ví dụ 12.5 ( Bài 12 ), biến N và A là các biến toàn cục, còn biến Tam là biến địa phương thủ tục Doicho, nó có tác dụng thủ tục Doicho mà thôi Tương tự, biến j là biến địa phương thủ tục Saptang Mỗi thủ tục Nhap, Saptang và Inday có biến địa phương tên là i, chúng trùng tên song nhớ chúng là ba ô nhớ khác nhau, có phạm vi tác dụng khác Ví dụ 13.3 : Xét chương trình đây : Program VIDU13_3; {1} Var {2} x: Integer; {3} Procedure TTUC1; {4} Var y: Integer; Begin y:=x+5; {5} {6} {7} {8} (222) Writeln(y); End; {9} {10} { hết TTUC1 } BEGIN {11} x:=10; {12} TTUC1; {13} Writeln(y); {14} { lệnh này bị lỗi} Readln; END {15} {16} Chương trình gồm 16 dòng đánh số từ {1} đến {16} Biến x là toàn cục nên có phạm vi tác dụng từ dòng {3} đến dòng {16} Biến y là biến địa phương TTUC1 nên có phạm vi tác dụng từ dòng {6} đến dòng {10} Lệnh Writeln(y); dòng {9} in số 15, còn lệnh Writeln(y); dòng {14} lại bị lỗi Thật vậy, sau thực lệnh {12} gán x:=10; dòng {13} gọi TTUC1 và điều khiển chuyển đến dòng {4} Các dòng {5} {6} cấp ô nhớ cho biến y địa phương, dòng {8} gán y:=x+5; nên y=15 và dòng {9} in gía trị 15 y Ðến đây, TTUC1 kết thúc và biến y bị xóa khỏi nhớ, điều khiển trả cho lệnh {14} chương trình chính, vì y đã bị xóa nên không thể in được, và máy báo lỗi 13.2.2 Phạm vi tác dụng các khai báo : Hình 13.1 (223) Phạm vi tác dụng hay tầm tác dụng biến (hay hằng, kiểu liệu, chương trình con) là khu vực mà đó nó có thể sử dụng được, ngoài khu vực đó nó bị xem là chưa khai báo Ðể diễn tả phạm vi tác dụng biến nói riêng, các khai báo nói chung, kể khai báo chương trình con, ta đưa khái niệm gọi là mức: mức là chương trình chính, mức là các chương trình chương trình chính, mức là các chương trình các chương trình mức 1, v.v Hình vẽ 13.1 mô tả chương trình có hai chương trình A và B mức 1, chương trình A lại có hai chương trình A1 và A2 mức Việc xác định phạm vi tác dụng các biến (hay hằng, kiểu liệu, chương trình con) dựa trên các nguyên tắc sau: Các biến khai báo mức (chương trình chính) có phạm vi tác dụng là toàn chương trình Các biến khai báo mức nào có phạm vi là vùng giới hạn mức đó, kể các mức cao nằm mức này Ví dụ: các biến khai báo thủ tục A dùng thủ tục A, A1 và A2, không dùng chương trình chính và thủ tục B Các biến khai báo thủ tục B dùng thủ tục B không dùng chương trình chính và các thủ tục A, A1 và A2 -Có thể khai báo hai (hay nhiều) biến trùng tên các mức khác chúng là hai biến khác có phạm vi tác dụng khác Nếu hai biến trùng tên lại nằm hai mức có phạm vi bao trùm thì biến mức thấp tạm bị che khuất làm việc mức cao Ví dụ : Nếu chương trình chính và thủ tục B có khai báo hai biến trùng tên là x, thì thủ tục B có biến x địa phương B là có tác dụng, còn biến x chương trình chính tạm thời bị che Ra khỏi thủ tục B, biến x địa phương B bị xóa và biến x toàn cục hoạt động lại bình thường Ví dụ 13.4: Xét chương trình sau: Program VIDU13_4; {1} Var {2} x: Integer; {3} Procedure B; Var {4} {5} x: Integer; {6} Begin {7} x:=5; {8} (224) Writeln(x); {9} End; {10} BEGIN {11} x:=10; {12} B; {13} Writeln(x); Readln; END {14} {15} {16} Chạy<VD13_4.EXE> Chép tập tin nguồn <VD13_4.PAS> Khi chạy chương trình kết qủa in là : 10 Ðầu tiên lệnh {12} gán cho biến x chương trình chính gía trị x=10 Lệnh {13} gọi thủ tục B Vì thủ tục B có biến địa phương tên x nên biến x toàn cục tạm thời ngưng hoạt động và lệnh {8} gán cho biến x địa phương gía trị x:=5 Lệnh {9} in gía trị biến x địa phương là số Khi trở lại chương trình chính thì biến x địa phương bị xóa khỏi nhớ và biến x toàn cục hoạt động trở lại, lệnh {14} in gía trị biến x toàn cục là số 10 Phạm vi các chương trình xác định tương tự Câu hỏi là thủ tục A2 có thể gọi đâu ? Vì thủ tục A2 khai báo thủ tục A nên nó biết đến bên thủ tục A, nghĩa là: Có thể gọi thủ tục A2 từ vị trí thân thủ tục A, thân thủ tục A1,và thân A2 (gọi đệ quy) Tóm lại phạm vi thủ tục A2 là toàn thủ tục A Tương tự, phạm vi thủ tục A1 là toàn thủ tục A Phạm vi thủ tục A hay B là toàn chương trình, kể thủ tục A, A1, A2 và B Ðể hiểu rõ thêm phạm vi các biến, cách thức xây dựng và sử dụng các thủ tục và hàm, ta xét ví dụ sau : (225) Ví dụ 13.5: Nhập hai ma trận A, B cấp MxN, tính ma trận hiệu C=A-B, in ba ma trận lên màn hình Cho biết ma trận nào gồm toàn số Phân tích: Có bốn việc chính phải làm: Nhập hai ma trận A và B Về chất, đây là loại công việc nên có thể viết thành thủ tục để gọi hai lần Tính ma trận C=A-B Ðây là việc chuyên biệt có thể viết thành thủ tục để chương trình sáng sủa In ba ma trận A, B và C Về chất đây là loại công việc nên có thể viết thành thủ tục và gọi ba lần Kiểm tra xem ma trận nào toàn số ? : Câu trả lời là gía trị lôgic đúng hay sai (True hay False), phải viết dạng hàm và gọi ba lần ứng với các đối số là A, B và C Chương trình sau: PROGRAM VIDU13_5; { Tính hiệu hai ma trận } Uses CRT; Type Kmatran = Array[1 10, 10] of Integer ; Var N, M : Integer; A, B, C: Kmatran; Procedure Nhap(Var X: Kmatran ; ten: Char ); Var i, j : Integer; Begin For i:=1 to M { nhập mảng X } For j:=1 to N begin (226) Write(‘Nhập ‘, ten , ‘[‘ , i, ‘,’ , j , ‘]: ‘); Readln(X[i,j]); end; End; { Hết Nhập} Procedure InMatran( Chugiai: String ; X: Kmatran); { In ma trân X lên màn hình } Var i, j : Integer; Begin Writeln(Chugiai); For i:=1 to M begin For j:=1 to N write(X[i,j]:4 ); Writeln; end; End; { Hết In Ma trận} Procedure Tinh( Var X: Kmatran; A , B : Kmatran); { Tính ma trận X=A-B} Var i ,j : Integer; Begin For i:=1 to M For j:=1 to N X[i,j]:=A[i,j]-B[i,j]; End; { Hết Tính } Function Bang0( X : Kmatran) : Boolean ; { Kiểm tra ma tran X gồm toàn số ? } (227) Var i, j : Integer; Ktra: Boolean; Begin Ktra:=TRUE; For i:=1 to M For j:=1 to N if X[i,j] <> then Ktra:=FALSE; Bang0:=Ktra; End; { Hết hàm Bằng 0} BEGIN { chương trình chính } Clrscr; Repeat Write(‘ Nhập số hàng, số cột M, N : ‘); Readln(M, N); Until (N>0) and ( N<11) and ( M>0) and ( M<11) ; Nhap( A, ‘A’ ); Nhap( B, ‘B’ ); Tinh(C, A, B); InMatran( ‘ Ma trận A là: ‘ , A); InMatran( ‘ Ma trận B là: ‘ , B); InMatran( ‘ Ma trận C là: ‘ , C); If Bang0(A) =TRUE then writeln(‘ A toàn số ‘); If Bang0(B) =TRUE then writeln(‘ B toàn số ‘); If Bang0(C) =TRUE then writeln(‘ C toàn số ‘); Readln; (228) END Chạy<VD13_5.EXE> Chép tập tin nguồn <VD13_5.PAS> Trong các chương trình ví dụ trên, hai biến M và N sử dụng tự nhiên mà không cần phải khai báo dạng tham số vì chúng là các biến toàn cục, phạm vi chúng là toàn chương trình Rõ ràng không sử dụng thủ tục và hàm thì chương trình trên viết dài dòng 13.3 SỰ THAM KHẢO TRƯỚC VÀ SỰ ÐỆ QUI 13.3.1 Tham khảo trước (Forward reference): Bình thường chương trình chính có hai chương trình A, B khai báo A trước, B sau, thì B gọi A A không gọi B Khi đó để A gọi B ta phải tiến hành khai báo phần đầu B với từ khóa Forward trước khai báo B đầy đủ Ví dụ 13.6: PROGRAM VIDU13_6; Procedure B; Forward ; { khai báo tham khảo B trước} Procedure A; Begin Writeln(‘ Chào chị ‘); B; End; Procedure B; Begin Writeln(‘ Chào anh ‘); End; BEGIN A; Readln; END (229) Chạy<VD13_6.EXE> Chép tập tin nguồn <VD13_6.PAS> Khi chương trình chạy in lên màn hình: Chào chị Chào anh Tất nhiên, ta đưa khai báo đầy đủ B lên trước A thì không cần phải tham khảo trước Song đặt giả thiết A gọi B B lại gọi A thì định phải tham khảo trước thôi 13.3.2 Sự đệ qui (Recursion): Một thủ tục hay hàm có thể gọi chính nó, đó ta nói có đệ qui Ví dụ 13.7: Tính S= k! đệ qui Ta viết : Muốn tính k! ta phải tính (k-1)!, muốn tính (k-1)! lại phải tính (k-2)!, , suy cuối cùng phải tính 0!, vì 0!=1 nên qúa trình kết thúc Chương trình sau nhập N, tính và in gía trị N! Trong chương trình có xây dựng và sử dụng hàm đệ quy tính k! : PROGRAM VIDU13_7; { Tính N! đệ qui} Var N : Byte; Function Gt( k : Byte) : Real; { Hàm tính k! đệ qui} Begin If k=0 then Gt:= else Gt:= k* Gt(k-1); End; BEGIN (230) Repeat Write(‘ Nhập N: ‘); Readln(N); Until N>0; Writeln( N, ‘ != ‘, Gt(N):0:0 ); Readln; END Chạy<VD13_7.EXE> Chép tập tin nguồn <VD13_7.PAS> Khi nhập N=4, qúa trình gọi các hàm diễn giải sau: Gt(4) =4*Gt(3) =4*3*Gt(2) =4*3*2*Gt(1) =4*3*2*1*Gt(0) { vì k=0 nên Gt=1} =4*3*2*1* =24 Ví dụ 13.8: Tính số hạng U(k) dãy Fibonaci đệ qui: U(0)=1, U(1)=1, U(k)=U(k-1) + U(k-2) với k>1 Ta viết: U(k) = k=0 k=1 = U(k-1) + U(k-2) k>1 Công thức truy chứng trên là sở để xây dựng hàm đệ qui tính U(k): để tính số hạng ta phải tính hai số hạng đứng trước nó Chương trình sau in số Fibonaci thứ N cách gọi hàm đệ qui Fibo PROGRAM VIDU13_8; { Tính số Fibonaci thứ N } (231) Var N : Integer; Function Fibo( k : Integer) : Integer; { Hàm tính số Fibonaci thứ k đệ qui} Begin If k=0 then Fibo:= else if k=1 then Fibo:=1 else Fibo:=Fibo(k-1) + Fibo( k-2); End; BEGIN Write(‘ Nhập N: ‘); Readln(N); Writeln( ‘ Số Fibo thứ ‘, N, ‘ = ‘, Fibo(N) ); Readln; END Chạy<VD13_8.EXE> Chép tập tin nguồn <VD13_8.PAS> Ghi chú: Việc sử dụng đệ qui đòi hỏi nhiều nhớ Lời khuyên là nên tránh dùng đệ qui có thể (232) 13.4 CÂU HỎI TRẮC NGHIỆM Câu 1: Cho khai báo đầu hàm: Function F( k : Integer) : String ; Begin If k mod 2=0 then F:=’Chan’ else F:=’Le’; End; Muốn gán X:= F(5); thì biến X phải khai báo kiểu gì : a) Var X: Real; b) Var X: String; c) Var X: Integer; d) Var X : Char; Câu 2: Cho khai báo đầu hàm: Function F( k : Integer) : String ; Begin If k mod 2=0 then F:=’Chan’ else F:=’Le’; End; Muốn in Write( F(y) ); thì biến y phải khai báo kiểu gì : a) Var y : Real; b) Var y : String; c) Var y : Integer; d) Var y : Char; Câu 3: Cho khai báo biến và khai báo đầu thủ tục TT: Var x, y : Integer ; St :String ; (233) Procedure TT( Var a : Integer ; b : String); -Lệnh nào đúng : a) TT(x +1, St) ; b) TT(10, St) ; c) TT(x, St) ; d) y:= TT(St, x) ; Câu 4: Khi chạy chương trình : Var x, y : Real; Function F(x, y:Real):Real; Begin F:=x; If x < y then F := y; End; BEGIN x:=10; y:=15; Write(F(x, y): 0:0); END -Kết qủa in ra: a) 10 b) 15 c) d) F(x,y) Câu 5: Cho a là biến nguyên a=3, và khai báo thủ tục : Procedure TT( x : Integer) ; (234) Begin x:=x+2; End; Sau gọi thủ tục TT(a); thì Giá trị biến a là : a) b) c) d) Câu 6: Cho x, y là hai biến nguyên và khai báo thủ tục : Procedure Doicho( Var a : Integer; b : Integer); Var z : Integer; Begin z:=a; a:=b; b:=z; End; -Sau thực các lệnh: x:=7; y:=3; Doicho(x, y); thì giá trị x, y là: a) x=7, y=7 b) x=3, y=3 c) x=3, y=7 d) x=7, y=3 Câu 7: Cho khai báo hàm đệ quy : Function F( a : Integer) : Integer; (235) Begin If a=1 then F:=1 else F:= a*a+ F(a-1); End; Giá trị hàm F(4) là: a) b) 25 c) 14 d) 30 Câu 8: Khi chạy chương trình : Var x : Integer; Procedure TT ; Begin x:=4; x:= x+5; End; BEGIN x:=0; TT; Write(x); END -Kết in là: a) b) c) d) Câu 9: Khi chạy chương trình : Var x : Integer; (236) Procedure TINH ; Var x: Integer ; Begin x:=1; x:= x+12; End; BEGIN x:=10; TINH; Write(x); END -Kết in là: a) 10 b) 12 c) 22 d) 13 Câu 10: Khi chạy chương trình : Var x : Integer; Procedure TTA ; Var x : Integer; Begin x:= 7* 5; Write(x, ‘,’); End; BEGIN x:=4; TTA; Write(x:2); END -Kết in là: a) 35, (237) b) 4, 35 c) 4, 75 d) 354 13.5 BÀI TẬP Câu 1) Viết thủ tục nhập hai ma trận vuông A, B cấp N có các phần tử là các số nguyên Viết thủ tục tính ma trận C= A+2B Viết thủ tục in các ma trận A, B và C lên màn hình Viết hàm kiểm tra A, B, C có phải là ma trận đối xứng không ? Câu 2) Viết hàm kiểm tra hàng thứ k ma trận A cấp MxN có lập thành dãy tăng không ? Nhập ma trận A và cho biết hàng nào A lập thành dãy tăng ? Câu 3) Viết hàm để chuẩn hóa chuỗi: xóa bỏ ký tự trắng thừa đầu và cuối chuỗi, và hai từ giữ lại đúng ký tự trắng Câu 4) Viết hàm để đổi ký tự từ chữ hoa chữ thường Dùng hàm đó đổi tất các ký tự chuỗi St nhập từ bàn phím chữ thường hết Câu 5) Viết hàm để kiểm tra chuỗi có đối xứng không Câu 6) Nhập vào chuỗi số nhị phân, đổi số hệ thập phân tương ứng Ví dụ : nhập chuỗi ‘1111’ , đổi số 15 Yêu cầu phải có hàm tính y = 2k và không sử dụng hàm chuẩn EXP(x) ( Hd : 1111 = 1x 23 + 1x 22 + 1x 21 + 1x 20= 15 ) Câu 7) Viết hàm đệ qui tính S= xn (x thực, n nguyên dương) Câu 8) Viết hàm đệ qui tính Sn: Bài 14 Kiểu liệu Bản ghi YÊU CẦU CỦA BÀI GIẢNG (238) Nắm : Khái niệm, cách khai báo và sử dụng kiểu ghi Các ví dụ ghi 14.1 KIỂU BẢN GHI 14.1.1 Khái niệm Các phần trình bày trước cho thấy ngôn ngữ Pascal mạnh việc giải các bài toán thiên tính toán Trong phần này chúng ta thấy thêm khả mạnh mẽ ngôn ngữ Pascal lĩnh vực quản lý: quản lý nhân sự, quản lý vật tư, quản lý tài chánh,.v.v Hàng ngày chúng ta quen thuộc với danh sách sinh viên đây: Mỗi dòng liệt kê các liệu người, cột là liệu thành phần cung cấp thông tin thuộc tính cụ thể người đó Trong ngôn ngữ Pascal, dòng gọi là RECORD (dịch là ghi hay thẻ ghi), cột là FIELD (dịch là trường hay thành phần, hay thuộc tính cho sát với thực tế) Nói tổng quát, ghi là tập gồm nhiều trường (field), các trường có thể có kiểu liệu khác 14.1.2 Mô tả ghi : Kiểu ghi mô tả cách dùng từ khóa RECORD kèm theo danh sách khai báo các tên trường và kiểu liệu tương ứng, kết thúc từ khóa END; , tức là: TYPE Tênkiểu = RECORD Têntrường1 : Kiểudliệu1; Têntrường2 : Kiểudliệu2; Têntrườngk : Kiểudliệuk; End; (239) Ví dụ 1: Ta định nghĩa kiểu KSVIEN sau: TYPE KSVIEN = RECORD Hoten:String[20]; Maso : String[8]; Toan, Ly, DTB: Real; End; Theo mô tả trên, ta có kiểu liệu đặt tên là KSVIEN có cấu trúc ghi gồm trường (thuộc tính) là: Ví dụ 2: Ta mô tả thời gian là kiểu KDATE có ba trường ngày , tháng, năm sau: TYPE KDATE = RECORD Ngay : 31; Thang : 12; Nam : Integer; End; Ví dụ 3: Ðể quản lý các sách thư viện, ta xây dựng kiểu ghi KSACH sau: TYPE KSACH = RECORD (240) Ma_so_sach: String[6]; Ten_doc_gia: String[20]; Nam_xban :Integer; Gia_tien: Real; Ngay_muon : KDATE; End; Kiểu KSACH là ghi có trường mô tả thuộc tính sách là: mã số sách, tên độc giả, năm xuất bản, gía tiền và ngày mượn Ví dụ này cho thấy các ghi có thể mô tả lồng nhau: kiểu liệu trường ghi này lại có thể là kiểu ghi khác đã định nghĩa trước đó Trong ghi KSACH, Ngay_muon là trường có kiểu liệu là ghi kiểu KDATE Mỗi đối tượng cần quản lý có thể có nhiều trường, song tùy yêu cầu quản lý mà ta lựa chọn và khai báo trường thật cần thiết Khai báo thừa thì hao phí nhớ, thiếu thì công tác quản lý khó khăn thiếu thông tin Vì vậy, nên khai báo các trường với số lượng ít đủ dùng 14.1.3 Sử dụng ghi : Kiểu ghi sau đã định nghĩa có thể dùng khai báo cho các biến Ví dụ : Var X, Y, Z : KSVIEN; Trong đó KSVIEN là ghi đã mô tả phần trên Theo khai báo này, X ,Y và Z là ba biến kiểu ghi KSVIEN, biến có trường Hoten, Maso, Toan, Ly và DTB Ðể thâm nhập vào trường ghi ta viết tên biến kiểu ghi, sau đó là dấu chấm ‘.’ và tên trường, tức là : Tênbiến Têntrường Các lệnh đây gán gía trị cho trường biến X : X.Hoten :=‘Nguyen Van An’; X.Maso :=‘1973208’; X.Toan :=8.0; X.Ly :=7.0; (241) X.DTB :=(X.Toan+X.Ly)/2; Ðể nhập liệu cho trường Hoten biến Y, ta viết: Write(‘Nhap ho ten sinh vien Y : ‘); Readln(Y.Hoten); Sở dĩ phải viết tên biến ghi trước tên trường là để xác định trường đó là biến ghi nào Mỗi biến X, Y, Z có trường Hoten, nên viết Hoten thôi thì không biết đó là Hoten ai: X, Y hay Z ? Còn viết X.Hoten là rõ đây là Hoten biến X Như vậy, trường biến ghi có thể thâm nhập và sử dụng biến bình thường X.Hoten là biến kiểu String[20], X.Maso là biến kiểu String[8], , X.DTB là biến kiểu Real Ðối với các ghi lồng nhau, cách truy xuất đến trường tương tự Ví dụ: Cho khai báo biến S kiểu KSACH: Var S : KSACH ; Ðể truy nhập đến các trường Ngay, Thang, Nam Ngay_muon ta viết : S.Ngay_muon.Têntrường Chẳng hạn gán : S.Ngay_muon.Ngay := 2; S.Ngay_muon.Thang := 9; S.Ngay_muon.Nam := 1999; Hai biến ghi cùng kiểu có thể gán cho Lệnh : Y:=X; gán gía trị trường biến X cho trường tương ứng biến Y Vậy lệnh trên tương đương với khối lệnh sau : begin Y.Hoten :=X.Hoten; Y.Maso :=X.Maso; Y.Toan :=X.Toan; Y.Ly :=X.Ly; (242) Y.DTB :=X.DTB; end; Các ghi có thể so sánh khác nhau: Ví dụ: If X=Y then writeln(‘ X và Y là người ‘); If X<>Y then writeln(‘ X khác Y ‘); Tuy nhiên không có phép so sánh <, <=, >, >= cho các ghi Hai ghi có thể hoán đổi gía trị cho theo nghĩa hoán đổi cặp gía trị các trường tương ứng Giống các biến đơn giản, để hoán đổi hai ghi X và Y ta dùng ba lệnh: Z:=X; X:=Y; Y:=Z; đó Z là biến trung gian cùng kiểu ghi với X và Y Ví dụ: Nếu biến X và Y có các trường tương ứng là : X.Hoten =‘Nguyen Van An’ Y.Hoten =‘Tran Thi Nga’ X.Maso =‘1973208’ Y.Maso =‘1974564’ X.Toan =8.0 Y.Toan =5.0 X.Ly =7.0 Y.Ly =8.0 X.DTB =7.5 Y.DTB =6.5 thì sau hoán đổi, ta : X.Hoten =‘Tran Thi Nga’ Y.Hoten =‘Nguyen Van An’ X.Maso =‘1974564’ Y.Maso =‘1973208’ X.Toan =5.0 Y.Toan =8.0 X.Ly =8.0 Y.Ly =7.0 X.DTB =6.5 Y.DTB =7.5 14.1.4 Câu lệnh WITH : (243) Khi làm việc với nhiều trường biến ghi thì cách thâm nhập trên tỏ rườm rà vì phải viết nhiều lần tên biến trước tên trường Ðể đơn giản cách viết, Pascal đưa câu lệnh : WITH Tênbiến DO LệnhP; Tên biến thuộc kiểu ghi Nếu LệnhP có truy xuất đến các trường Tên biến thì không cần phải viết Tên biến và dấu chấm trước các tên trường Ví dụ, thay vì viết: X.Hoten:= ‘Nguyen Van An’; ta có thể viết : WITH X DO Hoten:= ‘Nguyen Van An’; Ðể in các trường biến X lên màn hình, ta viết: WITH X DO Begin Writeln(‘ Họ và tên :’ , Hoten); Writeln(‘ Mã số sinh viên :’ , Maso); Writeln(‘ Ðiểm Toán :’ , Toan: 4:1); Writeln(‘ Ðiểm Lý :’ , Ly: 4:1); Writeln(‘ Ðiểm trung bình : ‘ , DTB :4:1); End; Tất các tên trường nằm khối begin và end hiểu là các trường biến X (nếu không ghi rõ tên biến nào khác) Các lệnh sau gán các gía trị cho các trường biến S kiểu KSACH là ghi lồng nhau: WITH S DO begin Ma_so_sach:=‘TH-435’; Ten_doc_gia:=‘Nguyen van Mai’; Nam_xban :=1999; (244) Gia_tien:= 15000; WITH Ngay_muon DO begin Ngay:=2; Thang:=9; Nam:=1999; end; end; 14.1.5 Mảng các ghi : Trong thực tế, ta thường phải quản lý danh sách sinh viên lớp, danh sách các sách thư viện Ví mảng các ghi dùng phổ biến Khi khai báo : VAR DS : Array[1 50] of KSVIEN; : TYPE KMang = Array[1 50] of KSVIEN; VAR DS: KMang; thì ta có mảng DS gồm 50 phần tử DS[1], , DS[50] cùng kiểu ghi KSVIEN Mỗi DS[i], i=1, , 50 là ghi có trường Hoten, Maso, Toan, Ly, DTB lưu trữ các thông tin sinh viên thứ i danh sách Ðể nhập liệu ( Hoten, Maso, Toan, Ly ) tính Ðiểm trung bình cho 50 sinh viên này, ta dùng vòng lặp For phối hợp với câu lệnh WITH : For i:=1 to 50 WITH DS[i] DO begin Write(‘Nhap ho ten sinh vien thu ‘,i,’ : ‘); Readln(Hoten); (245) Write(‘Nhap ma so sinh vien thu ‘,i,’ : ‘); Readln(Maso); Write(‘Nhap điểm Toan, Ly sinh vien thu ‘,i,’ : ‘); Readln(Toan, Ly); DTB:=(Toan + Ly)/2; end; Ðể xếp danh sách sinh viên theo trật tự giảm DTB cho người có DTB cao thì đứng trước, người có DTB thấp thì đứng sau, ta có thể áp dụng phương pháp xếp mảng, song lấy trường DTB làm tiêu chuẩn so sánh: For i:=1 to 49 For j:=i+1 to 50 If DS[i].DTB < DS[j].DTB then begin { Ðổi chỗ DS[i] và DS[j] } Z:=DS[i]; DS[i]:=DS[j]; DS[j]:=Z; end; Ở đây Z là biến ghi cùng kiểu với các phần tử DS[i] Khi xếp theo DTB tăng giảm thì trường DTB gọi là "khóa" ( key) xếp Một cách tương tự, có thể xếp danh sách sinh viên theo khóa là điểm Toan, điểm Ly, Maso, theo Hoten Ðể in danh sách đã xếp lên màn hình, ta dùng lệnh : For i:=1 to 50 WITH DS[i] DO Writeln( i:2, Hoten:25, Maso:9 , Toan:5:1, Ly:5:1, DTB:5:1); 14.2 CÁC VÍ DỤ VỀ BẢN GHI Ví dụ 14.1: Nhập danh sách N ( 1 N 50) sinh viên gồm các trường: Họ tên, Mã số, các điểm Toán, Lý Ðối với sinh viên, hãy tính điểm trung bình : (246) DTB=(Toan + Ly)/2 , và phân loại sau: Loại= Giỏi DTB  9, Khá 7 DTB < 9, Bình 5 DTB < 7, Kém DTB < Sắp xếp danh sách theo trật tự giảm DTB, in danh sách lên màn hình, người trên dòng gồm các mục: Số thứ tự, Họ tên, Mã số, điểm Toán, Lý, DTB và phân loại Cho biết điểm Tóan cao là ? Có bao nhiêu người điểm cao đó ? Ðiểm trung bình môn Toán cho danh sách là bao nhiêu ? Bài giải : Trong chương trình đây, chỗ nào có ký hiệu ' ' thì hãy thay ký tự trắng PROGRAM VIDU14_1; Uses CRT; Type KSVIEN = RECORD Hoten:String[18]; Maso, Loai : String[8]; Toan, Ly, DTB : Real; End; Var DS : Array[1 50] of KSVIEN; Z : KSVIEN; N, i, j, Dem : Integer; Max, TBToan: Real; BEGIN CLRSCR; (247) Repeat Write(‘ Nhập số sinh viên N= ‘) ; Readln(N); Until ( N>0) and ( N < 51); { Nhập danh sach, tính DTB va phân loại } For i:=1 to N WITH DS[i] DO begin Write(‘Nhap ho ten sinh vien thu ‘,i,’ : ‘); Readln(Hoten); Write(‘Nhap ma so sinh vien thu ‘,i,’ : ‘); Readln(Maso); Write(‘Nhap điểm Toan, Ly sinh vien thu ‘,i,’ : ‘); Readln(Toan, Ly); DTB:=( Toan + Ly)/2; If DTB >=9 then Loai:=‘Gioi’ else if DTB >=7 then Loai:=‘Kha’ else if DTB >=5 then Loai:=‘Binh’ else Loai:=‘Kem’; end; { Sắp xếp giảm theo DTB } For i:=1 to N-1 For j:=i+1 to N if DS[i].DTB < DS[j].DTB then (248) begin Z:=DS[i]; DS[i]:=DS[j]; DS[j]:=Z; end; Writeln(‘ In danh sach len man hinh ‘ ); Writeln(‘STT HO VA TEN MASO', ' TOAN LY DTBLOAI’); For i:=1 to N WITH DS[i] DO Writeln(i:2, #32 , Hoten, #32 :19-Length(Hoten), Maso:8, Toan:4:1,Ly:4:1, DTB:4:1, Loai:5); { Tìm điểm Toán cao } Max:=DS[1].Toan; For i:=1 to N if Max< DS[i].Toan then Max:=DS[i].Toan; Writeln(‘Diem Toan cao nhat = ‘, Max:4:1); { Ðếm số em có điểm Toán =Max} Dem:=0; For i:=1 to N if DS[i].Toan =Max then Dem:=Dem+1; Writeln(‘ Có ‘, Dem, ‘ em có điểm Toán= ‘, Max:4:1); { Tính điểm trung bình môn Toán cho danh sach } TBToan:=0; { Lấy tổng điểm môn Toán} For i:=1 to N TBToan := TBToan + DS[i].Toan; TBToan:=TBToan/N ; Writeln(‘Diem trung binh mon Toan= ‘ , TBToan:6:2); Readln; END Chạy<VD14_1.EXE> (249) Chép tập tin nguồn <VD14_.PAS> Ví dụ 14.2: Nhập danh sách N (1N 50) đầu sách gồ? các thông tin Tên sách, Số lượng (SL) và Ðơn gía (DG) Với đầu sách, tính Gía tiền sau: GT = SL * DG SL<10 = SL*DG - 5%*SL*DG 10  SL<30 = SL*DG - 8%* SL*DG 30  SL <50 = SL*DG - 10%* SL*DG SL  50 (Tức là mua từ 10 đến 29 thì giảm 5% đơn gía, mua từ 30 đến 49 thì giảm 8% đơn gía, mua từ 50 trở lên thì giảm 10% đơn gía) Tính Tổng số tiền cho việc mua sách, kể 10% thuế gía trị gia tăng đánh vào tổng gía tiền Tìm xem danh sách đó có "TIN HOC DAI CUONG" không Nếu có thì cho biết có bao nhiêu và đơn gía nó Bài giải: PROGRAM VIDU14_2; Uses CRT; Type KSACH = RECORD Tensach : String[20]; SL : Integer; DG, GT: Real; End; Mang = Array[1 50] of KSACH; Var S : Mang; Z : KSACH; (250) N, i : Integer; Tongtien : Real; BEGIN Repeat Write(‘ Nhập N: ‘); Readln( N ); Until (N>0) and ( N<51); { Nhập N sách và tính tiền} For i:=1 to N With S[i] begin Write(‘Nhập tên sách thứ ‘, i ,’: ‘); Readln(Tensach); Repeat Write(‘Nhập Số lượng : ‘); Readln(SL); Until SL>0; Write(‘Nhập đơn giá : ‘); Readln(DG); Case SL of : GT:=SL*DG; 10 29 : GT:=SL*DG*(1-0.05); 30 49 : GT:=SL*DG*(1-0.08); else GT:=SL*DG*(1-0.1); end; { Hết Case} end; { Hết For} { Tính tổng gía thành các đầu sách} (251) Tongtien:=0; For i:=1 to N Tongtien:=Tongtien+S[i].GT; { Cộng thêm thuế 10% gía tri gia tăng} Tongtien:=Tongtien + 0.1*Tongtien ; Writeln(‘Tổng tiền là: ‘, Tongtien :6:2); { Tìm ‘TIN HOC DAI CUONG’} i:=1; While (i<=N) and ( S[i].Tensach<> ‘ TIN HOC DAI CUONG’) i:=i+1; If i> N then writeln (‘ Không có THDC?‘) else WITH S[i] DO writeln(‘ Sách THDC có ‘, SL:4, ‘ cuốn, đơn gía= ‘, DG:6:2); Readln; END Chạy<VD14_2.EXE> Chép tập tin nguồn <VD14_2.PAS> Ví dụ 14.3: Sử dụng liệu ví dụ viết thủ tục in danh sách các đầu sách lên mà hình, trình bày thành biểu sau : TỔNG KẾT TIỀN MUA SÁCH NĂM 1999 Giải: Thủ tục INBIEU sau đây chứa thủ tục INCHITIET có nhiệm vụ in chi tiết dòng cho sách (252) Thân thủ tục INBIEU là các lệnh in tiêu đề, sau đó là lời gọi thủ tục INCHITIET Các liệu phục vụ cho thủ tục này là các biến toàn cục khai báo chương trình chính ví dụ 14.2, đó là N và S Chỗ nào có ký hiệu  thì hãy thay ký tự trắng Nhắc lại #32 là ký tự trắng Thủ tục in biểu viết sau: PROCEDURE INBIEU; Var i: Integer ; Procedure INCHITIET; { Thủ tục in chi tiết sách} Var i : Integer; Begin For i:=1 to N WITH S[i] DO begin Write(‘| ‘ , i:3, #32); Write(‘| ‘ , Tensach); Write(#32: 21-Length(Tensach) ); Write(‘| ‘, SL:8, #32); Write(‘| ‘, DG:8:2, #32); Write(‘| ‘, GT:8:2, ‘ |’); Writeln; end; For i:=1 to 63 write(‘-’); Writeln; End; { hết in chi tiết} Begin { Vào thủ tục Inbiểu } (253) { In tiêu đe?} Writeln(' TONG KET TIEN MUA SACH NAM 1999’); Writeln( #32 :6 , ‘ ’); For i:=1 to 63 write(‘-’); Writeln; Write(‘| STT ‘); Write(‘|’ , #32:7 , ‘TEN SACH’, #32:7 ); Write(‘| SO LUONG ‘); Write(‘| DON GIA ‘); Write(‘| GIA TIEN |’); Writeln; For i:=1 to 63 write(‘-’); Writeln; INCHITIET; End ; Ráp toàn thủ tục INBIEU vào phần khai báo chương trình ví dụ 14.2, và thêm lệnh gọi INBIEU; vào cuối thân chương trình đó, ta chương trình đầy đủ mà chạy in biểu theo đúng yêu cầu Ngoài ra, để chương trình chính bớt rườm rà, ta đưa phần nhập liệu vào thủ tục riêng gọi là NHAP, phần tính tổng gía thành các sách vào thủ tục riêng gọi là TINH, và phần tìm TIN HOC DAI CUONG vào thủ tục gọi là TIM Trong chương trình chính ta phải gọi tên các thủ tục đó mà thôi PROGRAM VIDU14_3; Uses CRT; Type KSACH = RECORD Tensach : String[20]; SL : Integer; DG, GT: Real; (254) End; Mang = Array[1 50] of KSACH; Var S : Mang; Z : KSACH; N, i : Integer; Tongtien : Real; { - Thủ tục Nhập -} PROCEDURE NHAP ( Var N : Integer); { Nhập N đầu sách và tính gía thành } Var i : Integer; Begin Repeat Write(‘ Nhập số lượng sách N: ‘); Readln( N ); Until (N>0) and ( N<51); For i:=1 to N With S[i] begin Write(‘Nhập tên sách thứ ‘, i ,’: ‘); Readln(Tensach); Repeat Write(‘Nhập Số lượng : ‘); Readln(SL); Until SL>0; Write(‘Nhập đơn giá : ‘); Readln(DG); (255) Case SL of : GT:=SL*DG; 10 29 : GT:=SL*DG*(1-0.05); 30 49 : GT:=SL*DG*(1-0.08); else GT:=SL*DG*(1-0.1); End; { Hết Case} end; { Hết For} End; { - Thủ tục Tinh -} PROCEDURE TINH ; { Tính tổng gía thành các đầu sách} Var i: Integer; Begin Tongtien:=0; For i:=1 to N Tongtien:=Tongtien+S[i].GT; { Cộng thêm thuế 10% gía tri gia tăng} Tongtien:=Tongtien + 0.1*Tongtien ; Writeln(‘Tổng tiền là: ‘, Tongtien :6:2); End; { - Thủ tục Tìm -} PROCEDURE TIM ; { Tìm ‘TIN HOC DAI CUONG’} Var i : Integer; Begin (256) i:=1; While (i<=N) and ( S[i].Tensach<> ‘ TIN HOC DAI CUONG’) i:=i+1; If i> N then writeln (‘ Không có THDC ‘) else WITH S[i] DO writeln(‘ Sách THDC có ‘, SL:4, ‘ với đơn gía= ‘, DG:6:2); End; { Thủ tục In biểu } PROCEDURE INBIEU; Var i: Integer ; Procedure INCHITIET; { Thủ tục in chi tiết sách} Var i : Integer; Begin For i:=1 to N WITH S[i] DO begin Write(‘|‘ , i:3, #32); Write(‘| ‘ , Tensach); Write(#32: 21-Length(Tensach) ); Write(‘| ‘, SL:8, #32); Write(‘| ‘, DG:8:2, #32); Write(‘| ‘, GT:8:2, ‘ |’); Writeln; end; (257) For i:=1 to 63 write(‘-’); Writeln; End; { hết in chi tiết} Begin { Vào thủ tục Inbiểu } { In tiêu đề} Writeln(‘~~~~~~ONG KET TIEN MUA SACH NAM 1999’); Writeln( #32 :6, ‘ -’); For i:=1 to 63 write(‘-’); Writeln; Write(‘| STT ‘); Write(‘|’ , #32:7 , ‘TEN SACH’, #32:7 ); Write(‘| SO LUONG ‘); Write(‘| DON GIA ‘); Write(‘| GIA TIEN |’); Writeln; For i:=1 to 63 write(‘-’); Writeln; INCHITIET; End ; { Hết thủ tục In biểu } BEGIN NHAP ( N); TINH; TIM; INBIEU; Readln; (258) END (259) 14.3 CÂU HỎI TRẮC NGHIỆM Câu 1: Chọn khai báo đúng : a) Type Phanso = Record Tu, Mau: Integer; end ; b) Type Phan so = Record Tu so, Mau so : Integer; end; c) Var Phanso = Record ; Tu, Mau: Integer; end ; d) Type Record = Phanso ; Tu, Mau : Integer; end; Câu 2: Chọn khai báo đúng : a) Type DIEM = Record x,y : Real; b) Type DIEM = Record x,y : Real; end; c) Type DIEM = Record x, y ; end; d) DIEM = Record (260) x, y : Real; end; Câu 3: Cho khai báo : Type SV = Record Ten :String[20]; Dtb:Real; end; Var X, Y : SV ; -Chọn câu đúng : a) SV.Dtb:= 4.5 ; b) X.Dtb:=’ Le Van Toan’; c) X.Ten:=’Anh’ ; d) X := Y.Dtb; Câu 4: Cho khai báo : Type SV = Record Ten :String[20]; Dtb:Real; end; Var X : SV ; -Chọn câu đúng : a) With X Dtb:= 4.5 ; b) Dtb:= 4.5 ; c) With SV Dtb:=4.5 ; d) X := 4.5 ; (261) Câu 5: Cho khai báo : Type SVIEN = Record Ten, Maso : String[10]; end; -Câu nào đúng : a) Var A : array [1 10] of Record; b) Var A : array [1 10] of SVIEN; c) Var A: array[1 10] of Ten ; d) A: array[1 10] of Maso ; Câu 6: Khi chạy chương trình : Type Vector = Record x, y : Integer; end; Var A, B : Vector ; Begin A.x := ; A.y := 1; B.x := -1; B.y := -3 ; Write( A.x*B.x+A.y*B.y) ; End -Kết qủa in là: a) b) -5 c) -7 d) -3 (262) Câu 7: Khi chạy chương trình : Type Vector = Record x, y : Integer; end; Var A, B : Vector ; Begin A.x := ; A.y := 4; B.x := -1; B.y := ; Write( Sqr( A.x-B.x) + Sqr(A.y-B.y) ); End -Kết qủa in là: a) b) 16 c) d) 25 Câu 8: Cho khai báo : Type Vector = Record x, y : Integer; end; Var S : Array[1 4] of Vector ; i : Integer ; -Lệnh nào đúng : a) For i:=1 to S[i].x:= 3; y=4; b) For i:=1 to With S[i] x:= 3; y=4; (263) c) For i:=1 to begin S[i].x:= 3; S[i].y=4; end ; d) For i:=1 to begin S.x:= 3; S.y=4; end; Câu 9: Cho khai báo : Type Sach = Record Masach : String[4]; Gia: Real; end; Var DS : Array[1 10] of Sach ; Tien: Real; i : Integer ; -Lệnh nào đúng : a) For i:=1 to 10 With DS [i] Tien:=Tien+ Gia ; b) For i:=1 to 10 Tien:=Tien+ Gia ; c) For i:=1 to 10 Tien:=Tien+ DS[i].Masach ; d) For i:=1 to 10 Tien:=Tien+ Sach[i].Gia ; Câu 10: Cho khai báo : Type Toado = Record hoanhdo, tungdo : Integer; end; Var A, B: Toado ; -Lệnh nào SAI : a) A:=B ; b) A:=A-1; c) A.hoanh :=B.tung ; d) With A hoanh:= B.hoanh ; (264) 14.4 BÀI TẬP Câu *1) Ðể biết thí sinh đậu hay rớt kỳ thi tuyển sinh, cần biết các thông tin sau: Họ tên : họ và tên thí sinh KV : thí sinh thuộc khu vực nào? ( 1, hay ) NH : thí sinh thuộc nhóm nào ? ( 1, 2, hay 3) TÐ : tổng diểm ba môn thi a) Hãy nhập vào danh sách 100 thí sinh gồm Họ tên, KV, NH, TÐ Xét xem Kết qủa thí sinh này đậu hay rớt dựa vào bảng điểm chuẩn sau : Ví dụ : Thí sinh Khu vực , Nhóm 2, có Tổng điểm ? 17.5 thì đậu, ngược lại thì rớt b) In danh sách đã xếp theo trật tự giảm TÐ lên màn hình, gồm các mục Họ tên, KV, NH, TÐ và Kết qủa đậu, rớt c) Chỉ in danh sách người đậu lên màn hình theo mẫu: Câu *2) Mỗi điểm M(x,y) mặt phẳng toạ độ Oxy mô tả sau : Type DIEM = Record x, y : real; End; Viết chương trình với các yêu cầu sau : Có thủ tục nhập vào tọa độ ba điểm A, B, C Trong đó có hàm kiểm tra xem có cặp điểm nào trùng không ? Nếu có thì bắt nhập lại ba điểm A, B, C phân biệt Có thủ tục (hay hàm) tính độ dài các cạnh AB, BC, AC theo công thức : (265) Nếu A(xa,ya), B(xb,yb) thì Có thủ tục kiểm tra xem AB, BC, AC có phải là ba cạnh tam giác không? ( Hd : tổng hai cạnh phải lớn cạnh còn lại ) Nếu không phải thì in chữ " Không phải Tamgiác" , ngược lại thì tính và in diện tích tam giác ABC lên màn hình theo công thức Hêrông : , với P là nửa chu vi tam giác : P = (AB+BC+AC) / Câu 3) Viết chương trình pascal để thực các yêu cầu sau : Nhập số nguyên N ( 0<N<100) và danh sách N học sinh với các thông tin về: họ và tên, chuyên ban (A , B, C) và các điểm Toán, Văn, Sinh kiểu thực Với học sinh hãy tính điểm trung bình sau : DTB =(2*Toán+ Sinh+Văn)/4 em thuộc chuyên ban A =(Toán+2*Sinh+Văn)/4 em thuộc chuyên ban B =(Toán+Sinh+2*Văn)/4 em thuộc chuyên ban C Chuyên ban nào có nhiều em có điểm trung bình ? ? Câu 4) Nhập số nguyên N ( 0<N<50 ) và N hóa đơn tính tiền điện, hóa đơn có họ tên chủ hộ, số điện kế tháng trước (Socu), số điện kế tháng này (Somoi), và định mức (Dmuc) điện hàng tháng hộ Hãy tính tiền điện cho hóa đơn, biết rằng: Mỗi kw định mức có đơn gía là 5đ, 100 kw đầu tiên trên định mức có đơn giá 8đ, Từ kw thứ 101 trên định mức trở lên có đơn gía 10đ Tính tổng số tiền thu từ tất các hóa đơn Tìm các hóa đơn xem có hộ nào tên là Tuan không ? Nếu có thì in lên màn hình các hóa đơn có chủ hộ tên là Tuan gồm các thông tin Socu, Somoi, Dmuc và Tien điện phải trả Câu 5) (266) Nhập danh sách N người gồm Họ tên, Chức vụ (GD, TP, PP, NV) và Mức lương tháng (ML) Tính Phụ cấp lương (PC) cho người sau : PC = 50% Mức lương tháng chức vụ là GD = 40% " " " " TP = 30% " " " " PP = 20% " " " NV " Tính Thu nhập (TN) tháng cho người : TN = Mức lương + PC Ðổi họ tên người chữ thường hết, riêng chữ cái đầu từ thành chữ hoa, chẳng hạn: Nguyen Thi Loan Yêu cầu phần này viết thành thủ tục In Họ tên, Chức vụ, Mức lương, Phụ cấp và Thu nhập người có thu nhập cao lên màn hình Bài 15 Kiểu liệu tập hợp và tin YÊU CẦU CỦA BÀI GIẢNG Nắm được: Khái niệm tập hợp, các phép toán trên tập hợp Khái niệm tập tin, các thủ tục và hàm liên quan đến tập tin Cách khai báo và sử dụng tập tin có định kiểu và tập tin văn 15.1 KIỂU TẬP HỢP 15.1.1 Khai báo : Một tập hợp thì gồm nhiều gía trị có chung kiểu liệu, gọi là kiểu Kiểu phải là kiểu vô hướng đếm được, tức có thể là kiểu byte, ký tự , lôgic hay liệt kê Số phần tử tập hợp tối đa là 256 phần tử Kiểu tập hợp mô tả từ khóa SET OF , là kiểu các phần tử Ví dụ: TYPE Kky_tu = SET OF Char; Kchu_hoa = SET OF ‘A’ ‘Z’; (267) Kso = SET OF Byte; Var TapA, TapB : Kky_tu; TapH: Kchu_hoa; TapS : Kso; Các tập hợp TapA, TapB, TapH, TapS nói trên có thể khai báo trực tiếp sau: Var TapA, TapB : SET OF Char; TapH : SET OF ‘A’ ‘Z’; TapS : SET OF Byte; Chú ý các khai báo đây là sai, vì kiểu không thể là Integer, và là đoạn thì phạm vi đoạn không vượt qúa phạm vi kiểu Byte: Var T1: SET OF Integer; T2: SET OF 256 ; 15.1.2 Xác định tập hợp : Một tập hợp xác định cách liệt kê các phần tử nó, các phần tử phân cách dấu phẩy, và đặt hai dấu ngoặc vuông [ ] : tập rỗng [3 6] : tập các số nguyên 4, 3, 5, [3 6, 9, 12] : tập các số nguyên 3, 4, 5, 6, 9, 12 [‘A’ ’C’, ‘X’, ‘Z’] : tập các chữ ‘A’, ‘B’, ‘C’, ‘X’, ‘Z’ Các phần tử tập hợp có thể là biến hay biểu thức, ví dụ: [3, 5, i+j, 2*j] : tập hợp này có phần tử là 3, 5, hai phần tử có gía trị i+j và 2*j, đó i, j là các số nguyên cho i+j và 2*j nằm phạm vi từ đến 255 15.1.3 Các phép toán : Phép gán: (268) Có thể gán tập hợp cho biến tập hợp cùng kiểu Ví dụ, với các biến khai báo trên, có thể gán: TapA:=[‘1’ ’5’, ‘9’, ‘A’]; TapH:=[‘C’ ’F’]; TapS:=[15 20, 30, 40]; Tập rỗng [ ] gán cho biến tập hợp kiểu nào : TapA:=[ ]; TapH:= [ ]; Lệnh gán đây là sai vì hai vế không cùng kiểu liệu: TapA:=[1 8]; TapS:=[‘1’ ’9’]; Phép hợp: Hợp hai tập hợp A và B, ký hiệu là A+B, là tập hợp gồm các phần tử thuộc tập A thuộc tập B Ví dụ: [3 5]+[4 6,10, 15]=[ 6, 10, 15] Phép giao: Giao hai tập hợp A và B, ký hiệu là A*B, là tập hợp gồm các phần tử đồng thời thuộc A và B Ví dụ: [1 10]*[5 15] =[5 10] Phép hiệu: Hiệu hai tập hợp A và B, ký hiệu là A-B, là tập hợp gồm các phần tử thuộc tập A không thuộc tập B Ví dụ: [1 10] - [5 15] =[1 4] Nhận xét: Các phép toán trên thực A và B cùng kiểu, và kết qủa là tập hợp C cùng kiểu với A và B Phép thử IN (thuộc về) : Dùng để kiểm tra xem biến hay gía trị có phải là phần tử tập hợp nào đó không (269) Biểu thức x IN TapA cho kết qủa là True gía trị x thuộc TapA, cho gía trị False trường hợp ngược lại Ví dụ : ‘N’ IN [‘N’, ‘n’] cho kết qủa là TRUE ‘y’ IN [‘N’, ‘n’] cho kết qủa là FALSE Các phép so sánh (=, <>, <=, >=) : Cho A và B là hai tập hợp cùng kiểu, kết qủa các phép so sánh A với B là TRUE FALSE Phép bằng: A=B và phần tử A thuộc B và phần tử B thuộc A, trường hợp ngược lại, ta nói A khác B và viết A<>B Ví dụ: [3,2,4,5]= [2, 5] [‘A’, ‘B’]<>[‘a’,’B’] Phép nhỏ : A<=B và phần tử A thuộc B, ví dụ: [3 5]<=[3 5] [3 5]<=[1 6] Phép lớn : A>=B và phần tử B thuộc A, nói cách khác A>=B và B<=A [3 5]>=[3 5] [‘A’ ’Z’]>=[‘A’ ’D’] Chú ý các tập hợp không có phép so sánh nhỏ (<) và lớn (>) Khi cần so sánh lớn hay nhỏ ta có thể viết: If (A<=B) and ( A<>B) then writeln(‘A < B’); If (A>=B) and ( A<>B) then writeln(‘A > B’); 15.1.4 Các ví dụ : Ví dụ 15.1: Nhập vào chuỗi St , cho biết St có chữ hoa nào Ví dụ St=‘ABc3BAFdzA’ thì có các chữ hoa là A, B, F PROGRAM VIDU15_1; (270) Var Taphoa : Set of ‘A’ ’Z’; N, i: byte; ch : char; St : String; Begin Write(‘ Nhập chuỗi St: ‘); Readln(St); Taphoa:=[]; N:=length(St); For i:=1 to N if St[i] IN [‘A’ ’Z’] then Taphoa := Taphoa+[ St[i] ]; Writeln(‘ Cac chu hoa co St la :’); For ch:=‘A’ to ‘Z’ if ch IN Taphoa then write(ch:3); Readln; End Ví dụ 15.2: Nhập N số nguyên phạm vi từ đến 255 In các tập số chẵn, lẻ và cho biết có bao nhiêu số chẵn, bao nhiêu số lẻ (các số trùng kể lần) Ví dụ, nhập số : 1, 2, 3, 4, 1, 2, 3, 4, thì có hai số chẵn là và và có số lẻ là 1, 3, PROGRAM VIDU15_2; Const N=10; Var Tapchan, Taple : Set of byte; N1, N2, i, k: byte; Begin (271) Tapchan:=[]; Taple:=[]; For i:=1 to N begin Write(‘Nhap so thu ‘, i, ‘: ‘); Readln(k); If odd(k)=False then Tapchan:=Tapchan+[k] else Taple:=Taple+[k]; end; writeln(‘ Các số chẵn là: ‘); N1:=0; For i:=0 to (255 div 2) if 2*i IN Tapchan then begin Write(2*i : 3); N1:=N1+1; end; Writeln( ‘ Co ‘, N1, ‘ số chẵn’); Writeln(‘ Các số lẻ là: ‘); N2:=0; For i:=0 to (255 div 2) if (2*i +1) IN Taple then begin Write(2*i+1 : 3); N2:=N2+1; end; (272) writeln( ‘ Co ‘, N2, ‘ số lẻ’); Readln; End Ví dụ 15.3: Tìm các số nguyên tố  số nguyên dương N cho trước Có nhiều cách giải khác nhau, đây giới thiệu phương pháp Eratosthene, sử dụng liệu kiểu tập hợp và không cần đến các phép toán nhân Xuất phát từ tập số nguyên S=[2 N] ta loại số nguyên tố đầu tiên và tất các bội số nó khỏi S, lặp lại quá trình trên S thành tập rỗng Ví dụ: S=[2 15]; Bước 1:-đưa vào tập số nguyên tố, Tapsnt:=[2] -loại và các bội khỏi S, ta S=[3,5,7,9,11,13,15 ] Bước 2:-đưa vào tập số nguyên tố, Tapsnt:=[2,3] -loại và các bội khỏi S, S=[5,7,11,13 ] Bước 3:-đưa vào tập số nguyên tố, Tapsnt:=[2,3,5] -loại và các bội khỏi S, S=[7,11,13 ] Bước 4:-đưa vào tập số nguyên tố, Tapsnt:=[2,3,5,7] -loại và các bội khỏi S, S=[11,13 ] Bước 5:-đưa 11 vào tập số nguyên tố, Tapsnt:=[2,3,5,7,11] -loại 11 và các bội 11 khỏi S, S=[13 ] Bước 6:-đưa 13 vào tập số nguyên tố, Tapsnt:=[2,3,5,7,11,13] -loại 13 và các bội 13 khỏi S, S=[ ] Kết qủa Tapsnt = [2,3,5,7,11,13] Tập S giống cái sàng để lọc và loại các số không phải số nguyên tố Chương trình cụ thể sau: PROGRAM VIDU15_3; Const (273) N=20; Var Tapsnt, S: Set of N; snt, i: Integer; Begin S:=[2 N]; Tapsnt:=[]; snt:=2; { so nguyen to nho nhat } Writeln(‘ Cac so nguyen to la :’ ); Repeat { tim snt la so nho nhat S} While Not (snt IN S) snt:=snt+1; Tapsnt:= Tapsnt+[snt]; { dua vao Tapsnt } Write(snt:4); { Loại các bội snt khỏi S } i:=snt; While i<=N begin S:=S - [i]; i:=i+snt; end; Until S=[]; Readln; End 15.2 DỮ LIỆU KIỂU TẬP TIN 15.2.1 Khái niệm : (274) Nhập và xuất liệu là hai công việc phổ biến thực chương trình Cho đến nay, ta nhập liệu từ bàn phím và xuất liệu màn hình Các liệu này tổ chức nhớ máy, chúng tồn chương trình chạy và bị xóa chương trình kết thúc Muốn lưu trữ các liệu lâu dài để sử dụng nhiều lần thì phải ghi chúng lên đĩa thành các tập tin Tập tin (file) Pascal là kiểu liệu có cấu trúc Mỗi tập tin là tập hợp các phần tử có cùng chung kiểu liệu nhóm lại thành dãy và ghi trên đĩa cái tên chung Khái niệm tập tin và mảng có điểm gần Song tập tin khác mảng điểm sau đây: Mảng tổ chức nhớ còn tập tin chủ yếu tổ chức trên đĩa Số phần tử mảng xác định khai báo, còn số phần tử tập tin thì không Các tập tin kết thúc dấu hiệu đặc biệt gọi là EOF ( End Of File) Các phần tử mảng truy xuất thông qua số Các phần tử tập tin truy xuất nhờ biến trung gian điểm vào vị trí chúng trên đĩa, gọi là trỏ tệp Tại thời điểm, trỏ vào vị trí nào đó tập tin, gọi là vị trí thời Dưới đây trình bày hai loại tập tin thường gặp là tập tin có định kiểu và tập tin văn 15.2.2 Tập tin có định kiểu: Tập tin mà các phần tử nó có cùng kiểu liệu gọi là tập tin có định kiểu Kiểu liệu các phần tử tập tin có thể là kiểu đơn giản ( nguyên, thực, ký tự , lô gic, chuỗi ký tự ) kiểu có cấu trúc ( mảng, ghi) Cách khai báo kiểu tập tin sau: Type TênkiểuTtin = File of Kiểuphầntử ; Ví dụ: Type Ksvien = Record Ten: String[20]; Namsinh : Integer; DTB : Real; end; KieuT1 = File of Integer; (275) KieuT2 = File of String[20]; KieuT3 = File of Ksvien ; Theo khai báo trên thì KieuT1 là tập tin có các phần tử kiểu nguyên ( Integer ), KieuT2 là tập tin có các phần tử là các chuỗi ký tự ( String[20] ), còn KieuT3 là tập tin có các phần tử là các ghi kiểu Ksvien Khi đã có kiểu tập tin, ta có thể khai báo các biến tập tin : Var F1 : KieuT1; F2 : KieuT2; F3 : KieuT3; F1, F2, F3 là các biến kiểu tập tin, loại biến đặc biệt, không dùng để gán gía trị các biến nguyên, thực hay chuỗi Mỗi biến này đại diện cho tập tin mà thông qua các biến đó ta có thể thực các thao tác trên tập tin : tạo tập tin, mở, đóng, xóa tập tin, ghi liệu vào tập tin và đọc liệu từ tập tin, Ngoài cách khai báo các biến F1, F2, F3 thông qua việc địng nghĩa các kiểu liệu trên, Pascal còn cho phép khai báo trực tiếp các biến tập tin sau: Var TênbiếnTtin : File of Kiểuphầntử ; Ví dụ: có thể khai báo ba biến F1, F2, F3 nói trên theo cách sau : Type Ksvien = Record Ten: String[20]; Namsinh : Integer; DTB : Real; end; Var F1 : File of Integer; F2 : File of String[20]; F3 : File of Ksvien ; (276) 15.2.2.1 Các thủ tục chuẩn: 1) Thủ tục ASSIGN( biếntậptin, têntậptin) : Gán tên tập tin cho biến tập tin Ở đây tên tập tin là kiểu chuỗi là tên thực tập tin Ví dụ : biểu thức Assign(F1, ‘DLIEU.DAT’); Assign(F3, ‘QLSV.DAT’); Sau hai lệnh này, biến F1 đồng với tập tin DLIEU.DAT, thao tác trên biến F1 chính là thao tác trên tập tin DLIEU.DAT Tương tự, biến F3 đồng với tập tin QLSV.DAT 2) Thủ tục REWRITE( biếntậptin) : Khởi tạo tập tin mới, tập tin đã có trên đĩa thì nó xóa và tạo Ví dụ : Rewrite(F1) ; khởi tạo tập tin DLIEU.DAT Rewrite(F3) ; khởi tạo tập tin QLSV.DAT 3) Thủ tục RESET(biếntậptin): Mở tập tin đã có để sử dụng Con trỏ tập tin trỏ vào phần tử đầu tiên (có số thứ tự là 0) tập tin Ví dụ : Reset ( F3); mở tập tin QLSV.DAT 4) Thủ tục WRITE( biếntậptin, b1, b2, , bN): Tuần tự ghi vào tập tin các gía trị các biến b1, b2, , bN Các biến b1, , bN phải cùng kiểu liệu với các phần tử tập tin Ví dụ: - Cho i, j, k là các biến kiểu Integer và i=10, j=20, k=100, đó lệnh : Write(F1, i, j, k ) ; ghi các gía trị 10, 20, 100 vào tập tin DLIEU.DAT -Cho khai báo: Var X : Ksvien; (277) Các lệnh sau gán gía trị cho X và ghi X vào tập tin QLSV.DAT: X.Ten:=’Ng Van An’; X.Namsinh :=1980 ; X.DTB :=6.5; Write(F3, X); Sau ghi X vào tập tin QLSV.DAT, trỏ tập tin tự động dời đến vị trí phần tử 5) Thủ tục READ( biếntậptin, b1, b2, , bN) : Ðọc các phần tử tập tin từ vị trí thời trỏ tập tin và gán cho các biến b1, b2, , bN Kiểu liệu các biến b1, b2, , bN phải cùng kiểu với các phần tử tập tin Mỗi đọc xong phần tử, trỏ tập tin tự động dời đến phần tử Ví dụ: Lệnh Read(F1, i, j); đọc hai số nguyên tập tin DLIEU.DAT ( kể từ vị trí thời) và gán cho các biến nguyên i, j Lệnh Read(F3, X); đọc ghi thời tập tin QLSV.DAT và gán cho biến ghi X 6) Thủ tục CLOSE( biếntậptin) : Ðóng tập tin 7) Thủ tục SEEK( biếntậptin, k ) : Ðặt trỏ tập tin vào phần tử thứ k tập tin Thủ tục này cho phép truy xuất trực tiếp phần tử tập tin mà không phải thực từ đầu tập tin Ví dụ: đọc phần tử thứ 10 tập tin DLIEU.DAT và gán cho biến nguyên i in gía trị i : Seek(F1, 10); Read(F1, i); Write(i); 8) Thủ tục ERASE( biếntậptin) : Xóa tập tin trên đĩa 9) Thủ tục RENAME( biếntậptin, tênmới ) : Ðổi tên tập tin Yêu cầu là tập tin phải đóng thì xóa hay đổi tên (278) 15.2.2.2 Các hàm chuẩn: 1) Hàm EOF(biếntậptin): Cho kết qủa True trỏ tập tin cuối tệp, các trường hợp khác hàm cho gía trị False 2) Hàm FILESIZE(biếntậptin) : Cho số phần tử tập tin Nếu tập tin rỗng thì số phần tử 3) Hàm FILEPOS(biếntậptin) : Cho vị trí thời trỏ tập tin Phần tử đầu tiên có số thứ tự là Phần tử cuối cùng có số thứ tự FileSize -1 Ví dụ : Ghi số 100 vào cuối tập tin DLIEU.DAT, dùng các lệnh: i:=100; Seek( F1, FileSize(F1) ) ; {Ðặt trỏ vào cuối tập tin} Write(F1, i); { Ghi gía trị i vào cuối tệp} Ví dụ 15.4: Nhập danh sách sinh viên gồm Họ tên, điểm Toán, Lý, tính điểm trung bình lưu vào tập tin HOSO.DAT Sau đó đọc liệu tập tin này và in màn hình Trong chương trình , chỗ nào có dấu ~ thì thay ký tự trắng PROGRAM VIDU15_4; Uses CRT; Const Tenttin = ‘HOSO.DAT’; Type Ksvien= Record Hoten: String[20]; Toan, Ly, Dtb : Real; end; KieuTtin = File of Ksvien ; Var F : KieuTtin ; (279) X : Ksvien ; i: Integer; Procedure Hienthi ( Var F : KieuTtin); begin Clrscr; Writeln(#32 :5, ‘HỌ VÀ TÊN’, #32:6 , ‘ÐTOÁN~~~ÐLÝ~~~~DTB’); Reset(F); While Not Eof(F) begin Read(F, X); Writeln(X.Hoten, #32:20-Length(X.Hoten), X.Toan:4:1,#32:3, X.Ly:4:1, #32:3, X.DTb:4:1); end; end; {Hết hiển thị} BEGIN Clrscr; Assign(F, TenTtin); Rewrite(F); i:=0; Repeat Clrscr; Gotoxy(10,4); Write( ‘NHẬP SINH VIÊN THỨ?‘, i , ‘: ( Enter để kết thúc) ‘ ); With X begin (280) Gotoxy(10,6); Write(‘Ho va ten:’); Gotoxy(10,8); Write(‘Ðiem Toan:’); Gotoxy(10,10); Write(‘Ðiem Ly :’); Gotoxy(20,6); Readln(Hoten); If Hoten<>’’ then begin Gotoxy(20,8); Readln(Toan); Gotoxy(20,10); Readln(Ly); DTB:=(Toan+Ly)/2; end; end; If X.Hoten<>’’ then Write(F,X); i:=i+1; Until X.Hoten=’’; Close(F); Hienthi(F); Close(F); Readln; END Chú ý : Nếu tham số chương trình là tập tin thì nó phải là tham số biến, không thể là tham số trị 15.2.3 Tập tin văn bản: Trong Pascal có kiểu tập tin đã định nghĩa sẵn, đó là kiểu TEXT hay tập tin văn Ðể khai báo F là biến tập tin văn ta viết : Var F: Text; (281) Các phần tử tập tin văn là các ký tự ghi thành dòng có độ dài khác Các dòng phân cách nhờ các dấu kết thúc dòng ( End of line) Ðó là hai ký tự điều khiển CR ( Carriage return : nhảy đầu dòng) và LF ( Line feed: xuống dòng dưới) Ví dụ , đoạn văn sau : Tap tin van ban Text 12345 Het chứa tập tin văn thành dãy : Tap tin van ban Text CR LF 12345 CR LF Het Eof Các thủ tục Assign, Rewrite, Reset, Write, Read, Close, Erase, Rename dùng cho tập tin văn Ngoài còn có thêm thủ tục Append(biếntậptin) dùng để mở tập tin văn và cho phép ghi thêm liệu vào cuối tập tin Ðối với tập tin văn bản, không thể đồng thời vừa ghi vừa đọc liệu tập tin có định kiểu Ðể ghi liệu, trước tiên phải khởi tạo tập tin lệnh Rewrite hay mở tập tin và đưa trỏ cuối tệp lệnh Append Sau đó ghi liệu vào tập tin thủ tục Write hay Writeln Ðể đọc liệu tập tin đã có, trước tiên ta phải mở tập tin lệnh Reset Sau đó đọc liệu thủ tục Read hay Readln Nếu mở tập tin Rewrite Append thì không thể đọc Read và Readln Nếu mở tập tin Reset thì không thể ghi Write hay Writeln Ghi liệu vào tập tin văn : Thủ tục WRITE( biếntậptin, bt1, bt2, , btN) : cho phép ghi các gía trị các biểu thức bt1, bt2, btN vào tập tin văn Các biểu thức bt1, bt2, btN phải thuộc kiểu đơn giản chuẩn ( nguyên, thực, ký tự, lôgic) hay kiểu chuỗi, và chúng không cần phải có kiểu giống Ví dụ : Write(F, 3, 10:4, ‘a’:2, ‘Text’, 4.5:6:2); ghi vào tập tin thành dãy sau ( Dấu ~ hiểu là ký tự trắng): 3~~10~aText~~4.50 Chương trình đây tạo tập tin văn T1.TXT : Program VIDU; Var F: Text; (282) A : Integer; B : Real; Begin A:=100; B:=1234.5; Assign(F, ’T1.TXT’); Rewrite(F); Write(F, ‘Ket qua=’ :10, A:5, B:7:2); Close(F); End Nội dung tập tin T1.TXT là : ~~Ket qua=~~100~123.45 Như vậy, cách ghi liệu vào tập tin văn hoàn toàn giống in liệu lên màn hình Thủ tục WRITELN có công dụng WRITE, ghi xong liệu thì đưa trỏ tập tin xuống dòng Ðặc biệt, lệnh Writeln(F); không ghi gì cả, đưa trỏ tập tin xuống dòng Nội dung các tập tin văn tạo Pascal hoàn toàn có thể xem lệnh Type MSDOS, Norton hay chính Turbo Pascal, Ðọc liệu tập tin văn : Thủ tục READ( biếntậptin, biến1, biến2, , biếnN) đọc các gía trị từ tập tin và gán cho các biến Các biến1, biến2, , biếnN phải có kiểu liệu phù hợp vơí liệu cần đọc vị trí tương ứng tập tin Ví dụ: Nếu tập tin T1.TXT có nội dung sau: ~~Ket qua=~~100~123.45 thì để đọc lại các liệu này, ta phải khai báo: Var St :String[10]; i: Integer ; Z : Real; Và dùng các lệnh: (283) Reset(F); Read(F, St, i, Z); Gía trị St, i, Z là: St=’~~Ket qua=’, i=100, Z=123.45 Nếu khai báo St có kiểu String[9] thì bị lỗi vì sau đọc xong ký tự đầu, máy đọc tiếp gía trị =~~100 cho biến nguyên i, vì gía trị này bắt đầu là dấu = nên không đổi số nguyên Thủ tục READLN(biếntậptin, biến1, biến2, , biếnN ) đọc liệu cho các biế? xong đưa trỏ tập tin xuống đầu dòng Ðặc biệt, lệnh READLN( biếntậptin); không đọc gì cả, đưa trỏ tập tin xuống dòng Chú ý Hàm Eof(F) dùng cho tập tin văn bản, ngoài còn có hàm EOLN(F) cho kết qủa là True False tùy theo trỏ tập tin có cuối dòng hay không Khi Eof(F)=True thì Eoln(F) có gía trị là True Thủ tục Seek và các hàm FileSize, FilePos không dùng cho tập tin văn Các tập tin văn ngầm định: Trong Pascal có hai biến tập tin văn đã khai báo sẵn là Input và Output , tức là máy đã ngầm khai báo : Var Input , Output : Text ; Input thường là bàn phím còn Output thường là màn hình Lệnh Readln(Input, x); viết tắt thành Readln( x) ; Lệnh Writeln(Output, x); viết tắt thành Writeln(x); Máy in là tập tin văn bản, ngầm khai báo với tên là LST Ðể in các biểu thức bt1, bt2, , btN máy in, ta phải khai báo sử dụng thư viện chuẩn PRINTER, và dùng lệnh : Write(LST, bt1, bt2, , btN); So sánh tập tin văn với tập tin định kiểu: Các tập tin có định kiểu cho phép vừa đọc vừa ghi và truy nhập trực tiếp vào phần tử gần giống thao tác với mảng Các tập tin văn không cho phép đồng thời đọc, ghi và có thể đọc ghi tuần tự, cho phép ta có thể xem, sửa trực tiếp cách dễ dàng các hệ soạn thảo văn đơn giản, NC hay chính Turbo Pascal (284) Ví dụ 15.5: Cho tập tin văn tên là T2.TXT và có nội dung là: dong=6 cot =7 8 -2 11 8020702 11 12 -2 11 -7 12 -7 11 9 6 Hãy đọc tập tin này đưa vào ma trận A và in ma trận A lên màn hình Số dòng và số cột ma trận A ghi hai dòng đầu tiên tập tin T2.TXT Program VIDU15_5; { vi du ve File Van ban } uses crt; Type MANG = array[1 20,1 20] of integer ; Var A : MANG; N, M : integer; F : Text; Procedure Nhap; Var i,j : Byte; st: string[5]; Begin Assign(F, 'T2.TXT'); (285) Reset(F); Readln(F, St, N); Readln(F, St, M); For i:=1 to N begin For j:=1 to M Read(F, A[i,j]); Readln(F); end; Close(F); End; Procedure InMatran; Var i, j : Integer; Begin For i:=1 to N begin for j:=1 to M write( A[i,j]:4); writeln; end; End; BEGIN Clrscr; Nhap; InMatran; Readln; END (286) 15.3 CÂU HỎI TRẮC NGHIỆM Câu 1: Khai báo nào đúng : a) Type T = Set of Real; b) Type T = Set of Integer; c) Type T = Set of String ; d) Type T = Set of ; Câu 2: Khai báo nào sai : a) Var T : Set of Char ; b) Var T : Set of -10 300 ; c) Var T : Set of ‘A’ ’z’ ; d) Var T : Set of Boolean ; Câu 3: Tổng [1 5] + [3 10, 20] là tập hợp nào: a) [1 10, 20] b) [1 5] c) [1 20] d) [3 5] Câu 4: Hiệu hai tập hợp [10 15]-[4 12] là tập hợp nào: a) [4 15] b) [13 15] c) [4 10] d) [10 12] (287) Câu 5: Cho khai báo: Var T : Set of Char ; ch : Char ; Sau thực các lệnh: T:=[‘A’ ‘D’] * [‘A’ ‘Z’]; For ch:=’A’ to ‘F’ T:=T+[ch] ; Tập T là: a) [‘A’ ’D’] b) [‘A’ ’Z’] c) [‘A’ ’F’] d) [‘C’ ’F’] Câu 6: Cho khai báo : Var F: File of Integer ; i , j , k :Integer ; Chọn câu có các lệnh đúng : a) Assign( F, T1.DAT ); Rewrite(F); Write(F, i, j, k ); b) Assign(F, ‘T1.DAT’ ); Rewrite(F); Write(F, i+ j+ k ); c) Assign(F); Rewrite( F, ‘T1.DAT’ ); Write(F, i, j, k ); d) Assign(F, ‘T1.DAT’ ); Rewrite(F); Write(F, i, j, k ); Câu 7: Khi chạy chương trình : Var F : File of Char; ch : Char; Begin Assign(F, ‘tt.txt’); Rewrite(F); (288) For ch:=’A’ to ‘F’ Write(F, ch); Seek(F, 4); Read(F, ch); Write(ch); Close(F); End Kết in là: a) E b) F c) C d) D Câu 8: Cho khai báo: Var F : TEXT ; Sau thực các lệnh: Assign(F, ‘tt1.txt’); Rewrite(F); Write(F, 123+456); Close(F); Nội dung tập tin tt1.txt là: a) 123+456 b) 123456 c) 579 d) 123 456 Câu 9: Cho F1 là biến tập tin có định kiểu và F2 là biến tập tin văn Lệnh nào không dùng : a) Seek( F1, 0); b) Seek(F2, 0); c) Write( Filesize(F1) ) ; (289) d) Write( FilePos(F1) ) ; Câu 10: Cho TT2.TXT là tập tin văn có nội dung là : Turbo Pascal 6.0 Khi chạy chương trình : Var F : Text; St : String[20]; Begin Assign(F, ‘tt2.txt’); Reset(F); Read(F, St); Write(St); Close(F); End in chữ : a) Turbo Pascal 6.0 b) Turbo c) Pascal 6.0 d) Turbo Pascal 15.4 BÀI TẬP Câu 1) Nhập chuỗi St, xây dựng ba tập hợp: S1 là tập các chữ hoa có St S2 là tập các chữ thường có St S3 là tập các chữ số có St In các gía trị tập S1, S2, S3 trên dòng Câu 2) Nhập vào mảng A1, A2, , A10 các số nguyên dương < 10 Hãy in các gía trị mảng này theo thứ tự tăng dần cho các phần tử trùng in lần Ví dụ : cho mảng 1, 6, 4,1, 9, 6, 6, 0, 3, , in ra: 0,1, 3, 4, 6, ( Hướng dẫn : xây dựng tập hợp gồm các phần tử mảng A) (290) Câu 3) Viết chương trình thực trò chơi sau: Người chơi nhập số k phạm vi từ đến Tạo tập S gồm ba số ngẫu nhiên phạm vi từ đến Kiểm tra xem k có thuộc tập S không? Nếu thuộc thì người chơi thắng, ngược lại là thua In k và tập S lên màn hình Hướng dẫn: Trong thư viện CRT có hàm Random(n) trả số ngẫu nhiên j thuộc phạm vi:  j < n Câu 4) Mỗi phân số mô tả sau : Type Phanso = Record tu, mau : Integer; end; Nhập hai phân số từ bàn phím, tạo tập tin chứa hai phân số đó và hai phân số là tổng, hiệu chúng Ðọc bốn phân số đó từ tập tin và in lên màn hình Câu 5) Nhập số nguyên dương N (0<N< 20 ) và dãy N số nguyên : A1, A2, , AN Ghi dãy số đó vào tập tin DL.DAT Ðếm tập tin DL.DAT có bao nhiêu số chẵn Ðọc các số lẻ từ tập DL.DAT và in lên màn hình Câu 6) Ðể quản lý Họ tên , các điểm Toán, Lý và Ðiểm trung bình sinh viên, ta mô tả kiểu Ksvien sau : Type Ksvien= Record Hoten: String[20]; Toan, Ly, Dtb : Real; end; Hãy nhập danh sách sinh viên gồm Họ tên, điểm Toán và điểm Lý, tính Ðiểm trung bình: Dtb:=(Toán+Lý)/2, lưu vào tập tin QLY.DAT Quá trình nhập kết thúc nhập Họ tên là rỗng ( tức không nhập gì cả, Enter) Ðọc danh sách sinh viên từ tập tin QLY.DAT và in danh sách lên màn hình Chép danh sách sinh viên vào tập QLY.IDX cho các phần tử QLY.IDX xếp theo trật tự giảm điểm trung bình Ðọc liệu tập tin QLY.IDX và ghi vào tập tin văn tên là QLY.TXT theo dạng : (291) STT Họ và tên Nguyen Van Tuan Pham Thi Mai   Ðiểm trung bình 8.5 8.0  Câu 7) Dùng hệ soạn thảo Turbo Pascal để tạo tập tin văn có tên là MT.DAT chứa hai ma trận vuông cấp là A và B có các phần tử là các số nguyên Lấy liệu từ tập tin MT.DAT để tính ma trận C=A+B Ghi ma trận C vào cuối tập tin MT.DAT Ðọc các ma trận A, B, C từ tập tin MT.DAT và in lên màn hình (292)

Ngày đăng: 08/06/2021, 03:05

Xem thêm:

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

  • Đang cập nhật ...

TÀI LIỆU LIÊN QUAN

w