Tải bản đầy đủ (.doc) (22 trang)

Cơ bản về Free Pascal Việt Hóa

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (166.18 KB, 22 trang )

TÀI LIỆU FREE PASCAL
Bài 01: Giới thiệu FP
Song song với việc nâng cao tốc độ và những tiện ích về môi trường cho máy tính, người
ta cũng quan tâm đến việc phát triển các ngôn ngữ lập trình ở nhiều mức khác nhaụ
Hướng ưu tiên hiện nay dành cho những ngôn ngữ lập trình hướng đối tượng với nhiều
tiện nghi 'chìa khoá trao taý cho người sử dụng. Tuy nhiên hầu hết các nhà lập trình đều ít
nhất một lần trải qua Turbo Pascal (TP) hoặc C/C++. Do đó gần đây có hai nhóm quan
tâm đến việc phát triển hai ngôn ngữ nói trên: nhóm FreePascal (FP) cho TP và nhóm
GCC cho C. Một điều lý thú là các trình nguồn của các ngôn ngữ này tương ứng được
viết bằng TP và C. Bắt đầu từ kỳ thi Olympic Tin học quốc tế lần thứ 13 (năm 2001), chỉ
có FP và GCC là hai ngôn ngữ lập trình chính thức.
Sau đây là một số nét chính của FP được trình bày đối chiếu với TP, những thông tin chi
tiết hơn về FP có thể tìm trong trang web .
- FP có thể chạy trên mọi hệ điều hành phổ biến như MS-DOS, Windows, OS/2, Linux,
Amiga, Atari và về cơ bản vẫn tương thích với TP theo nghĩa mọi chương trình chuẩn
mực của TP đều có thể chạy trong môi trường FP. Có các gói chương trình khác nhau cho
các hệ điều hành nhưng nói chung đều bao gồm các phần chính: FP (Editor), PPC386
(Source Compiler), MAKE (Project Compiler), GDB (Debuger).
- Khi biên dịch, FP liệt kê mọi lỗi của chương trình trong khi TP chỉ thông báo lỗi đầu
tiên.
- Cho phép chương trình được dùng bộ nhớ thoải mái chỉ phụ thuộc dung lượng bộ nhớ
của máy và bộ nhớ ảo của hệ điều hành. Trong khi đó, đối với TP, vùng DATA không
được quá một segment của DOS (64KB). Do đó chương trình viết bằng FP có thể khai
báo các dữ liệu với kích thước nhiều MB.
- FP cho phép thực hiện việc hợp hàm do đó giá trị của hàm không chỉ là số, xâu,
Boolean hoặc Pointer như đối với TP mà có thể là mảng hoặc Object.
- Trong định nghĩa hàm, hàm chỉ xuất hiện với tên trong biểu thức tính toán sẽ không
xem là đệ quy, hàm xuất hiện với tên trong biểu thức kèm theo các dấu mở, đóng ngoặc
mới xem là đệ quỵ
- Có một số kiểu dữ liệu mới như CARDINAL (số nguyên không dấu 32 bit), STRING
có thể có giá trị là xâu với độ dài lớn hơn 255.


- Một vài chi tiết nhỏ: FP không cho phép viết thêm gì trong chương trình sau END.
trong khi TP cho phép; FP buộc người dùng phải ghi chương trình vào đĩa trước khi tiến
hành biên dịch.
Do việc soạn chương trình bằng FP chậm hơn so với bằng TP, khi soạn một chương
trình, ta vẫn có thể soạn trong TP sau đó chuyển sang chạy trên FP.
Tuy nhiên FP còn có lçi. Tập thể các tác giả kêu gọi người sử dụng khi gặp lỗi hãy cố
gắng thông báo cho họ biết để hoàn thiện FP.
1. Bộ nhớ rộng rãi
Trong chúng ta, chắc có rất nhiều người biết về bài toán tìm dãy con chung dài nhất. Bài
toán phát biểu ngắn gọn như sau:
Cho 2 dãy A và B. Dãy A có các phần tử là a1, a2,…an, dãy B có các phần tử là là b1,
b2,…bn. Hãy tìm dãy C là dãy con của cả A và B và có nhiều phần tử nhất.
Chẳng hạn, nếu dãy A là 5 3 2 1 4 và B là 3 2 5 4 1 thì C là dãy 3 2 4.
1
Đây là một bài toán quy hoạch động kinh điển và có công thức quy hoạch động được
thiết lập như sau:
Gọi L(i,j) là độ dài dãy con chung lớn nhất của dãy Ăi) gồm các phần tử a1, a2,…ai và
dãy B(j) có các phần tử là là b1, b2,…bj.
Thế thì:
L(0,j)=L(i,0)=0.
Nếu aij thì L(i,j)=L(i-1,j-1)+1.
Nếu ai ≠bj thì L(i,j)= max(L(i-1,j), L(i,j-1)).
Trường hợp 2 và 3 áp dụng với tất cả các chỉ số i từ 1 đến n và j từ 1 đến m. Nếu bạn
chưa tin vào tính đúng đắn của công thức thì tôi xin giải thích như sau:
Trường hợp 1 hiển nhiên.
Với công thức ở trường hợp 2 và 3 ta thấy: nếu ai =bj thì ta phải chọn ngay cặp phần tử
chung đó, các phần tử còn lại của 2 dãy là a1, a2,…a i−1 và b1, b2,…b j −1 có dãy con
chung lớn nhất gồm độ dài L(i-1,j-1), do đó L(i,j)=L(i-1,j-1) + 1. (Tư tưởng quy hoạch
động thể hiện ở chỗ L(i,j) đạt max thì L(i-1,j-1) cũng phải đạt max).
Còn nếu ai ≠bj thì ta có 2 lựa chọn: hoặc không xét phần tử ai và so dãy là a1, a2,…ai-1

với dãy b1, b2,…bj để được dãy con chung dài nhất L(i-1,j) phần tử; hoặc không xét
phần tử bj và so dãy là a1, a2,…ai với dãy b1, b2,…bj-1 để được dãy con chung dài nhất
L(i,j-1) phần tử. (Chú ý định nghĩa của L(i-1,j) và L(i,j-1)). Vì có 2 lựa chọn nên ta chọn
hướng tốt hơn, do đó L(i,j)=max(L(i-1,j) , L(i,j-1)).
Các bạn có thể băn khoăn là ở trường hợp 2 cũng có thể lựa chọn cả 2 tình huống trên
chứ? Thực chất không cần như vậy, vì dễ thấy L(i,j)≤ min(i,j) do đó L(i-1,j-1) + 1 chắc
chắn không nhỏ hơn cả L(i-1,j) và L(i,j-1).
Sau khi tính được xong toàn bộ L(i,j) thì ta sẽ được: dãy C có L(n,m) phần tử, để xác
định đó là các phần tử nào thì ta lần vết trên L theo 3 trường hợp trên để tìm các cặp aij
được chọn. Các bạn xem trong chương trình cài đặt cụ thể dưới đây trên TP:
CODE
{$A+,B-,D+,E+,F-,G+,I+,L+,N+,O-,P-,Q+,R+,S+,T-,V+,X+}
program daycon;
const
inp = ’daycon.in0’;
out = ’daycon.out’;
max = 100;
type
mang1 = array[0 max] of integer;
mang2 = array[0 max] of mang1;
var
n,m,z : integer;
a,b,d : mang1;
L : mang2;
(*****************************************)
procedure nhap;
var
i : integer;
f : text;
begin

