Professional Documents
Culture Documents
Nội dung
C7: Kiểu Set (tập hợp)
C8: Kiểu Record (bản ghi)
C9: Kiểu File (tệp)
C10: Kiểu Pointer (con trỏ)
1. Nguyễn Quý Khang, Kiều Văn Hưng, Bài tập Pascal (tập 1), NXB ĐHQG
Hà Nội, 2002 (hoặc Bài tập Pascal, ĐHSP Hà Nội 2).
2. Quách Tuấn Ngọc, Ngôn ngữ lập trình Pascal, NXBGD, 1996.
3. Bùi Thế Tâm, Văn Văn Tuấn Dũng, Turbo Pascal 7.0, NXB Thống kê,
1996.
1
Chương 7
KIỂU SET (TẬP HỢP)
Khai báo
• Khai báo kiểu tập hợp
trong đó
KieuTH: từ tự đặt xđ kiểu tập hợp;
KieuCS: kiểu dữ liệu của phần tử.
2
VD 7.1 (khai báo kiểu, biến tập hợp)
Chú ý
(i) Vị trí của các phần tử trong tập hợp không có ý nghĩa ([1, 2] = [2, 1]).
(ii) Dùng lệnh gán để thay đổi giá trị cho các biến tập hợp.
(iii) Không dùng lệnh Read và Write trực tiếp cho dữ liệu kiểu tập hợp.
TH := TH + [pt]; {Thêm pt}
if pt in TH then Write(pt); {Viết pt}
Phép hợp (+), giao (*), hiệu (-), bao hàm (IN): giống như trong toán học.
A := [1, 3]; B := [2, 3, 4]
2 in A FALSE
Phép so sánh (=, <>, <=, >=): kết quả có kiểu logic (TRUE/FALSE).
A <= B có KQ là TRUE nếu A là tập con của B, trái lại KQ là FALSE.
A >= B có KQ là TRUE nếu A bao hàm tập B, trái lại KQ là FALSE.
Không có phép so sánh < và > trên kiểu tập hợp trong Pascal.
7.3 VÍ DỤ
3
VD 7.2 (Phân loại kí tự) Lập trình nhập vào một kí tự. Kiểm tra xem kí tự đó chữ cái, chữ số
hay kí tự khác?
Hướng dẫn: khai báo biến ch kiểu Char và 2 biến ChuCai, ChuSo kiểu tập hợp kí tự, rồi
gán giá trị:
ChuCai := ['A'..'Z', 'a'..'z']
ChuSo := ['0'..'9']
VD 7.3 (Bán vé máy bay, BT 6.9, tr. 187) Một máy chứa tối đa 250 hành khách, với các ghế
được đánh số 1, 2, ..., 250. Lập trình bán vé máy bay, yêu cầu hiện lên các số ghế còn trống để
khách lựa chọn.
Hướng dẫn: Tạo tập V = [1..250] tương ứng với số ghế trên các vé và liệt kê chúng ra màn
hình.
Dùng vòng lặp không xác định để nhập số ghế mà hành khách chọn. Một số ghế đã
chọn thì số đó không còn trong V và trên màn hình.
Chương 8
KIỂU RECORD (BẢN GHI)
4
Khái niệm
• Kiểu bản ghi (Record) là một kiểu dữ liệu có cấu trúc gồm nhiều thành phần và được gọi
là field - trường.
Mỗi trường được đặt tên và các trường có thể có các kiểu dữ liệu khác nhau.
• Kiểu bản ghi dùng để mô tả các đối tượng có cùng một số thuộc tính mà các thuộc tính có
thể có kiểu dữ liệu khác nhau.
Chẳng hạn, bảng kết quả thi TSĐH gồm thông tin về các thí sinh như: họ tên, SBD, ngày
sinh, giới tính, điểm môn 1, 2, 3, ... mà các thông tin này thuộc các kiểu dữ liệu khác nhau.
Khai báo
• Khai báo kiểu bản ghi
5
Cách 2 (khai báo gián tiếp)
HSTS = RECORD
hoten : String[25];
sbd : String[8];
ngaysinh : String[10];
gt : Boolean;
mon1, mon2, mon3,
tong : Real;
KQ : String[10];
END;
HSCB = RECORD
hoten : String[25];
ngaysinh : String[10];
chucvu : String[15];
Luong : Real;
Ghichu : String[10];
END;
VAR {Khai bao bien ban ghi}
ts : HSTS;
cb : HSCB;
sv : Record
hoten : String[25];
lop : String[5];
tuoi : Byte
dtb: Real;
End;
6
8.2 SỬ DỤNG RECORD
Chỉ được phép truy nhập tới các trường của biến Record
BienBG.Truong
Các thao tác truy nhập:
- Nhập: Readln(BienBG.Truong);
- Xuất: Write(BienBG.Truong);
Chú ý
(i) Không dùng thủ tục Read, Readln, Write, Writeln cho một biến Record.
Write(bg); {SAI !}
Readln(bg) {bg - biến Record}
(ii) Không dùng các phép toán số học, logic, so sánh (= , <>, >, >=, <, <=)
đối với các biến Record.
Type
HSSV = record
hoten:string[20];
dtb:real;
end;
var s1, s2: HSSV;
begin
s1.hoten:= 'Mot'; s1.dtb:= 1.1;
s2.hoten:= 'Hai'; s2.dtb:= 2.2;
if (s1=s2) then writeln('s1 = s2')
else
writeln('SV1 khac SV2!');
7
Readln;
end.
VD 8.3 (Khoảng cách giữa 2 điểm) Lập trình nhập vào toạ độ 2 điểm A(xA, yA), B(xB, yB)
trong hệ toạ độ đềcác. Tính d(A, B).
Hướng dẫn:
- Khai báo 2 biến A, B kiểu Record với 2 trường x, y (kiểu thực).
- Tính d(A, B) theo công thức:
Sqrt(Sqr(xA-xB) + Sqr(yA-yB))
VD 8.4 (Xếp loại học bổng) Lập trình nhập vào danh sách N sinh viên (N < 1000) với các
thuộc tính họ tên, ngày sinh, lớp, điểm trung bình mở rộng, học bổng. Xếp loại học bổng cho
các SV theo quy định hiện hành và in kết quả ra màn hình.
Hướng dẫn:
- Khai báo 1 biến SV kiểu mảng Record, mỗi phần tử của mảng lưu trữ thông tin cho
một SV.
- Nhập N và dùng lệnh FOR để nhập thông tin của mỗi SV gồm họ tên, ngày sinh,
lớp, điểm trung bình mở rộng vào biến SV, đồng thời dùng lệnh IF để gán trị cho
trường học bổng.
- Dùng lệnh FOR để in DS ra màn hình.
WITH BienBG DO
begin
T1:= ...;
Readln(T2);
...
Write(Tn);
end;
8
truy nhập đơn giản tới các trường (T1, ..., Tn) của biến bản ghi (BienBG).
8.3 RECORD CÓ CẤU TRÚC THAY ĐỔI (Tham khảo [3], tr. 140)
Chương 9
KIỂU FILE (TỆP)
9
Khái niệm về tệp
• Tệp (File, tập tin, hồ sơ) dữ liệu là một tập hợp các dữ liệu có liên quan với nhau, có cùng
kiểu được tổ chức thành dãy, và được lưu trữ ở bộ nhớ ngoài (đĩa, băng từ).
EOF
• Tệp dùng để lưu trữ dữ liệu: dữ liệu trong tệp được dùng nhiều lần và tồn tại cả khi kết
thúc chương trình hay mất điện (khác với các kiểu mảng, xâu, bản ghi,...).
• Các loại tệp trong TP: tệp văn bản (TEXT file), tệp định kiểu (Typed file), tệp không định
kiểu (Untyped file).
TYPE
KieuTep = FILE OF KieuPT;
trong đó KieuTep là một từ tự đặt xác định kiểu tệp, KieuPT là kiểu dữ liệu của phần
tử (Real, String, Array, Record, ... trừ kiểu file).
10
VD 9.1 (khai báo kiểu, biến tệp)
TYPE {Đinh nghia cac kieu tep}
FileInteger = FILE OF Integer;
FileReal = FILE OF Real;
HosoSV= RECORD
hoten: String[25];
lop: String[5];
dtb: Real;
END;
FHosoSV = FILE OF HosoSV;
• Các phần tử của ARRAY hay RECORD được truy nhập ngẫu nhiên thông qua tên biến và
chỉ số / tên trường.
Một phần tử của tệp được truy nhập thông qua giá trị của một biến đệm (tampon
variable). Biến đệm được dùng để đánh dấu vị trí truy nhập hay còn gọi là cửa sổ
(window) của tệp.
• Có lệnh để di chuyển cửa sổ tệp sang vị trí khác (Reset, Seek, ...).
• Mỗi tệp có một dấu hiệu kết thúc tệp - EOF (End of File).
Hàm chuẩn EOF(f) trả về TRUE nếu cửa sổ ở vị trí dấu hiệu kết thúc tệp f, trái lại hàm
trả về FALSE.
Mỗi ô là 1 phần tử của tệp
Chỉ số ptử 0 1 2 ...
Các ptử EOF
• Phân loại tệp theo bố trí các phần tử và cách truy nhập tệp: tệp truy nhập tuần tự
(sequential access), tệp truy nhập trực tiếp (direct access).
Tệp truy nhập tuần tự: việc đọc một phần tửCửa sổ phải
bắt buộc tệptuần tự đi qua các phần tử
trước đó. Ghi một phần tử phải ghi vào sau phần tử cuối tệp.
11
Tệp truy nhập trực tiếp: để đọc/ghi, có thể đặt cửa sổ vào phần tử bất kỳ thông qua chỉ
số thứ tự của phần tử trong tệp.
Trong Pascal chuẩn chỉ có tệp truy nhập tuần tự.
Chú ý:
ARRAY FILE
- Tập các dữ liệu cùng kiểu - Tập các dữ liệu cùng kiểu
- Chứa tạm trong RAM - Lưu trữ trên đĩa, băng từ
- Truy nhập ngẫu nhiên đến các phần tử qua chỉ số - Truy nhập ngẫu nhiên hay tuần tự đến các phần tử qua chỉ số
- Số phần tử xác định khi khai báo - Số phần tử không xác định khi khai báo
Biến tệp đại diện cho một tệp. Việc truy xuất dữ liệu trên tệp được thể hiện qua các lệnh với
thông số là biến tệp.
• Mở tệp để ghi
ASSIGN(BienTep, TenTep);
REWRITE(BienTep);
trong đó BienTep là một biến kiểu tệp; TenTep là một xâu kí tự xác định tên của tệp
(quy tắc đặt tên tệp theo quy định của hệ điều hành).
Chú ý:
12
• Ghi vào tệp với thủ tục WRITE
trong đó BienTep là biến tệp đã được dùng để mở tệp; b1, ..., bN là các biến (có cùng
kiểu thành phần của BienTep) cần ghi vào tệp.
28 8 2006 EOF
trong đó BienTep là biến tệp đã được dùng để mở tệp. Việc đóng tệp đối với tệp mới
tạo nhằm đảm bảo dữ liệu đã ghi không bị mất.
VD 9.4 Lập trình nhập vào số nguyên dương N < 1000, sau đó tạo tệp SN.DAT chứa N số
nguyên ngẫu nhiên.
VD 9.5 Tạo tệp chứa 100 số nguyên dương đầu tiên (sử dụng CTC).
Biến tệp dùng làm tham số trong CTC bắt buộc phải là tham biến (khai báo có VAR ở
trước).
13
• Mở tệp để đọc
ASSIGN(BienTep, TenTep);
RESET(BienTep);
trong đó BienTep là một biến kiểu tệp; TenTep là một xâu kí tự xác định tên của tệp.
Sau lệnh RESET(BienTep), nếu tệp không rỗng thì cửa sổ tệp ở phần tử đầu tiên.
Nếu tệp chưa tồn tại (hoặc sai đường dẫn) thì sẽ có thông báo lỗi (File not found).
trong đó BienTep là biến tệp đã được dùng để mở tệp; b1, ..., bN là các biến có cùng
kiểu thành phần của BienTep.
- Lệnh READ(BienTep, ...) sẽ đọc giá trị tại các vị trí cửa sổ ra các biến tương ứng.
Đọc xong một giá trị, cửa sổ sẽ chuyển sang vị trí tiếp theo và đọc giá trị cho biến
khác, cứ thế cho đến biến bN.
- Để đọc tất cả các phần tử của tệp, dùng đoạn lệnh sau:
RESET(BienTep);
WHILE not EOF(BienTep) DO
BEGIN
READ(BienTep, x); {Đọc một phần tử của tệp và gán vào biến x}
... {Xử lý biến x}
END;
VD 9.6 Lập trình đọc dữ liệu từ tệp SN.DAT (chứa các số nguyên). Cho biết trong tệp này có
bao nhiêu phần tử (không dùng hàm FileSize)? Có bao nhiêu số nguyên tố?
Bài tập. Lập trình đọc dữ liệu từ tệp SN.DAT (chứa các số nguyên), ghi các số dương vào tệp
SND.DAT, còn các số âm ghi vào tệp SNA.DAT.
14
Viết một chương trình khác để đọc dữ liệu trong các tệp SND.DAT, SNA.DAT và in chúng ra
màn hình để kiểm tra.
SEEK(BienTep, k);
trong đó BienTep là biến tệp đã được dùng để mở tệp; k là chỉ số của phần tử trong tệp
(phần tử đầu tiên có chỉ số là 0).
Thủ tục SEEK(BienTep, k) sẽ đặt cửa sổ tệp vào phần tử có chỉ số k. Dùng thủ tục
READ(BienTep, ...) để đọc phần tử này ra, dùng thủ tục WRITE(BienTep, ...) để ghi
giá trị mới vào phần tử này.
VD 9.7 Lập trình đọc dữ liệu từ tệp SN.DAT (chứa các số nguyên). Hãy kiểm tra xem phần tử
thứ hai (nếu có) của tệp có là số dương không? Nếu không, hãy thay nó bằng một số
nguyên dương nhập từ bàn phím.
Hướng dẫn
15
Một số CTC xử lý tệp của Turbo Pascal
• Hàm FileSize
FileSize(BienTep);
trả về số phần tử của tệp BienTep (hàm trả về 0 nếu tệp rỗng).
• Hàm FilePos
FilePos(BienTep);
trả về chỉ số của phần tử mà cửa sổ của tệp BienTep đang ở đó (phần tử đầu tiên có chỉ
số 0).
- Để thêm phần tử vào cuối tệp:
SEEK(BienTep, FileSize(BienTep));
WRITE(BienTep, ...);
- Ghi lại sự thay đổi của tệp: CLOSE(BienTep);
• Thủ tục ERASE
ERASE(BienTep);
xóa tệp trên đĩa đã được gán BienTep bởi thủ tục ASSIGN(BienTep, TenTep); trước
đó.
Chẳng hạn, để xóa tệp SN.BAK trên đĩa:
ASSIGN(f, ’SN.BAK’);
ERASE(f);
• Thủ tục RENAME
RENAME(BienTep, TenTepMoi);
đổi tên tệp ở trạng thái đóng với tên mới (không được trùng với tên tệp khác đã có) đặt
trong xâu TenTepMoi; tệp đã được gán BienTep bởi thủ tục ASSIGN(BienTep,
TenTep); trước đó.
Chẳng hạn, để đổi tên tệp SN.DAT thành SN2.DAT:
16
ASSIGN(f, ’SN.DAT’);
RENAME(f, ’SN2.DAT’);
• Vấn đề
{$I+}: Dừng chương trình và báo lỗi khi có lỗi vào/ra (ngầm định);
{$I-}: Không dừng chương trình khi có lỗi vào/ra.
Hàm IOResult = 0 nếu vào/ra tệp không có lỗi.
VD 9.8 Lập trình kiểm tra sự tồn tại của một tập tin tuỳ ý trên đĩa (xem Bài tập 8.1).
• Tệp văn bản là một kiểu tệp được định nghĩa trước trong TP, với từ chuẩn Text.
• Các phần tử của tệp kiểu Text là các ký tự, và được tổ chức thành các dòng, mỗi dòng kết
thúc bởi dấu hiệu EOLN (End Of Line: CR LF).
CR - Carriage Return (về đầu dòng, mã ASCII= 13)
LF - Line Feed (xuống dòng tiếp theo, mã ASCII= 10)
Dấu hiệu kết thúc tệp văn bản (EOF) trong TP là Ctrl+Z (mã ASCII = 26).
VD 9.9 (cấu trúc tệp văn bản) Nếu một tệp văn bản có nội dung:
Turbo Pascal
Ver 7.0
Borland Inter., Inc.
thì sẽ có cấu trúc là
Turbo Pascal Borland Inter., Inc.
CR LF Ver 7.0 CR LF EOF
17
• File of Char mỗi phần tử là một ký tự. Các ký tự CR, LF, CTRL+Z được xử lý như các ký
tự bình thường.
• Hàm EOF(Var F: Text): Boolean; Hàm trả về giá trị False khi cửa sổ tệp chưa đến cuối
tệp, ngược lại, cho giá trị True (hàm dùng để kiểm tra đã đọc hết tệp văn bản chưa).
• Hàm EOLN(Var F: Text): Boolean; Hàm trả về giá trị False khi cửa sổ tệp chưa đến điểm
cuối dòng hoặc cuối tệp, ngược lại, cho giá trị True. Hàm này thường sử dụng để kiểm
tra xem đã đọc đến cuối dòng chưa. Chẳng hạn:
While not EOLN(F) Do ...
Có thể ghi các giá trị kiểu Integer, Real, Boolean, String vào tệp văn bản bằng lệnh
WRITE hoặc WRITELN.
WRITE (BienTep, bt1, ... , btN); (1)
WRITELN(BienTep); (3)
• Lệnh (1): Ghi giá trị các biểu thức bt1, ... , btN có kiểu: nguyên, thực, ký tự, xâu, logic vào
BienTep.
• Lệnh (2): Tương tự như (1) nhưng thêm dấu hiệu hết dòng sau các giá trị của bt1, ... , btN.
• Ghi chú: Các lệnh (1), (2) có thể viết có định dạng (quy cách) như viết ra màn hình.
Chẳng hạn:
WRITE(f, 'Pascal': 20, 1509 + 20.06: 10: 1);
VD 9.10 Lập trình tạo tệp văn bản TP70.TXT với nội dung như sau:
**********************************************************************
* *
* *
* *
**********************************************************************
18
Đọc dữ liệu từ tệp văn bản
Read (BienTep, b1, ..., bN); (1)
Readln(BienTep, b1, ..., bN); (2)
Readln(BienTep); (3)
trong đó b1, ...,bN là các biến thuộc kiểu kí tự, nguyên, thực, logic, chuỗi.
• Lệnh (1): đọc từ tệp ra các biến b1, ..., bN mà không chuyển cửa sổ tệp xuống dòng.
• Lệnh (2): đọc từ tệp ra các biến b1, ..., bN và chuyển cửa sổ tệp xuống dòng.
• Lệnh (3): chuyển cửa sổ tệp xuống dòng.
VD 9.11 Lập trình đọc tệp văn bản và in nội dung tệp đó ra màn hình.
mở tệp văn bản để ghi thêm vào cuối tệp với thủ tục Write(...) hay Writeln(...).
VD 9.12 Lập trình ghi thêm một số dòng vào cuối tệp TP70.TXT.
• LST: tệp máy in (trong Unit PRINTER.TPU khai báo Uses Printer; khi dùng).
VD 9.13 Lập trình tạo bảng mã ASCII và ghi vào tệp văn bản ASCII.TXT.
VD 9.14 Lập trình tạo bảng cửu chương và ghi vào tệp văn bản B9C.TXT.
VD 9.15 Lập trình đọc dữ liệu từ tệp SN.DAT (đã có trên đĩa), ghi các số dương vào tệp văn
bản SND.TXT.
19
VD 9.16 Lập trình giải phương trình bậc 2
ax2 + bx + c = 0 (a <> 0)
Đọc dữ liệu từ tệp văn bản GPT2.INP gồm 1 dòng ghi 3 số thực a, b, c.
Kết quả ghi vào tệp văn bản GPT2.OUT có cấu trúc như sau:
Dòng đầu tiên ghi số nghiệm của phương trình.
Các dòng tiếp theo, mỗi dòng ghi một giá trị nghiệm nếu có (lấy 2 chữ số thập phân).
Khái niệm
• Tệp không định kiểu: kiểu tệp đặc biệt trong TP, được khai báo với từ khoá File.
• Khi khai báo tệp không định nghĩa kiểu, không nêu rõ bản chất của dữ liệu ghi trong tệp.
VD 9.17 Lập trình tạo chương trình copy một tệp tuỳ ý.
20
• Rất phổ biến: ở đâu có tổ chức xã hội thì ở đó có nhu cầu quản lý.
Thuật toán
• Bài toán: Giả sử hồ sơ tuyển sinh của một thí sinh gồm: họ tên, SBD, điểm môn 1, môn 2,
môn 3, tổng điểm và kết quả thi. Dùng kiểu tệp các bản ghi, lập trình giải quyết các việc:
Nhập hồ sơ cho các thí sinh
In danh sách phòng thi
Tính toán và xét kết quả thi (điểm chuẩn là 22,0)
Xem kết quả thi của thí sinh theo SBD
In bảng kết quả thi (màn hình/máy in)
Thống kê kết quả thi
21
• Khai báo hằng, kiểu và biến
uses Crt;
const
fn = 'HOSOTS.DAT';
type
HosoTS = record
hoten: String[25];
sbd: String[8];
mon1, mon2, mon3, tong: Real;
kq: String[10];
end;
FHosoTS = file of HosoTS;
var
f: FHosoTS;
• Một số CTC
procedure NhapHS(var f: FHosoTS);
var
ts: HosoTS; ht: String[25]; i: Word;
begin
Assign(f, fn); {$I-} Reset(f); {$I+};
{Neu tep chua co thi tao moi}
if IOResult <> 0 then Rewrite(f);
ClrScr;
Writeln('Nhap ho so, go ho ten trong de ket thuc !');
22
i := FileSize(f) + 1;
repeat
Writeln('Thi sinh thu ', i);
Write('Ho ten: '); Readln(ht);
if ht <> '' then
begin
ts.hoten := ht;
Write('So bao danh: '); Readln(ts.sbd);
Write('Diem mon 1, mon 2, mon 3: ');
Readln(ts.mon1, ts.mon2, ts.mon3);
Seek(f, i-1); Write(f, ts);
i := i+1;
end;
until ht = '';
Close(f);
Write(#10#13,'So ho so trong tep ', fn, ' la: ', i,
'. An phim ENTER.');
Readln;
end;
procedure InDSPT(var f: FHosoTS);
var ts, ts1, ts2: HosoTS; i, j, n: Word; pthi, stt: Byte;
begin
{Sap xep theo ho ten thi sinh}
Assign(f, fn); Reset(f); {fn='HOSOTS.DAT'}
n:= FileSize(f);
for i:= 0 to n - 2 do
for j:= i+1 to n - 1 do begin
Seek(f, i); Read(f,ts1); Seek(f, j); Read(f,ts2);
if ts1.hoten > ts2.hoten then begin
Seek(f, j); Write(f,ts1); Seek(f, i); Write(f,ts2);
end;
end;
{In danh sach phong thi}
ClrScr;
Seek(f, 0); {Dua con tro ve dau tep}
pthi:= 1; {So phong thi tu 1}
while not Eof(f) do begin
Writeln('DANH SACH THI SINH THI TSDH NAM ...');
Writeln(' Phong thi so: ', pthi); Writeln;
Writeln('+----+-------------------+-------+--------+-----------+');
Writeln('|STT| Ho va ten |SoBD|Chu ki| Ghi chu |');
Writeln('+----+-------------------+-------+--------+-----------+');
stt := 1;
while (stt < 18)and(not Eof(f)) do begin {In: stt < 41}
Read(f, ts);
With ts do
Writeln('|', stt: 3, '|', hoten: 25, '|', sbd: 8,
'|', #32:12, '|',#32:9,'|');
Inc(stt);
end;
Inc(pthi);
Write(#10#13,'An phim ENTER tiep tuc... '); Readln;
end;
Close(f);
end;
23
procedure InKQ(var f: FHosoTS);
var ts, ts1, ts2: HosoTS;
i, j, n: Word; soto, stt: Byte;
begin
Assign(f, fn); Reset(f); {fn = 'HOSOTS.DAT'}
{Sap xep giam theo tong diem}
n:= FileSize(f);
for i:= 0 to n - 2 do
for j:= i+1 to n - 1 do
begin
Seek(f, i); Read(f,ts1); Seek(f, j); Read(f,ts2);
if ts1.tong < ts2.tong then
begin
Seek(f, j); Write(f,ts1); Seek(f, i); Write(f,ts2);
end;
end;
{In danh sach ket qua thi}
ClrScr;
Seek(f, 0); {Dua con tro ve dau tep}
soto:= 1; {So to tu 1}
while not Eof(f) do
begin
Writeln('KET QUA THI TUYEN SINH DAI HOC ...');
Writeln(' To so: ', soto);
Writeln;
Writeln('+----+ ------------------+--------+-------+------+-------+------+---------+');
Writeln('|STT| Ho va ten | So BD|Mon1|Mon2|Mon3|Tong|Ghi chu|');
Writeln('+----+ ------------------+--------+-------+------+-------+------+---------+');
stt := 1;
Chương 9
KIỂU CON TRỎ VÀ BIẾN ĐỘNG
24
• Biến tĩnh được cấp phát vùng nhớ trong DataSegment (64KB - IMB PC), tồn tại cùng với
khối chương trình mà nó được khai báo.
• Biến động được lưu trữ trong vùng nhớ Heap, khi cần có thể tạo ra để chứa dữ liệu, khi
không cần có thể xoá.
Biến động không có tên và do con trỏ quản lý.
• Biến con trỏ (Pointer variable): biến đặc biệt có kích thước 2 bytes, không dùng để chứa dữ
liệu mà chứa địa chỉ của biến động.
• Biến con trỏ có 2 loại: định kiểu và không định kiểu.
Biến con trỏ không định kiểu sẽ có kiểu như biến con trỏ định kiểu mà nó được gán.
• NIL: giá trị hằng đặc biệt của biến con trỏ để báo con trỏ không trỏ vào đâu.
Có thể gán Nil cho bất kì biến con trỏ nào.
TYPE
KieuCT = ^KieuDL;
trong đó KieuCT - từ tự đặt xác định kiểu con trỏ, KieuDL - kiểu dữ liệu của biến động do
biến con trỏ quản lý (Real, String, Array, Record, ...).
25
VD 10.1 (khai báo kiểu, biến con trỏ)
TYPE {Định nghĩa các kiểu con trỏ}
RealPtr = ^Real;
svPtr = ^HosoSV;
HosoSV= RECORD
hoten: String[25];
lop: String[5];
dtb: Real;
END;
VAR {Khai báo các biến con trỏ}
p: RealPtr; {biến con trỏ chứa đ/c biến động kiểu Real}
sv: svPtr; { ~ kiểu HosoSV}
p2: ^Char; { ~ kiểu Char}
p0: Pointer; {biến con trỏ không định kiểu}
Thâm nhập vào biến động trỏ bởi p ta viết p^
p^
p
Biến con trỏ p (2 bytes) chứa địa chỉ của biến động p^ (6 bytes) 2006.1011
26
Thủ tục New(p): Cấp phát bộ nhớ cho biến động trỏ bởi biến con trỏ p.
Nếu dùng N lần NEW(p) liên tục thì có N biến động cùng kiểu, nhưng con trỏ p chỉ trỏ
vào biến động tạo ra cuối cùng. Muốn truy nhập các biến động tạo ra trước đó, phải lưu
trữ địa chỉ của chúng.
Thủ tục Dispose(p): Giải phóng bộ nhớ đã cấp cho biến động trỏ bởi p.
Thủ tục Mark(p): Đánh dấu địa chỉ cần giải phóng sau này.
Thủ tục Release(p): Xoá mọi biến động được tạo ra từ khi đánh dấu bởi
Mark(p).
Thủ tục GetMem(p, n): Cấp phát n bytes cho biến động trỏ bởi p.
Thủ tục FreeMem(p, n): Xoá n bytes đã cấp bằng thủ tục Getmem(p, n).
27
Hàm Maxavail: Cho kích thước block cực đại các bytes liên tiếp chưa dùng
Heap.
VD 10.3 Lập trình tạo n < 100 biến động có kiểu số nguyên. Tính tổng các số nguyên tố trong
n số đó.
Khái niệm
28
• Danh sách liên kết: cấu trúc dữ liệu thích hợp cho việc thêm, bớt, ghép nối các phần tử.
• Tổ chức: vùng liên kết của phần tử thứ i chứa địa chỉ của phần tử thứ i+1 hoặc ngược lại.
Mỗi phần tử của DSLK gồm 2 phần chính: vùng chứa dữ liệu (data) và vùng chứa địa chỉ của
phần tử khác (link).
Firs Dat Lin
t a k
Dat Lin
a k
Dat Lin
TYPE {Khai báo kiểu DSLK đơn}
a k
DataType = ^Real;
PtrList = ^Item; NIL
Item = RECORD
Data: DataType;
Link: PtrList;
END;
• Các loại DSLK đơn: FIFO (First In First Out) - hàng đợi (Queue), LIFO (Last In First Out) -
ngăn xếp (Stack).
VAR
First, Last, p, q: PtrList;
29
• Tạo DSLK đơn (FIFO):
30
• Thêm một phần tử vào DS
Thêm p vào đầu DS
b1. Cho vùng liên kết của p trỏ vào First;
p^.Link:= First;
b2. Cho First trỏ vào p.
First:= p;
Thêm vào giữa/cuối DS (p là phần tử cần thêm, q phần tử đứng ngay trước p)
b1. Cho vùng liên kết của p trỏ vào vùng liên kết của q;
p^.Link:= q^.Link;
b2. Cho vùng liên kết của q trỏ vào p;
q^.Link:= p;
Ứng dụng
31
VD 10.4 Lập trình sinh ngẫu nhiên DSLK đơn có n phần tử (n <= 1000), mỗi phần tử chứa
một số nguyên có trị tuyệt đối < 2008.
In DS ra màn hình;
Tìm phần tử có giá trị bằng số nguyên x nhập từ bàn phím;
Thêm phần tử y vào vị trí k, với y và k nhập từ bàn phím;
Xoá khỏi DS các số chính phương;
Sắp xếp DS theo thứ tự tăng bằng cách thay đổi mối liên kết thay vì thay đổi giá trị.
TYPE
PtrList = ^Item;
Item = RECORD
Data: Integer;
Link: PtrList;
END;
VAR
First: PtrList;
VD 10.5 Lập trình giải bài toán tuyển sinh trong Mục 9.5.
32