a. Các đặc trưng của hàm
Các yếu tố đặc trưng cho một hàm gồm có:
• Tên hàm
• Kiểu dữ liệu của các tham số
• Kiểu dữ liệu của giá trị hàm
o Hàm Sqrt(x): cho căn hai của x. Tên hàm là Sqrt, tham số x là nguyên hay thực còn giá trị hàm kiểu thực, ví dụ Sqrt(4)=2.0.
o 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 giá trị hàm kiểu ký tự, ví dụ Chr(65)=‘A’.
o 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à giá trị hàm kiểu lôgic, ví dụ Odd(4)=False.
o Hàm Copy(St, k, n): cho chuỗi con gồm n ký tự của 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à giá trị hàm kiểu chuỗi, ví dụ Copy(‘ABCD’, 2, 3) = ‘BCD’.
o Hàm Readkey: không có tham số, giá trị hàm kiểu ký tự, hàm nhận một ký tự được gõ từ bàn phím.
Tóm lại, hàm có thể không có tham số hoặc có một đến nhiều tham số, nhưng hàm luôn trả về một giá trị duy nhất.
Các tham số luôn luôn phải để trong cặp nháy đơn (), nếu có nhiều tham số thì chúng phải phân cách nhau bằng dấu phẩy. Mỗi khi gọi hàm (call) ta phải cho các tham số các giá trị cụ thể phù hợp với kiểu dữ liệu của tham số. Ví dụ:
For k:=1 to 10 do 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ủa 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ố chỉ mang tính tượng trưng, nên gọi là tham số hình thức, còn khi gọi hàm, các tham số phải là các biến hay các giá trị cụ thể nên gọi là các tham số thực sự.
Ví dụ, khi viết Sqrt(x) thì x là tham số hình thức, nó đại diện cho một giá trị nào đó. Còn khi gọi hàm y:=Sqrt(4); thì 4 là tham số thực sự.
b. Khai báo hàm tự viết
Tất cả các hàm có sẵn trong Turbo Pascal gọi là các hàm chuẩn, chúng có thể được 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 được yêu cầu đa dạng của người sử dụng, cho nên khi thảo chương, ta thường phải tự xây dựng thêm các hàm mới.
Các hàm tự viết cần phải được khai báo, theo cú pháp sau:
Const ... Type ... Var ... Begin {Các lệnh của hàm} End;
Tên hàm và tên tham số phải được đặt theo đúng quy tắc của một tên. Thông thường tên hàm nên đặt sao cho gợi nhớ giá trị mà nó chứa. Tên tham số ở mức khai báo này chỉ mang tính tượng trưng nên mới gọi là tham số hình thức.
Nếu có nhiều tham số hình thức thuộc cùng một kiểu dữ liệu thì chúng được viết phân cách nhau bằng 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 dữ liệu khác nhau thì phải khai báo riêng ra 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à một chương trình con nên nó cũng có đầy đủ các thành phần như một chương trình bình thường, tức là cũng có thể có khai báo hằng (Const), khai báo kiểu dữ liệu mới (Type) và khai báo biến (Var). Thân của hàm là các lệnh được đặt giữa hai từ khóa Begin và End, kết thúc bằng dấu chấm phẩy ";" chứ 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).
c. Kiểu dữ liệu của tham số và giá trị hàm
• Kiểu dữ liệu của kết quả của hàm không thể là mảng (array), bản ghi (record), tập hợp (set) hay tập tin (file).
Khai báo hàm như dưới đây là sai:
Function F(x: Integer): array[1..10] of Real;
• Kiểu dữ liệu của kết quả của hàm có thể là các kiểu đơn giản, chuỗi, hay con trỏ. Nếu là kiểu liệt kê, đoạn con 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 như sau là sai: Function F(x: Real): String[20]; Function F(x: Real): 1..31;
Mà phải định nghĩa kiểu trước:
Type
Str20= String[20]; Ngay = 1..31; rồi mới 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;
• Kiểu dữ liệu của tham số trong hàm và thủ tục thì không hạn chế. Nhưng nếu là kiểu chuỗi (trừ kiểu String) hay kiểu tự xây dựng thì phải được định nghĩa trước bằng 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];
rồi mới 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 ;
d. Ví dụ
Ví dụ 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 căn bậc ba của z, tức là:
S:=0;
For i:=1 to N do S:=S + Canba(x[i] );
Ở đây hàm Canba được tính N lần ứng với các tham số thực sự là các giá trị x[i], i=1,..., N. Vấn đề còn lại là phải viết hàm tính căn ba của z. Hàm này có tên là Canba, tham số z kiểu thực, và giá trị hàm cũng kiểu thực, nó được xây dựng như sau:
FUNCTION Canba(z: Real):Real;
{ Hàm tính căn bậc ba của 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;
Ðặt đoạn khai báo hàm trên đây vào ngay trước phần thân của chương trình chính, ta được chương trình đầy đủ sau đây:
PROGRAM VIDU5_1; Var
x: Array[1..20] of Real; S: Real;
N, i: integer;
FUNCTION Canba(z: Real):Real;
{ Hàm tính căn bậc ba của 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 Write(‘ nhap N: ‘); Readln(N); Until (N>0) and (N<21); S:=0; For i:=1 to N do begin Write(‘nhap x[‘, i, ‘]:’); Readln(x[i]); S:=S + Canba(x[i] ) end; Writeln(‘ S= ‘, S:8:2); Readln END. e. Các chú ý khi viết hàm:
• Ta chọn chương trình con là hàm khi cần nhận lại một giá trị duy nhất thông qua tên hàm, nhờ đó có thể dùng tên hàm trong các biểu thức. Ví dụ, vì Gt(4) là một giá trị nên ta có thể viết:
k:= Gt(4) - 1 ;
Write(‘ Giai thừa của 4 là ‘, Gt(4) );
• Vì tên hàm chứa giá trị hàm nên trong thân của hàm phải có ít nhất một lệnh gán:
Thông thường ta dùng một biến trung gian để tính giá trị hàm, xong xuôi mới gán biến trung gian đó cho tên hàm trước khi kết thúc hàm. Ở ví dụ 3.1, trong hàm Canba ta dùng biến F để tính giá trị hàm, sau cùng mới gán Canba:=F; trước khi kết thúc hàm.
• Về phong cách lập trình, trong hàm nên tránh dùng các lệnh nhập hay in dữ liệu (Readln, Write). Các tham số hình thức chính là các dữ liệu phục vụ cho các tính toán trong hàm, chúng sẽ có giá trị cụ thể khi gọi hàm. Việc nhập dữ liệu hay in kết quả thường để trong thân chương trình chính.