assign(f, inp);
reset(f);
readln(f, n, m);
2
for i := 1 to n do read(f,a[i]);
readln(f);
for i := 1 to m do read(f,b[i]);
close(f);
end;
(*****************************************)
procedure trace;
var
i,j : integer;
begin
i := n; j := m; z := L[n,m];
repeat
if L[i,j] = L[i-1,j-1] + 1 then begin
d[i] := 1;
i := i - 1; j := j - 1;
end
else
if L[i,j] = L[i-1,j] then
i := i - 1
else j := j - 1;
until (i=0) or (j=0)
end;
(*****************************************)
procedure qhd;
var
i,j : integer;

function max(a,b : integer): integer;
begin
if a > b then max := a else max := b;
end;
begin
for i := 1 to n do begin
for j := 1 to m do
if a[i] = b[j] then
L[i,j] := L[i-1,j-1] + 1
else
L[i,j] := max(L[i-1,j],L[i,j-1]);
end;
end;
(*****************************************)
procedure xuly;
begin
qhd;
trace;
end;
(*****************************************)
procedure inkq;
var
f : text;
i : integer;
begin
3
assign(f, out);
rewrite(f);
writeln(f, z);
for i := 1 to n do

if d[i] = 1 then write(f,’ ’,a[i]);
close(f);
end;
(*****************************************)
begin
nhap;
xuly;
inkq;
end.
Thuật toán có thời gian thực thi cỡ O(n2). Với n,m =100 thì chương trình chạy trong
chớp mắt. Vậy thì tại sao không thử giải với n=1000 (ai mà không muốn chương trình
của mình mạnh hơn). Vậy ta sửa hằng số max trong chương trình thành 1000. Và, TP báo
lỗi "structure too large"!!! Tại sao lại thế???
Câu trả lời là: TP là môi trường lập trình 16 bit trên HĐH DOS do đó nó có nhiều hạn
chế. Han chế thứ nhât là kích thước của biến và kiểu &l; 64KB, trong đó có biến mảng và
kiểu mảng. Đó là do dùng số 16 bit thì chỉ có thể chỉ số hoá được 216 = 64K giá trị thôi.
Khi ta khai báo max = 1000 thì mảng L của ta có kích thước 1000x1000x2 (2 là kích
thước kiểu integer)=2.106>>64K nên TP báo lỗi "structure too large" (kiểu cấu trúc quá
lớn) là đúng rồi.
Vậy bây giờ thay vì khai báo mảng L là mảng 2 chiều, ta sẽ khai báo L thành rất nhiều
mảng nhỏ hơn. Bạn cứ thử thế mà xem. Nếu TP không báo lỗi "structure too large" thì
cũng báo lỗi là "too many varibles". Đó là do hạn chế thứ 2 của TP: tổng kích thước các
biến toàn cục (global) cũng ≤ 64KB . Bạn có chia L thành bao nhiêu mảng con thì TP vẫn
bắt tổng kích thước của chúng ≤ 64KB.
Vẫn còn giải pháp nữa: thay vì dùng mảng tĩnh thì dùng mảng động. Khai báo L là mảng
1000 con trỏ, mỗi con trỏ trỏ đến một mảng 1000 phần tử. (L:Array[1 max] of ^mang1).
May quá, TP không báo lỗi khi dịch. Nhưng khi chạy thì ôi thôi, lỗi "Heap overflow"
(tràn heap). Nguyên nhân là hạn chế của DOS: toàn bộ bộ nhớ DOS có thể sử dụng ≤ 640
KB. Mà các chương trình hệ thống và IDE của TP cũng chiếm mất hơn 300KB rồi. Tức
là chương trình của bạn dù có tận dụng hết bộ nhó còn lại cũng chỉ được 300KB nữa thôi.

(Khi bạn nhấn F9 để dịch, TP báo xxxKB free memory, đó chính là phần heap tối đa hệ
thống có thể cấp phát cho các biến động đó).
Vẫn còn nhiều giải pháp có thể giải quyết: dùng 2 mảng một chiều tính lẫn nhau và đánh
dấu lần vết bằng bit; ghi ra file; dùng mảng răng lược… Nhưng dù sao thì cũng chỉ là giải
pháp tình thế, hơn nữa lại rất phức tạp. Giải pháp tốt nhất là dùng một môi trường lập
trình mạnh hơn. Và IOI đã chọn FP.
Tôi đem chương trình trên với khai báo max =1000 chạy trên FP và mọi chuyện đều ổn,
chẳng có lỗi nào xảy ra hết. Đối với FP, bộ nhớ không bị hạn chế bởi con số 64KB nữa
(free mà).
Điều đó có được là nhờ những đặc tính tuyệt vời của FP:
a. FP là môi trường lập trình 32 bit. Dùng một số 32 bit thì có thể chỉ số hoá được 232
= 4G giá trị, vậy nên biến trong FP có thể có kích thước 4GB. Các bạn chú ý:
4GB=4x1024MB. Trong khi đó máy tính chúng ta thường dùng thường có chừng 128MB
RAM. Mảng L kích thước ≤ 2MB thì nhằm nhò gì.
b. FP là môi trường lập trình chạy trên nền các HĐH 32 bit (Windows, Linux, BeOS,
4
OS/2… và cả DOS nữa. Nhưng đó là phiên bản DOS 32 bit mở rộng). Đây cũng là điều
quan trọng. Vì nếu cho FP chạy trên DOS 16 bit (nếu có chạy được), thì với bộ nhớ chật
hẹp 640KB, FP cũng phải bó tay không phát huy được tài năng. Ngược lại do TP là 16
bit, nên có cho chạy trên Windows 32 bit, thì cũng chỉ phát huy được tài năng đến mức
của 16 bit mà thôi. Chạy trên môi trường 32 bit, ngoài RAM (đã rất nhiều), HĐH còn có
có chế bộ nhớ ảo (virtual memory) sử dụng một phần HĐ làm bộ nhớ tạm nên FP có thể
cung cấp cho bạn dung lượng nhớ có thể nói là thoải mái (free mà).
c. FP là tương thích hoàn toàn với TP. Đây cũng là một điều thú vị. Chương trình ở
phàn trên tôi viết trong TP, đem sang FP vẫn chạy ngon lành, chẳng phải sửa đổi gì hết
(thực ra thì có sửa giá trị max từ 100 thành 1000). IDE của FP thì giống hệt TP (tất nhiên
có nhiều chức năng tiên tiến hơn, nhưng những gì bạn làm được với TP đều làm được
trên FP).
Tôi nghĩ vậy là quá đủ để chúng ta thay thế TP bằng FP. Nếu bạn còn băn khoăn, hãy đợi
các bài viết tiếp theo để tìm hiểu tiếp về những điều kì diệu mà FP có còn TP thì không.

