Lập trình Pascal - Chương 6: Kiểu mảng
Tập chỉ số phải là một kiểu miền con, kiểu vô hướng liệt kê, kiểu char hoặc
kiểu boolean. Tuy nhiên. người ta thường dùng kiểu miền con các số nguyên là dễ
hình dung nhất vì nó gần giống với khái niệm chỉ số trong toán học.
Có hai cách khai báo là khai báo gián tiếp và khai báo trực tiếp.
Type
Vector = Array[1.10] of Integer;
Var
vt: Vector ;
Hoặc ta khai báo như sau:
Var
vt: Array[1.10] of Integer;
Ta thấy cách cách khai báo trực tiếp thì ngắn hơn, nhưng trong một số trường
hợp lại bất tiện, thậm chí không sử dụng được như khi truyền tham số cho các chương
trình con.
FALSE và ngược lại. - Phép so sánh <= (nhỏ hơn hoặc bằng). A <= B cho kết quả là True khi mọi phần tử của A đều có trong B. - Phép so sánh >= (lớn hơn hoặc bằng). A >= B cho kết quả là True khi mọi phần tử của B đều có trong A. Trang 13 III. VIẾT VÀ ĐỌC DỮ LIỆU TRÊN TẬP HỢP Đối với dữ liệu kiểu tập hợp ta không thể viết ra hoặc đọc vào bằng các lệnh Read, Readln, Write, Writeln. Tuy nhiên ta có thể lập trình thực hiện các thao tác này. Ví dụ sau sẽ nhập vào một tập hợp kiểu Char và in lên màn hình tập hợp vừa nhập. Type CHUCAI = SET OF CHAR; Var cc: CHUCAI; i, n: Integer; ch: Char; Begin Write(‘ Tập hợp có bao nhiêu phần tử? ‘); Readln(n); cc := []; For i := 1 to n do Begin Write(‘ Phần tử thứ ‘ ,i, ’ là: ’); Readln(ch); cc:= cc + [ch]; End; Writeln(‘Các phần tử trong tập hợp bạn vừa nhập’); For ch := ‘A’ to ‘z’ do If ch IN cc then Write(ch: 5); Readln; End. Trang 14 Chương 10: KIỂU MẨU TIN I. KHÁI NIỆM VÀ KHAI BÁO KIỂU MẨU TIN Chúng ta đã học các cấu trúc dữ liệu như mảng (Array), tập hợp (Set). Các kiểu dữ liệu này là một tập hợp có cùng kiểu do đó kả năng sử dụng các kiểu dữ liệu này còn hạn chế. Vấn đề đặt ra là có một kiểu cấu trúc dữ liệu có nhiều phần tử khác kiểu nhau nhưng lại liên quan đến nhau, người ta đã định nghĩa kiểu mẩu tin (RECORD) để đáp ứng vấn đề đó. Cấu trúc dữ liệu kiểu RECORD được gắn liền với cấu trúc dữ liệu kiểu FILE (được trình bày chương sau) để lưu trữ dữ liệu. Dĩ nhiên Pascal cũng cho phép sử dụng RECORD độc lập với FILE. Khai báo dữ liệu kiểu RECORD bắt đầu là chữ RECORD tiếp theo là danh sách các phần tử của Record gọi là các trường (Fields), mỗi trường có tên trường, kiểu trường. Kết thúc khai báo Record là tìư khoá END; (End và chấm phẩy). Ta xem cú pháp khai báo dưới đây. Ta hãy xét ví dụ dưới đây. Khai báo Record là các thuộc tính của học sinh. Type HOCSINH = RECORD Holot: String[30]; Ten: String[10]; Lop: Byte; Diachi: String; END; Var hsa, hsb, hsc: HOCSINH; Lop10A: Array[1..50] of HOCSINH; II. TRUY XUẤT MỘT MẨU TIN Để truy xuất một trường của Record, ta cần dùng tên biến kiểu Record sau đó là dấu . (chấm) rồi đến trường. Ví dụ ta sẽ nhập vào và in ra các thuộc tính của học sinh a (hsa) đã khai báo trên. Type HOCSINH = RECORD Holot: String[30]; Ten: String[10]; Lop: Byte; Diachi: String; END; Var hsa: HOCSINH; Cú pháp: = RECORD [, ]: [, ]: ........................................................................ END; Trang 15 Begin Write(‘ Nhập vào họ và các chữ lót: ‘); Readln(hsa.Holot); Write(‘ Nhập vào tên: ‘); Readln(hsa.Ten); Write(‘ Nhập vào lớp: ‘); Readln(hsa.Lop); Write(‘ Nhập vào địa chỉ: ‘); Readln(hsa.Diachi); Writeln(‘ Thông tin về học sinh bạn vừa nhập ’); Writeln(‘ Họ và tên: ’ , hsa. Holot,’ ‘, hsa.Ten); Writeln(‘ Lớp: ’ , hsa.Lop); Writeln(‘ Địa chỉ: ’ , hsa.Diachi); Readln; End. Ta lưu ý lệnh hsb := hsa là sao chép toàn bộ hsa vào hsb. Đây là việc truy xuất vào toàn bộ biến kiểu Record chứ không riêng lẻ một trường nào cả. III. CÂU LỆNH WITH…DO Như trên ta thấy việc truy xuất một trường biến kiểu Record phải thông qua tên và dấu chấm, làm phức tạp thêm chương trình, giải quyết bớt phần nào sự phức tạp này, Pascal đưa ra câu lệnh With … do ta hãy viết chương trình nhập học sinh của lớp 10A đã khai báo ở trên, có dùng lệnh With … do. Var Lop10A: Array[1..50] of HOCSINH; i, n: Integer; Begin Write(‘ Lớp có bao nhiêu học sinh? ‘); Readln(n); For i:=1 to n do With Lop10A[i] do Begin Write(‘ Nhập họ và các chữ lót: ‘); Readln(Holot); Write(‘ Nhập vào tên: ‘); Readln(Ten); Write(‘ Nhập vào lớp: ‘); Readln(Lop); Write(‘ Nhập vào địa chỉ: ‘); Readln(Diachi); End; Writeln(‘ Thông tin về các học sinh bạn vừa nhập ’); For i:=1 to n do With Lop10A[i] do Begin Writeln(‘ Họ và tên: ’ , Holot,’ ‘, Ten); Writeln(‘ Lớp: ’ , Lop); Writeln(‘ Địa chỉ: ’ , Diachi); End; Readln; End. Trang 16 Chương 11: KIỂU TẬP TIN I. KHÁI NIỆM Đối với các kiểu cấu trúc dữ liệu ta đã biết như kiểu mảng, kiểu tập hợp, kiểu Record, dữ liệu được tổ chức trên bộ nhớ trong (RAM) của máy tính nên khi kết thúc chương trình thì dữ liệu cũng mất luôn. Điều này thật tai hại vì khi cần ta phải nhập dữ liệu lại - một công việcchẳng thú vị gì và rất mất thời gian. Để giải quyết vấn đề này, người ta đặt ra kiểu tập tin (File). Kiểu FILE cho phép lưu trữ dữ liệu ở bộ nhớ ngoài (trên đĩa cứng hay đĩa mềm…), khi kết thúc chương trình hay khi tắt máy thì dữ liệu vẫn còn nên có thể sử dụng nhiều lần. Trong Pascal, tập tin có 3 loại: tập tin định kiểu, tập tin văn bản và tập tin tổng quát. II. TẬP TIN ĐỊNH KIỂU 1. Khai Báo Khai báo gián tiếp Type TAPTINKYTU = FILE OF CHAR; Var fc: TAPTINKYTU; Khai báo trực tiếp Var fc: FILE OF CHAR; Kiểu của tập tin có thể là bất kỳ một kiểu dữ liệu nào, trừ chính bản thân nó, nghĩa là không có tập tin của tập tin. 2. Truy Xuất Các Phần Tử Của Tập Tin Muốn truy xuất một phần tử của tập tin ta phải có một biến trung gian, kiểu của biến trung gian này phải tương tích với kiểu của các phần tử trong tập tin. Biến trung gian này gọi là con trỏ tập tin. Mỗi tập tin có một con trỏ tập tin riêng. Con trỏ tập tin có thể di chuyển trong toàn bộ tập tin và khi con trỏ tập tin ở tại phần tử nào thì ta chỉ có thể truy xuất tại vị trí đó mà thôi. Như vậy, mỗi lần chỉ có thể truy xuất được một phần tử. Muốn truy xuất phần tử nào thì con trỏ tập tin phải di chuyển đến phần tử đó. Có hai cách để di chuyển con trỏ tập tin là di chuyển tuần tự từ đầu đến cuối tập tin hoặc di chuyển trực tiếp từ phần tử này sang phần tử khác bất kể hai phần tử đó có kế tiếp nhau không. 3. Các Thủ Tục Và Hàm Trên Tập Tin Ta dùng chữ FileVar để chỉ biến kiểu tập tin. Trong những thủ tục và hàm trình bày ở chương này, có một số cũng được sử dụng cho tập tin văn bản, các hàm và thủ tục đó sẽ có dấu * sau đề mục để người đọc tiện theo dõi. Cú pháp: = FILE OF ; Trang 17 a. Thủ tục ASSIGN(FileVar, FileName)* FileName là tên của tập tin do đó phải tuân thủ qui cách đặt tên của MS-DOS. Tổng quát FileName là một PathName để dẫn đường truy xuất một tập tin trên đĩa từ. Lệnh này dùng để gán tên tập tin FileName vào biến tập tin FileVar. Sau lệnh này mọi thao tác trên FileVar thực tế là thao tác trên tập tin FileName trên đĩa từ. Ví dụ: Var fc: FILE OF CHAR; Assign(fc, ‘A:\VanBan.txt’); b. Thủ tục REWRITE(FileVar)* Tạo mới trên đĩa từ tập tin có tên là FileName (đã được khai báo trong lệnh Assign). Nếu FileName đã có thì nội dung của nó bị xoá và con trỏ tập tin đặt ở đầu tập tin. Như vậy sau lệnh này trên đĩa từ sẽ có tập tin là FileName với nội dung rỗng. Thông tin mới sẽ được đưa vào nhờ lệnh Write sẽ được đề cập sau. c. Thủ tục RESET(FileVar)* Mở trên đĩa từ tập tin có tên là FileName (đã được khai báo trong lệnh Assign). Con trỏ tập tin đặt ở đầu tập tin. Thông tin sẽ được đọc ra nhờ lệnh Read sẽ được đề cập sau. d. Thủ tục WRITE(FileVar, x1, x2,…, xn) Các biến x1, x2,…, xn phải thuộc kiểu phần tử của FileVar. Lệnh này cho phép ghi thông tin mới vào tập tin có tên là FileName. Thông tin sẽ được ghi vào tại vị trí con trỏ tập tin đang đứng, sau khi ghi xong một giá trị con trỏ tập tin sẽ chuyển đến phần tử kế tiếp. e. Thủ tục READ(FileVar, x1, x2,…, xn) Các biến x1, x2,…, xn phải thuộc kiểu phần tử của FileVar. Lệnh này cho phép đọc thông tin từ tập tin có tên là FileName. Thông tin sẽ được đọc ra tại vị trí con trỏ gán vào các biến tương ứng. Sau khi đọc xong một giá trị con trỏ tập tin sẽ chuyển đến phần tử kế tiếp. f. Thủ tục SEEK(FileVar, n) Biến n là một biến số nguyên chỉ số thứ tự của phần tử trong tập tin. Phần tử thứ nhất có số thứ tự là 0. Thủ tục này dịch con trỏ tập tin đến vị trí thứ n của tập tin. g. Hàm FILEPOS(FileVar): Integer Cho kết quả là một số nguyên chỉ vị trí hiện tại của con trỏ tập tin. h. Hàm FILESIZE(FileVar): Integer Cho kết quả là một số nguyên chỉ số lượng phần tử có trong tập tin. FileSize nhận giá trị 0 khi không có một phần tử nào. Để đưa con trỏ về cuối tập tin ta có thể dùng lệnh: Seek(FileVar, FileSize(FileVar)). Trang 18 i. Thủ tục FLUSH(FileVar)* Cho phép đẩy thông tin nằm trong vùng nhớ đệm của tập tin ra đĩa từ. j. Thủ tục CLOSE(FileVar)* Đóng tập tin lại và cập nhật thư mục để phản ánh trạng thái mới của tập tin. k. Thủ tục ERASE(FileVar)* Xoá tập tin trên đĩa. Chú ý: tập tin phải đóng trước khi xoá. l. Thủ tục RENAME(FileVar, NewName)* Đổi tên tập tin thành NeưName. NewName là một chuỗi ký tự theo qui tắc đặt tên tập tin (tổng quát là một PathName). m. Hàm EOF(FileVar): Boolean* Cho kết quả là True nếu con trỏ tập tin ở cuối tập tin. Người ta dùng hàm này để kiểm tra tình trạng hết tập tin hay chưa. 4. Kiểm Tra Tập Tin Khi Mở Có một vài điều ta cần chú ý khi làm việc với tập tin, như các trường hợp nêu ra dưới đây. - Ta dùng thủ tục RESET để mở một tập tin phải có trên đĩa. Nếu trên thực tế, tập tin này không có trên đĩa thì Pascal sẽ báo lỗi “File not found” và ngừng thực hiện. - Khi chúng ta dùng lệnh REWRITE để tạo mới một tập tin lên đĩa. Nếu tập tin ta tạo trùng tên với một tập tin đã có trên đĩa, thì nội dung của tập tin cũ bị xoá hết. Để khắc phục trình trạng trên, ta sử dụng hướng biên dịch của Pascal, kiểm tra vào/ra bằng hàm IOResult. - {$I+} Mở kiểm tra, khi có lỗi vào/ra thì chương trình sẽ báo lỗi và dừng thực hiện. - {$I-} Tắt kiểm tra tồn tại của tập tin để thông báo lỗi. - Hàm IOResult: Word. Hàm này dùng để kiểm tra lỗi vào/ra và cho kết quả là một số nguyên kiểu Word. Ta thường dùng hàm này để kiểm tra một tập tin có tồn tại trên đĩa hay không, hàm IOResult được kiểm tra sau lệnh Reset, nếu hàm trả về 0 thì tập tin đã có trên đĩa, ngược lại tập tin chưa tồn tại trên đĩa.
File đính kèm:
- Lập trình Pascal - Chương 6_Kiểu mảng.pdf