Còn nếu bạn háo hức muốn dùng thử, hãy làm theo chỉ dẫn cài đặt dưới đây.
2. Cài đặt và sử dụng FP
a. Tải bộ cài đặt
FP có rất nhiều phiên bản, cả các phiên bản đã sử dụng chính thức và phiên bản còn đang
phát triển. Theo tôi thì các bạn nên sử dụng các phiên bản chính thức vì chúng ổn định
hơn.
Để cài đặt bạn vào website của FP (), vào mục download và tải
file zip chứa bộ cài. Chú ý là có nhiều phiên bản của FP cho các hệ điều hành khác nhau
nên bạn phải chú ý:
b. Unzip và Install
Sau khi đã tải được bộ cài (tất cả ở trong một file zip), bạn unzip file đó ra một folder rồi
chạy file Install.exe. Giao diện cài đặt hiện ra, yêu cầu bạn lựa chọn thư mục cài đặt cho
FP (mặc định là C:PP). Và tiếp theo là một bảng lựa chọn các cấu hình cài đặt. Theo tôi
thì bạn nên chọn các cấu hình mặc định, và đơn giản là nhấn Enter để bộ cài tự làm việc
của mình.
c. Chạy và cấu hình IDE
Sau khi cài xong, toàn bộ IDE, chương trình dịch, tài liệu, ví dụ,… của FP được copy vào
thư mục bạn đã chọn khi cài đặt (mặc định là C:PP). Có 2 bản cho cả Windows và DOS
(32bit). Nếu chỉ dùng FP thay thế TP trong học tập thì theo tôi bạn nên sử dụng bản cho
DOS. Vì qua sử dụng tôi thấy IDE của FP trên DOS hoạt động ổn định hơn IDE của FP
trên Windows.
Để sử dụng IDE của FP trên DOS, bạn vào thư mục con bingo32v2 và chạy file fp.exe.
(Có thể sẽ cần nhấn Alt-Enter để chương trình chạy toàn màn hình full screen. Bạn sẽ
thấy ngạc nhiên, hoặc cũng chẳng ngạc nhiên lắm, vì giao diện IDE của FP giống hệt TP.
(Tôi thì thấy ấn tượng hơn, nhất là hình ảnh nền).
Đến đây thì mọi chuyện như trên TP thôi. Nhưng để thuận tiện hơn trong sử dụng, bạn
nên thiết lập một số thông số cấu hình như sau:
- Vào menu CompileTarget: chọn DOS (để nhấn Ctrl-F9 là chương trình của bạn có thể
chạy ngay lập tức như trong TP. Vì compiler ta dùng cũng đang chạy trên DOS mà.
Nhưng đây là DOS 32 bit đấy, không hạn chế như DOS 16 bit đâu).

- Vào menu OptionsMode: chọn Normal (để FP sẽ hỗ trợ chúng ta debug dễ chịu nhất).
- Vào menu OptionsCompiler:
ở tab Syntax các bạn chỉ chọn các mục:
+ TP/BP compatibily: để tương thích với TP (sau này khi quen với FP rồi thì không cần
nữa, còn bây giờ thì chọn chức năng này cho dễ sử dụng).
+ Stop after first error: bình thường FP dịch sẽ thông báo một loạt lỗi (giống C,
Delphi…), nhưng ta quen với việc thông báo lỗi đầu tiên gặp của TP nên chọn mục này
5
cho thân thiện. Sau này có thể không cần nữa.
+ C-like operators: đây là một điều thú vị của FP (các bạn hãy đón đọc trong kì sau nhé).
ở tab Code generaion các bạn chọn
+ Toàn bộ các mục phần Run-time checks: cho an toàn các bạn ạ, tránh trường hợp ta lập
trình sai như: truy cập ngoài mảng, tính toán tràn số mà máy vẫn không thông báo gì.
+ Target processor: chọn PPro/PII. Hầu hết máy của chúng ta là máy Pen III, Pen IV, thế
thì nên để FP tận dụng hết tiềm năng của chúng để chương trình của chúng ta chạy hiệu
quả hơn.
- Vào menu OptionsEnviroimentEditor: đặt các thông số soạn thảo mà bạn thích. Tôi thì
thường chỉ đặt các mục sau:
Các mục mà TP mặc định (và FP cũng thế):
+ Insert mode: chế độ gõ chèn.
+ Auto indent mode: đặt lề tự động.
+ Backspace unindent.
+ Tab size: 4. Indent size: 4.
Những thông số này giúp chương trình dễ đọc hơn (có cấu trúc, thẳng lề, các đầu dòng
thò thụt đều đặn theo khoảng cách 4 kí tự).
Syntax highlight: hiện sáng từ khoá (trong TP cũng có).
Persirtent block: khối sau khi đánh dấu sẽ hiển thị cho đến khi dùng lệnh ẩn khối.
Auto closing brackets: tự động thêm kí tự đóng ngoặc. Đây là điều đặc sắc không có
trong TP. Bình thuờng trong TP bạn gõ các kí tự mở ngoặc như (, [, { thì phải tự thêm kí
tự đóng ngoặc cho đúng. Nếu không chú ý thì rất dễ lẫn. Còn trong FP nếu đặt chức năng

này thì khi ta gõ kí tự mở ngoặc, FP cũng thêm luôn kí tự đóng ngoặc, do đó chúng ta
không sợ các lầm lẫn thừa thiếu đóng mở ngoặc nữa.
Bài 02: Các kiểu dữ liệu – Cách viết hàm – Thủ tục
Trong số trước chúng ta đã biết một đặc tính rất tuyệt vời của FP là hỗ trợ bộ nhớ rộng
rãi. Không chỉ có vậy, trong bài này chúng ta sẽ tìm hiểu tiếp về những điều thú vị khác
của FP.
1. Kiểu số nguyên lớn
Có rất nhiều bài toán cần chúng ta phải tính toán với những số nguyên lớn. Chẳng hạn
như tính giai thừa, tính số Fibonacci hay tìm các số nguyên tố lớn (chẳng hạn tìm các số
nguyên tố lớn để dùng trong thuật toán mã hoá RSA). Với kiểu Integer của TP ta tìm
được số nguyên tố lớn nhất có 5 chữ số. Với kiểu LongInt thì được 9 chữ số. Muốn tìm
được các số to hơn thì phải dùng kiểu số thực (như comp hay extended). Nhưng có điều
bất tiện là các kiểu số thực thì không dùng các phép toán div, mod được nên cài đặt rất
khó khăn.
Ngoài bài toán về tìm số nguyên tố lớn, với những bài toán khác như tính giai thừa, tính
số Fibonacci,… kiểu integer của TP rất hạn chế.
Một hạn chế thứ hai với kiểu integer của TP là hay gặp các lỗi tính toán số học. (Không
biết bạn có đặt {$Q+} để phát hiện các lỗi như vậy chưa). Lỗi tính toán số học xảy ra khi
chúng ta tính biểu thức có các hạng tử trong miền integer nhưng kết quả thì nằm ngoài
miền (chẳng hạn 30000 + 30000). Những lỗi như vậy thường ít khi ta để ý, nhưng rất
phiền toái. Sửa chúng thì cũng không khó lắm, chỉ cần chuyển đổi kiểu (thành LongInt
hay Real) là OK.
Với FP thì những hạn chế đó không thành vấn đề. Với lợi thế 32 bit (gấp đôi TP), FP
cung cấp kiểu Int64, mới nghe chắc bạn cũng đoán được đó là kiểu số nguyên 64 bit. Với
Int64 các bạn có thể tìm được các số nguyên tố 18 chữ số (cỡ tỉ tỉ) hay tính được giai thừa
của 20. (Nếu vẫn muốn hơn thì ta phải xây dựng riêng một kiểu BigInt, ta sẽ làm điều đó
6
trong phần sau).
Trong trường hợp muốn tiết kiệm bộ nhớ, ta vẫn có thể sử dụng kiểu Byte (kích thước 1
byte), SmallInt (kích thức 2 byte).

Bảng sau trình bày về các kiểu nguyên của FP:
Chú ý: với kiểu Integer, mặc định FP dùng kích thước 2 byte. Vì vậy khi muốn dùng kiểu
nguyên lớn, ta nên khai báo rõ ràng.
2. Kiểu string lớn
Khi lập trình, chúng ta rất nhiều lần gặp vấn đề với các xâu tối đa 255 kí tự của TP
(chẳng hạn bài toán xâu đối xứng, bài toán đếm từ…). Ta có thể giải quyết vấn đề bằng
mảng kí tự (array of char) nhưng khi đó ta lại không thể dùng các phép toán trên xâu rất
mạnh của Pascal.
Không chỉ có cải tiến về kiểu nguyên, kiểu string trong FP cũng rất tuyệt vời. String trong
FP không còn hạn chế 255 kí tự của TP nữa mà có kích thước tối đa là 2 tỉ kí tự. Hơn
nữa FP còn hỗ trợ kiểu xâu Unicode (WideString). Nếu bạn vẫn thích kiểu String cũ của
TP, bạn có thể dùng kiểu ShortString.
Bây giờ bạn có thể viết chương trình giải bài xâu đối xứng, xâu con chung với kiểu string
của trên FP và hạn chế n cỡ 1000 một cách rất dễ dàng. Chúng ta sẽ tìm hiểu kĩ hơn về
xâu trong FP ở một bài báo khác.
3. Viết hàm thuận lợi hơn
FP có rất nhiều cải tiến trong cách viết các hàm. Để so sánh, chúng ta sẽ xem xét một số
ví dụ. Trong TP, chúng ta viết hàm tính giai thừa như sau:
CODE
function gt(n:integer):integer;
var
i,tg:integer;
begin
tg:=1;
for i:=1 to n do tg:=tg*i;
gt:=tg;
end;
Tại sao ta lại phải thêm một biến tg để lưu trữ kết quả trung gian? Đó là do trong TP với
tên hàm ta chỉ được sử dụng duy nhất lệnh gán trị. Nếu đưa tên hàm vào biểu thức thì sẽ
thực hiện lời gọi hàm.

Điều này đã được FP làm cho free bằng cách cho phép sử dụng tên hàm như một biến
7
(giống như Object Pascal dùng biến Result). Khi đó tên hàm có thể xuất hiện ở trong
cách biểu thức tính toán ngay trong thân hàm mà không tạo ra lời gọi đệ quy. Hàm giai
thừa trong FP có thể viết rất tiết kiệm biến như sau:
CODE
function Gt(n: integer): int64;
begin
gt := 1;
for n := n downto 2 do gt := gt * n;
end;
Vậy khi ta muốn gọi đệ quy thì sao? Thì chỉ việc thêm cặp dấu () và truyền tham số cần
thiết. FP sẽ biết ta muốn gọi đệ quy khi ta có thêm cặp (). Hàm giai thừa viết kiểu đệ quy
như sau:
CODE
function Gt(n: integer): int64;
begin
if n=0 then exit(1)
else exit(n*gt(n-1));
end;
Trong cách viết này ta còn thấy một điều tiện lợi của FP: dùng lệnh exit để trả lại kết quả
cho hàm (giống như C và Object Pascal sử dụng lệnh return). Bạn sẽ thấy sự tiện lợi của
cách viết này khi viết các hàm dạng " phát hiện được phần tử đầu tiên rồi thoát".
Chẳng hạn hàm tìm vị trí của phần tử x trong mảng a có n phần tử. Viết trong TP ta phải
viết như sau:
CODE
function Find(x: integer): integer;
Var
i : integer;
begin

for i := 1 to n do
if a[i] = x then begin
Find := i;
exit;
end;
Find := 0;
end;
Hàm này viết trong FP thì ngắn ngọn hơn nhiều:
CODE
function Find(x: integer): integer;
Var
i : integer;
begin
for i := 1 to n do
if a[i]=x then exit(i);
8
exit(0);
end;
4. Kết quả trả lại của hàm có thể là kiểu cấu trúc
Rất nhiều ngôn ngữ lập trình thông dụng như C, VB… chỉ cho phép kết quả trả lại của
hàm là các kiểu cơ sở như: số nguyên, số thực, kí tự, con trỏ… Riêng TP thì có thêm kiểu
xâu kí tự. Nếu muốn trả lại kết quả là kiểu cấu trúc như mảng hay bản ghi thì bạn chỉ có
cách dùng tham biến thôi. Một số NNLT hướng đối tượng như C++, Java, Object Pascal
có cho phép kết quả trả lại là một đối tượng, nhưng như vậy vẫn không free như FP: FP
cho phép kết quả của hàm có thể là kiểu cấu trúc.
Để hiểu hơn chúng ta cùng làm bài toán sau (Đề thi OLP2004):
Gọi X là tập tất cả các xâu nhị phân không có 2 bit 1 liền nhau. Các xâu được đánh thứ tự
theo trình tự được sinh ra (từ nhỏ đến lớn, bit 0 đứng trước bit 1). Chẳng hạn với n=5 ta
có các xâu sau:
Bài toán đặt ra: hãy xác định xâu nhị phân n bit ứng với số thứ tự m cho trước. Hạn chể:

n <= 200.
Bài toán này có thuật giải như sau:
Gọi L[k] là số các xâu nhị phân như vậy có k bit. Nếu bit thứ k của nó là bit 0 thì k-1 bit
còn lại là tự do (tức là ta có L[k-1] dãy). Nếu thứ k của nó là bit 1 thì bit k -1 phải là 0, và
k-2 bit còn lại free. Vậy ta có: L[k] = L[k-1] + L[k-2]. Chú ý: L[1]=2 và L[2]=3.
Có công thức đó, ta tính số các xâu có n bit. Để xác định xâu nhị phân n bit có thứ tự m
cho trước ta có nhận xét: nếu m > L[n-1] thì nhất định bit thứ n phải là 1 (vì thứ tự của
xâu có bit 0 đứng trước xâu có bit 1, và có đúng L[n-1] xâu có bit thứ n là bit 0). Xâu n-1
bit còn lại có sẽ thứ tự là m-L[n-1]. Ngược lại thì bit thứ n là bit 0 và xâu n-1 bit còn lại
có thứ tự là m.
Do đó ta có thể làm như sau:
CODE
for i:=n downto 1 do
if m <= L[i-1] then
x[i] := 0
else begin
x[i] := 1;
m := m - L[i-1];
end;
Tuy nhiên n có thể bằng 200 nên m và các giá trị L[i] có thể xấp xỉ 2200, tức là cỡ 1070
(vì 210 xấp xỉ 103 ). Ta không thể dùng các kiểu số có sẵn mà phải tự xây dựng một kiểu
9
số lớn hơn.
Có nhiều người thích dùng xâu để biểu diễn số lớn, nhưng tôi thấy dùng mảng thì thích
hợp hơn. Ta dùng mảng biểu diễn số nguyên lớn, mỗi phần tử của mảng là một chữ số.
Các chữ số lưu trữ trong mảng theo chiều từ trái sang phải: chữ số hàng đơn vị là phần tử
1, chữ số hàng chục là phần tử 2…
Ta khai báo kiểu số lớn đó như sau:
const max = 100;
type BigInt = array[1 max] of byte;

Để cộng, trừ 2 số nguyên lớn biểu diễn bằng mảng, ta dùng thuật toán cộng kiểu thủ công
(cộng các chữ số từ bậc thấp đến bậc cao, có nhớ). Các thủ tục cộng, trừ viết trong TP
như sau:
CODE
procedure cong(var a,b,c : BigInt);
var
i,t : integer;
begin
t := 0;
for i:=1 to max do begin
t := t + a[i] + b[i];
c[i] := t mod 10;
t := t div 10;
end;
end;
procedure tru(var a,b,c : BigInt);
var
i,t : integer;
begin
t := 0;
for i:=1 to max do begin
t := a[i] - b[i] - t;
if t < 0 then begin
c[i] := 10 + t;
t := 1;
end else begin;
c[i] := t;
t := 0;
end
end;

end;
Ta khai báo L là mảng 200 phần tử kiểu BigInt. Gán L[1] là 2, L[2] là 3 rồi tính các phần
tử khác bằng câu lệnh như sau:
for i:=3 to n do cong(L[i-1],L[i-2],L[i]);
Viết như vậy thì chương trình hoạt động tốt, nhưng không trực quan lắm. Nếu có thể viết
L[i]:=cong(L[i-1],L[i-2]) thì sẽ trong sáng hơn nhiều. Trong TP thì không thể, nhưng
trong FP hoàn toàn có thể viết được như vậy. Sau đây là toàn bộ chương trình nguồn giải
bài toán này viết bằng FP:
CODE
10
program Xau2bit1;
const
inp = ’fibo.inp’;
out = ’fibo.out’;
max = 100;
type
BigInt = array[1 max] of byte;
var
n : integer;
m : BigInt;
s : string;
kq: array[1 200] of byte;
L : array[1 200] of BigInt;
f : text;
{==================================}
procedure nhap;
var
c : char;
i : integer;
begin

assign(f,inp);
reset(f);
readln(f,n);
readln(f,s);
close(f);
end;
{==================================}
function chuyen(s : string): BigInt;
var
i : integer;
begin
for i:=1 to length(s) do
chuyen[i]:=ord(s[i]) - ord('0');
for i:=i+1 to max do
chuyen[i]:=0;
end;
function cong(var a,b : BigInt): BigInt;
var
i,c : integer;
begin
c := 0;
for i:=1 to max do begin
c := c + a[i] + b[i];
cong[i] := c mod 10;
c := c div 10;
end;
end;
function tru(var a,b : BigInt): BigInt;
var
i,c : integer;

begin
11
c := 0;
for i:=1 to max do begin
c := a[i] - b[i] - c;
if c < 0 then begin
tru[i] := 10 + c;
c := 1;
end else begin;
tru[i] := c;
c := 0;
end
end;
end;
function nho(var a,b : BigInt): boolean;
var
i : integer;
begin
for i := max downto 1 do
if a[i] < b[i] then
exit(true)
else
if a[i] > b[i] then exit(false);
exit(true)
end;
{==================================}
procedure tinh;
var
i : integer;
begin

m := chuyen(s);
L[1]:=chuyen(’2’);
L[2]:=chuyen(’3’);
for i:=3 to n do
L[i] := cong(L[i-1],L[i-2]);
end;
procedure tim;
var
i : integer;
begin
for i:=n downto 2 do
if nho(m, L[i-1]) then
kq[i] := 0
else begin
kq[i] := 1;
m := tru(m,L[i-1]);
end;
if m[1] > 1 then kq[1] := 1
else kq[1] := 0;
end;
{==================================}
procedure inkq;
var
12
i : integer;
begin
assign(f,out);
rewrite(f);
for i:=n downto 1 do write(f,kq[i]);
close(f);

end;
{==================================}
BEGIN
nhap;
tinh;
tim;
inkq;
END.
Trong chương trình này, ngoài 2 hàm cộng, trừ, tôi còn viết thêm 1 hàm để chuyển một
xâu biểu diễn số nguyên thành một số nguyên kiểu BigInt và một hàm để so sánh 2 số
kiểu BigInt.
Đọc chương trình nguồn, các bạn cảm thấy thế nào? Tôi thì thấy rất thoải mái, vì bây giờ
với FP có thể viết rất nhiều hàm mà trước đây trên TP phải viết bằng thủ tục một cách
không rõ ràng lắm. Hàm trong FP có thể trả lại kiểu cấu trúc là một điều tôi thấy cực kì
thú vị, vì chưa từng thấy một ngôn ngữ lập trình thông dụng nào làm được điều đó.
Bài 03: Mảng và các ưu thế so với TP
Trong các số báo trước, tôi có đề cập đến một số điều thú vị về mảng của FP mà TP
không có như: mảng kích thước không hạn chế. Trong bài này tôi xin giới thiệu một số
điều thú vị khác về mảng, con trỏ và đồ hoạ trong FP.
1. Mảng mở (open array)
Để một biến kiểu mảng có thể làm tham số cho một chương trình con, ta bắt buộc phải
khai báo trước về kiểu mảng đó. Chẳng hạn khai báo sau không hợp lệ cả trong TP và FP:
function are (x,y: array[1 100] of real): real;
Ta phải sửa lại thành khai báo như sau:
type
TArr1 = array[1 100] of real;
function area(x,y: TArr1): real;
Vấn đề tạm thời được giải quyết. Tuy nhiên lại gặp một vấn đề mới là đối số truyền cho
hàm area bắt buộc sẽ phải có kiểu TArr1. Vấn đề thứ hai là khai báo mảng phải xác định
trước số phần tử, sẽ gây bất tiện khi số phần tử thực sự nhiều hơn hoặc ít hơn.

FP có một cải tiến là cho phép khai báo tham số của chương trình là kiểu mảng mở.
Chẳng hạn hàm area trên có thể khai báo trong FP như sau:
function area(x,y: array of real): real;
Vậy khi chạy làm thế nào để xác định được số phần tử thực sự của tham số? Cách đơn
giản nhất là chúng ta thêm một tham số nữa để mô tả số phần tử. Nếu không thích như
vậy, chúng ta có thể dùng hàm Low và High để xác định chỉ số đầu và cuối của mảng.
Thông thường thì với mảng mở, chỉ số đầu là 0, chỉ số cuối là n-1 với n là số phần tử của
mảng (giống như trong ngôn ngữ C).
Sau đây là một ví dụ về hàm tính diện tích đa giác đơn bằng phương pháp hình thang viết
13
trong FP:
CODE
function areăx,y: array of real): real;
var
i,n : integer;
begin
n := high(x);
result := (x[0] - x[n]) * (y[0] + y[n]);
for i := 0 to n-1 do
result += (x[i+1] - x[i])*(y[i+1] + y[i]);
result := abs(result) / 2;
end;
Cách viết hàm có sử dụng một số cải tiến của FP: toán tử C-like, biến result là giá trị trả
lại của hàm.
Trong TP cũng có kiểu mảng mở như vậy (không tin bạn có thể thử khai báo). Tuy nhiên
mảng mở trong FP có một điều thú vị mà trong TP không có, đó là mảng tạo trong khi
chạy.
Để dễ hiểu, bạn hãy quan sát lời gọi hàm area của tôi đối với một tứ giác có 4 đỉnh là
Ăx1,y1), B(x2,y2), C(x3,y3), D(x4,y4).
s := areă[x1,x2,x3,x4], [y1,y2,y3,y4]);

Với lời gọi đó, khi chạy, chương trình sẽ tạo một mảng x gồm 4 phần tử x1,x2,x3,x4 và
mảng y với 4 phần tử y1,y2,y3,y4. Nếu không có cách viết này, ta sẽ phải khai báo 2
mảng x,y và gán các phần tử vào một cách thủ công. Cách viết [a1,a2, ,an] được FP hiểu
là một mảng mở ngoài cách hiểu thông thường là một tập hợp.
2. Con trỏ
Ai đã từng sử dụng ngôn ngữ C, nếu không cảm thấy khó khăn thì sẽ rất thích thú với sự
uyển chuyển của con trỏ trong C: chẳng hạn có thể thực hiện các phép toán số học cộng,
trừ với con trỏ, có thể dùng con trỏ như mảng. Con trỏ trong TP thì không được uyển
chuyển như vậy. Trong TP ta chỉ có thể thực hiện một số phép toán như: gán trị cho con
trỏ, so sánh 2 con trỏ hay truy cập vào phần tử mà con trỏ trỏ đến.
FP đã cải tiến và con trỏ trong FP bây giờ uyển chuyển như trong C. Chúng ta có thể hiểu
con trỏ trong FP như một biến nguyên 32 bit, giá trị của nó là một địa chỉ trong bộ nhớ.
Do đó FP có một số phép toán đối với con trỏ như sau:
Phép cộng : nếu p là một con trỏ kiểu X, i là một số nguyên, thì p+i cũng là một con trỏ
kiểu X và p+i trỏ đến biến có địa chỉ cách biến p trỏ đến i phần tử kiểu X. Chẳng hạn nếu
X là kiểu Int64, thì p+1 sẽ trỏ đến biến Int64 tiếp theo biến mà p trỏ đến.
Phép trừ : nếu p, q là 2 con trỏ cùng kiểu thì p-q là độ lệch của chúng, có giá trị bằng số
phần tử trong khoảng đó nhân với kích thước của kiểu mà chúng trỏ đến.
Phép tham chiếu : nếu p là một con trỏ thì p^ là biến mà p trỏ đến. Ta cũng có p+i là con
trỏ nên (p+i)^ cũng là biến mà p+i trỏ đến. Chú ý là cách viết này rất thường gặp trong C,
nhưng trong TP thì hoàn toàn không có. FP còn cải tiến cho phép viết (p+i)^ dạng p[i],
nghĩa là hoàn toàn giống C. Chú ý là p^ có thể viết là p[0].
Như vậy ta có thể coi một con trỏ như một mảng động. Ta có thể dùng các lệnh GetMem,
FreeMem để cấp phát động bộ nhớ và dùng cú pháp của mảng để truy cập.
Chương trình sau demo tính năng sử dụng con trỏ như mảng trong FP:
CODE
uses crt,go32;
var
14
a : ^integer;

n,i : integer;
BEGIN
n := 100;
GetMem(a,n);
for i := 0 to n-1 do a[i] := i;
FreeMem(a);
END.
Với tính năng này, chúng ta có thể sử dụng các con trỏ như các mảng động (dynamic
array), tức là khai báo mảng mà không cần xác định trước số phần tử, sau đó mảng được
cấp phát động trong quá trình thực thi.
Trong TP chúng ta dùng từ khoá absolute để xác định một vị trí cố định trong bộ nhớ.
Khai báo đó gọi là địa chỉ tuyệt đối. Chẳng hạn để đo thời gian chạy của chương trình,
người ta khai báo biến time kiểu longint tại địa chỉ 0:$46C, bởi vì vị trí đó là nơi máy tính
lưu bộ đếm của đồng hồ. Tần số cập nhật của nó là 18.2 lần/giây. Một chương trình ví dụ
của TP như sau:
CODE
var
time : LongInt absolute 0:$46C;
start : LongInt;
i,n : LongInt;
BEGIN
start := time;
for i := 1 to 10000000 do n := i;
writeln('Runned in: ',(time-start)/18.2:0:3);
readln;
END.
Trên máy tính của tôi, chương trình đơn giản này chạy mất gần 6 giây (5.814 giây).
FP chạy trong môi trường 32 bit, ở chế độ bảo vệ. Trong chế độ bảo vệ, không có khái
niệm địa chỉ tuyệt đối (để giải thích kĩ càng về điều này, chắc cần một bài báo rất dài). Để
sử dụng khai báo absolute, ta phải khai báo sử dụng unit go32. Unit go32 cho phép thao

tác vào vùng nhớ của DOS. Tất nhiên là chỉ có chương trình được dịch để chạy trên DOS
32 bit (target là DOS GO32v2) thì mới sử dụng được.
Chương trình trên được sửa để chạy trên FP như sau:
CODE
uses crt,go32;
var
time : LongInt absolute 0:$46C;
start : LongInt;
i,n : LongInt;
BEGIN
start := time;
for i := 1 to 10000000 do n := i;
writeln('Runned in: ',(time-start)/18.2:0:3);
readln;
END.
15
Thật kinh ngạc: trên máy tính của tôi chương trình đơn giản này chạy mất 0.000 giây!!!
Tôi tăng hằng số 10000000 lên 10 lần (thêm một chữ số 0 vào) thì chương trình chạy
trong 0.440 giây. Như vậy so với TP, FP nhanh hơn rất nhiều. Tôi chỉ có thể phỏng đoán
là FP sinh ra chương trình mã 32 bit, lại được tối ưu hoá mã cho Pentium nên nhanh hơn
TP vốn chỉ sinh mã 16 bit và hoàn toàn không có chức năng tối ưu mã. Đây có lẽ cũng là
một lí do rất thuyết phục để thay thế TP bằng FP.
3. Đồ hoạ trong FP
TP phiên bản cuối cùng là 7.0 ra đời năm 1992. Vào hồi đó, phần cứng đồ hoạ còn khá
yếu nên TP 7.0 chỉ hỗ trợ chế độ đồ hoạ cao nhất là 640x480x4 bit (16 màu). Bây giờ là
năm 2004, đồ hoạ máy tính đã rất mạnh, nhưng nếu dùng TP thì ta cũng chỉ dùng được
chế độ cao nhất đó thôi. Nếu có driver SVGA (SVGA256.BGI) thì ta có thể sử dụng
được các chế độ 256 màu. Nhưng nếu dùng FP, chúng ta có thể có chế độ đồ hoạ cao hơn
nhiều. Theo thử nghiệm thì tôi đã dùng được chế độ 800x600x16bit (64K màu) trong FP.
Nghĩa là chẳng không thua kém nhiều các môi trường lập trình trên Windows.

Unit Graph của FP tương thích hoàn toàn TP. Như vậy chúng ta vẫn có thể dùng các
chương trình đồ hoạ được viết trên TP để dịch lại và chạy trong FP mà không cần sửa đổi
gì. Hơn nữa, chúng ta có thể sử dụng những mode đồ hoạ với độ phân giải và số màu
nhiều hơn với những thao tác vẽ đơn giản và quen thuộc của TP.
Bảng sau là các driver và mode đồ hoạ mới trong FP. Chú ý là do FP là đa môi trường
(multi platform), tức là sinh mã cho nhiều hệ điều hành và hệ máy khác nhau, do đó có
thể những chế độ đồ hoạ không được một số hệ nào đó hỗ trợ.
D1bit = 11;
D2bit = 12;
D4bit = 13;
D6bit = 14; { 64 colors Half-brite mode - Amiga }
D8bit = 15;
D12bit = 16; { 4096 color modes HAM mode - Amiga }
D15bit = 17;
D16bit = 18;
D24bit = 19; {chưa được hỗ trợ}
D32bit = 20; {chưa được hỗ trợ}
D64bit = 21; {chưa được hỗ trợ}
detectMode = 30000;
m320x200 = 30001;
m320x256 = 30002; { amiga resolution (PAL) }
m320x400 = 30003; { amiga/atari resolution }
m512x384 = 30004; { mac resolution }
m640x200 = 30005; { vga resolution }
m640x256 = 30006; { amiga resolution (PAL) }
m640x350 = 30007; { vga resolution }
m640x400 = 30008;
m640x480 = 30009;
m800x600 = 30010;
m832x624 = 30011; { mac resolution }

m1024x768 = 30012;
m1280x1024 = 30013;
m1600x1200 = 30014;
m2048x1536 = 30015;
Còn sau đây là một chương trình demo về chế độ đồ hoạ cao của FP (800x600x16 bit).
16
Nếu máy của bạn hỗ trợ chế độ này, bạn sẽ thấy một dải màu rất đẹp.
CODE
uses graph;
var
gd, gm, i, error: integer;
BEGIN
gd := D16bit;
gm := m800x600;
initgraph(gd,gm,'');
error := graphResult;
if (error <> grOk) then begin
writeln('800x600x16bit is not supported!');
halt(1)
end;
for i := 1 to 600 do begin
setColor(random(65536));
line(0,i,799,i);
end;
readln;
closegraph;
END.
4. Xử lí lỗi ngoại lệ
Phần lớn các ngôn ngữ lập trình cao cấp đều có hỗ trợ xử lí lỗi ngoại lệ. Chẳng hạn
Visual Basic có lệnh On Error, C++, Java có nhóm lệnh try catch, Delphi, FP có nhóm

lệnh try except. Nói một cách đơn giản là: trong khi phương pháp xử lí lỗi truyền thống
né tránh lỗi (tức là kiểm tra trước để đảm bảo không có lỗi thì mới làm) thì phương pháp
lập trình xử lí lỗi ngoại lệ là thực hiện bình thường và dự phòng trước tình huống nếu gặp
lỗi.
Chúng ta có thể xét một ví dụ là thực hiện một phép chia biến a cho biến b. Trong TP ta
sẽ viết như sau:
if b <> 0 then c := a/b
else write ('Error: b=0.');
Trong FP, sử dụng tính năng xử lí lỗi ngoại lệ, chúng ta có thể viết như sau:
try
c := a/b;
except
on EDivByZero do begin
c := 0;
write('Error.');
end;
end;
Các bạn có thể nói: như vậy rõ ràng phức tạp, rắc rối hơn. Tất nhiên, tôi đồng ý. Nhưng
hãy nhìn vào ưu điểm của phương pháp xử lí lỗi ngoại lệ so với phương pháp truyền
thống: - Phương pháp kiểm tra không phải lúc nào cũng lường trước được mọi tình huống
và thường phải thực hiện những phép kiểm tra rất tốn thời gian. Phương pháp xử lỗi
ngoại lệ không cần những kiểm tra như vậy nên đơn giản hơn. Hơn nữa có những tình
huống phải thực hiện rồi mới biết là có lỗi (chẳng hạn đọc file, cộng 2 số ) - Phương
pháp truyền thống xử lí lỗi một cách không thống nhất: ở mức nào của chương trình bạn
cũng phải có những đoạn trình xử lí riêng và mỗi lỗi cũng phải có đoạn trình xử lí riêng.
17
Với phương pháp xử lí lỗi ngoại lệ ta có thể chủ động đưa lỗi lên mức xử lí cao nhất,
thậm chí tự gây ra lỗi để chuyển quyền điều khiển (bằng lệnh raise).
- Phương pháp truyền thống sau khi gặp lỗi thường rất khó phục hồi lỗi. Phương pháp xử
lí lỗi ngoại lệ có nhóm lệnh try finally sẽ đảm bảo dù gặp lỗi hay không những lệnh của

khối finally đều được thực hiện.
Phương pháp xử lí lỗi ngoại lệ là phương pháp rất hay nhưng không thể trình bày đơn
giản trong một đoạn báo ngắn được. Các bạn nếu thấy thú vị thì có thể tự tìm hiểu trong
các tài liệu của FP, Delphi hay Java.
Như vậy qua một loạt bài báo, tôi đã trình bày về những điểm mạnh của FP so với TP,
dưới góc độ một môi trường lập trình dành cho học sinh phổ thông hay sinh viên đại học
làm quen lập trình hoặc rèn luyện chuẩn bị cho các kì thi HSG hay Olympic. Tất nhiên
FP còn rất nhiều điểm mạnh khác như lập trình hướng đối tượng (OOP), đa nhiệm, đa
luồng và đa nền (multi process - multi thread - multi platform), hỗ trợ trao tác CSDL và
lập trình mạng nhưng đó là những lợi thế trong lập trình chuyên nghiệp, tạm thời chúng
ta chưa xét đến.
Chúng ta có thể tổng kết lại như sau những điểm mạnh của FP so với TP, những điểm đủ
thuyết phục để dùng FP thay thế TP:
- Không hạn chế bộ nhớ hay kích thước kiểu dữ liệu (mảng, xâu).
- Hàm có nhiều cải tiến: trả lại kết quả kiểu cấu trúc, định nghĩa hàm trùng tên, định
nghĩa phép toán, cho phép dùng tên hàm như biến, dùng biến result hoặc lệnh exit để trả
lại kết quả.
- Kiểu mảng mở và kiểu con trỏ uyển chuyển hơn, cho phép dùng con trỏ như mảng
động.
- Hỗ trợ các chế độ đồ hoạ cao cấp.
- Cho phép lập trình xử lí lỗi ngoại lệ.
- Tương thích hoàn toàn TP, cả về mã lệnh hay giao diện IDE. Sinh mã 32 bit tối ưu nên
tốc độ nhanh hơn TP rất nhiều lần. Hơn nữa FP có thể sinh mã cho nhiều hệ máy và hệ
điều hành khác nhau.
Và một điều rất quan trọng là FP là phần mềm nguồn mở, hoàn toàn miễn phí. Khi luật
bản quyền ở Việt Nam được thực thi nghiêm túc, Linux sẽ trở nên phổ biến và việc sử
dụng các môi trường lập trình cao cấp như .NET, Java và HĐH Windows sẽ phải trả tiền
bản quyền. Khi đó thành thạo FP sẽ là một lợi thế.
Phụ lục 01: Các lỗi hay gặp của FP
1 Invalid function number

An invalid operating system call was attempted.
2 File not found
Reported when trying to erase, rename or open a non-existent file.
3 Path not found
Reported by the directory handling routines when a path does not exist or is invalid. Also
reported when trying to access a non-existent file.
4 Too many open files
The maximum number of currently opened files by your process has been reached.
Certain operating systems limit the number of files which can be opened concurrently,
and this error can occur when this limit has been reached.
18
5 File access denied
Permission accessing the file is denied. This error might be caused by several reasons:
Trying to open for writing a file which is read only, or which is actually a directory.
File is currently locked or used by another process.
Trying to create a new file, or directory while a file or directory of the same name already
exists.
Trying to read from a file which was opened in write only mode.
Trying to write from a file which was opened in read only mode.
Trying to remove a directory or file while it is not possible.
No permission to access the file or directory.
6 Invalid file handle
If this happens, the file variable you are using is trashed; it indicates that your memory is
corrupted.
12 Invalid file access code
Reported when a reset or rewrite is called with an invalid FileMode value.
15 Invalid drive number
The number given to the Getdir or ChDir function specifies a non-existent disk.
16 Cannot remove current directory
Reported when trying to remove the currently active directory.

17 Cannot rename across drives
You cannot rename a file such that it would end up on another disk or partition.
100 Disk read error
An error occurred when reading from disk. Typically when you try to read past the end of
a file.
101 Disk write error
Reported when the disk is full, and you're trying to write to it.
102 File not assigned
This is reported by Reset, Rewrite, Append, Rename and Erase, if you call them with an
unassigned file as a parameter.
103 File not open
Reported by the following functions : Close, Read, Write, Seek, EOf, FilePos, FileSize,
Flush, BlockRead, and BlockWrite if the file is not open.
104 File not open for input
Reported by Read, BlockRead, Eof, Eoln, SeekEof or SeekEoln if the file is not opened
with Reset.
105 File not open for output
Reported by write if a text file isn't opened with Rewrite.
106 Invalid numeric format
19
Reported when a non-numeric value is read from a text file, when a numeric value was
expected.
150 Disk is write-protected
(Critical error)
151 Bad drive request struct length
(Critical error)
152 Drive not ready
(Critical error)
154 CRC error in data
(Critical error)

156 Disk seek error
(Critical error)
157 Unknown media type
(Critical error)
158 Sector Not Found
(Critical error)
159 Printer out of paper
(Critical error)
160 Device write fault
(Critical error)
161 Device read fault
(Critical error)
162 Hardware failure
(Critical error)
200 Division by zero
The application attempted to divide a number by zero.
201 Range check error
If you compiled your program with range checking on, then you can get this error in the
following cases:
An array was accessed with an index outside its declared range.
Trying to assign a value to a variable outside its range (for instance an enumerated type).
202 Stack overflow error
The stack has grown beyond its maximum size (in which case the size of local variables
should be reduced to avoid this error), or the stack has become corrupt. This error is only
reported when stack checking is enabled.
203 Heap overflow error
20
The heap has grown beyond its boundaries. This is caused when trying to allocate
memory exlicitly with New, GetMem or ReallocMem, or when a class or object instance
is created and no memory is left. Please note that, by default, Free Pascal provides a

growing heap, i.e. the heap will try to allocate more memory if needed. However, if the
heap has reached the maximum size allowed by the operating system or hardware, then
you will get this error.
204 Invalid pointer operation
This you will get if you call Dispose or Freemem with an invalid pointer (notably, Nil)
205 Floating point overflow
You are trying to use or produce too large real numbers.
206 Floating point underflow
You are trying to use or produce too small real numbers.
207 Invalid floating point operation
Can occur if you try to calculate the square root or logarithm of a negative number.
210 Object not initialized
When compiled with range checking on, a program will report this error if you call a
virtual method without having called istr constructor.
211 Call to abstract method
Your program tried to execute an abstract virtual method. Abstract methods should be
overridden, and the overriding method should be called.
212 Stream registration error
This occurs when an invalid type is registered in the objects unit.
213 Collection index out of range
You are trying to access a collection item with an invalid index (objects unit).
214 Collection overflow error
The collection has reached its maximal size, and you are trying to add another element
(objects unit).
215 Arithmetic overflow error
This error is reported when the result of an arithmetic operation is outside of its supported
range. Contrary to Turbo Pascal, this error is only reported for 32-bit or 64-bit arithmetic
overflows. This is due to the fact that everything is converted to 32-bit or 64-bit before
doing the actual arithmetic operation.
216 General Protection fault

The application tried to access invalid memory space. This can be caused by several
problems:
Deferencing a nil pointer
Trying to access memory which is out of bounds (for example, calling move with an
invalid length).
217 Unhandled exception occurred
21
An exception occurred, and there was no exception handler present. The sysutils unit
installs a default exception handler which catches all excpetions and exits gracefully.
219 Invalid typecast
Thrown when an invalid typecast is attempted on a class using the as operator. This error
is also thrown when an object or class is typecast to an invalid class or object and a
virtual method of that class or object is called. This last error is only detected if the -CR
compiler option is used.
227 Assertion failed error
An assertion failed, and no AssertErrorProc procedural variable was installed.
22

×