C
C
H
H
Ư
Ư
Ơ
Ơ
N
N
G
G
I
I
I
I
I
I
:
:
C
C
Ơ
Ơ
B
B
Ả
Ả
N
N
V
V
Ề
Ề
N
N
G
G
Ô
Ô
N
N
N
N
G
G
Ữ
Ữ
L
L
Ậ
Ậ
P
P
T
T
R
R
Ì
Ì
N
N
H
H
V
V
I
I
S
S
U
U
A
A
L
L
B
B
A
A
S
S
I
I
C
C
53
Một chương trình con đơn giản được tạo ra như sau:
Public Sub Test(ByRef a As Long, b As Long, ByVal c As Long)
a = 100: b = 200: c = 300
End Sub
Chú ý đến khai báo biến a, b và c của chương trình con này:
Ø
Ø
Trước biến a là từ khóa ByRef.
Ø
Ø
Trước biến b không có từ khóa, nghĩa là sử dụng kiểu mặc định của VB.
Ø
Ø
Trước biến c là từ khóa
ByVal.
Chương trình con thứ hai được xây dựng trên cùng một mô-đun với chương trình con trên
như sau:
Public Sub CallTest()
Dim va As Long, vb As Long, vc As Long
va = 500: vb = 500: vc = 500
' In giá trị của biến trước khi gọi chương trình con thứ nhất
Debug.Print " Cac gia tri bien truoc khi goi chuong trinh con:"
Debug.Print "va=" & Str(va)
Debug.Print "vb=" & Str(vb)
Debug.Print "vc=" & Str(vc)
' Gọi chương trình con thứ nhất
Test va, vb, vc
' In giá trị của biến sau khi gọi chương trình con thứ nhất
Debug.Print " Cac gia tri bien sau khi goi chuong trinh con:"
Debug.Print "va=" & Str(va)
Debug.Print "vb=" & Str(vb)
Debug.Print "vc=" & Str(vc)
End Sub
Trong chương trình con thứ 2 có lời gọi đến chương trình con thứ nhất để thực hiện thay đổi
giá trị của các biến. Kết quả khi thực thi chương trình con thứ 2 như sau:
Qua kết quả trên có thể thấy rằng:
Giá trị của biến có thể bị thay đổi hoặc không bị thay đổi khi chúng được truyền vào chương
trình con là phụ thuộc vào cách định nghĩa tham số trong chương trình con đó.
Ø
Ø
Biến
a trong Sub Test được khai báo với từ khóa ByRef và khi truyền biến ở vị trí này
(biến
va trong CallTest) thì giá trị của biến ban đầu bị thay đổi tương ứng với các tác
động trong chương trình con.
Giáo trình hướng dẫn cách tạo lập những chương trình lập trình
trên cùng một mặc định
54
Ø
Ø
Biến
b trong Sub Test được khai báo mặc định (không có từ khóa nào phía trước nó) và
khi truyền biến ở vị trí này (biến
vb trong CallTest) thì giá trị của biến ban đầu bị thay
đổi tương ứng với các tác động trong chương trình con.
Ø
Ø
Biến
c trong Sub Test được khai báo với từ khóa ByVal và khi truyền biến ở vị trí này
(biến
vc trong CallTest) thì giá trị của biến ban đầu không bị thay đổi cho dù trong
chương trình con biến này bị tác động.
Qua ví dụ trên có thể thấy rằng việc truyền tham số cho chương trình con có thể được phân làm
hai trường hợp và được đặt tên là truyền tham số theo tham chiếu và truyền tham số theo tham
trị.
9.3.1. Truyền tham số theo tham chiếu
Khi truyền một biến vào tham số theo kiểu tham chiếu, địa chỉ của biến sẽ
được truyền cho
chương trình con. Do đó, bất kì câu lệnh nào của chương trình con tác động lên tham số sẽ ảnh
hưởng trực tiếp lên biến được truyền tương ứng, nghĩa là khi chương trình con kết thúc, giá trị
của biến được truyền theo kiểu này sẽ bị thay đổi do chương trình con. Truyền tham số theo
kiểu tham chiếu là mặc định trong VB, người dùng cũng có thể chỉ rõ việc truyền theo tham
chiếu bằng cách thêm từ
khoá ByRef vào trước khai báo tham số.
9.3.2. Truyền tham số theo tham trị
Khi truyền một biến vào tham số theo kiểu tham trị, bản sao giá trị của biến sẽ được truyền cho
cho chương trình con. Do đó, nếu trong chương trình con có các câu lệnh tác động lên tham số
thì chỉ bản sao bị ảnh hưởng và biến truyền vào sẽ không bị thay đổi, nghĩa là sau khi chương
trình con kết thúc, giá trị của biến vẫn được giữ nguyên như ban đầu. Để
xác định cách thức
truyền dữ liệu cho một tham số theo kiểu tham trị, thêm từ khoá
ByVal vào trước khai báo
tham số.
Trong
Sub Test ở trên, a và b là hai tham số được truyền theo kiểu tham chiếu còn c được
truyền theo kiểu tham trị.
9.3.3. Tham số tuỳ chọn.
Tham số tuỳ chọn là tham số có thể có hoặc được bỏ qua khi gọi chương trình con.
Các tham số tuỳ chọn được khai báo với từ khoá
Optional và trong một chương trình con, các
khai báo của các tham số tuỳ chọn luôn phải nằm cuối danh sách tham số được khai báo.
Ví dụ: viết chương trình con tính toán diện tích của mặt cắt chữ nhật có khoét lỗ (như hình
dưới) với yêu cầu sau:
Ø
Ø
Tính diện tích mặt cắt với các thông số về chiều rộng w, chiều cao h và bán kính r của lỗ
khoét.
Ø
Ø
Trong trường hợp thiếu thông số về bán kính r, chỉ tính di
ện tích mặt cắt chữ nhật và bỏ
qua lỗ khoét.
Dưới đây là một chương trình con có sử dụng tham số tuỳ chọn:
Public Function DT(w As Double, h As Double, Optional r As Variant)
If Not IsMissing(r) Then
If (2 * r <= w) And (2 * r <= h) Then
C
C
H
H
Ư
Ư
Ơ
Ơ
N
N
G
G
I
I
I
I
I
I
:
:
C
C
Ơ
Ơ
B
B
Ả
Ả
N
N
V
V
Ề
Ề
N
N
G
G
Ô
Ô
N
N
N
N
G
G
Ữ
Ữ
L
L
Ậ
Ậ
P
P
T
T
R
R
Ì
Ì
N
N
H
H
V
V
I
I
S
S
U
U
A
A
L
L
B
B
A
A
S
S
I
I
C
C
55
DT = w * h - pi * r ^ 2
Else
MsgBox " Co loi, lo khoet vuot ra ngoai hinh"
DT = "Error"
End If
Else
DT = w * h
End If
End Function
Sau khi tạo mã lệnh trên, nếu muốn tính diện tích cho mặt cắt với w =100, h =200, r =20 có thể
gọi hàm như sau:
DT(100,200,20) để tính diện tích có xét đến khoét lỗ với bán kính là 20,
hoặc
DT(100,200) để tính diện của hình chữ nhật (không có lỗ).
CHÚ Ý Để biết được một tham số tuỳ chọn có bị bỏ qua khi gọi chương trình con hay
không, dùng hàm IsMissing(tham_số_tuỳ_chọn) và đồng thời tham số tuỳ chọn
bắt buộc phải có kiểu dữ liệu là Variant (vì hàm
IsMissing chỉ có hiệu lực đối với các
biến kiểu Variant). Hàm này trả về TRUE nếu tham số bị bỏ qua, FALSE nếu tham số có
mặt.
9.3.4. Danh sách tham số với số lượng tham số tuỳ ý.
Visual Basic 6.0 cho phép tạo một chương trình con với danh sách tham số tuỳ ý (nghĩa là số
lượng các tham số có thể thay đổi khi gọi chương trình con) thông qua việc đặt từ khoá
ParamArray trước danh sách tham số. Khi đó danh sách tham số là tuỳ chọn và có dạng một
mảng kiểu
Variant.
Ví dụ: viết một hàm tính tổng của tất cả các số truyền vào với số lượng số được truyền là tuỳ ý.
Mã lệnh tham khảo như sau:
Public Function TinhTong(ParamArray ds())
Dim So As Variant
Dim Tong As Variant
Tong = 0
For Each So In ds
Tong = Tong + So
Next
TinhTong = Tong
End Function
Khi đó:
TinhTong(100,200,-200) cho kết quả là 100
TinhTong(2,300) cho kết quả là 302
9.3.5. Hàm có giá trị trả về là kiểu mảng.
Để khai báo một hàm trả về mảng, thêm cặp kí tự “( )” sau khai báo hàm
[Private/Public] Function <Tên_hàm> ([danh sách tham số]) as _
<kiểu_dữ_liệu> ()
[Khối_lệnh]
End Function
Ví dụ: viết chương trình con sắp xếp các phần tử trong mảng một chiều và trả về một mảng có
thứ tự tăng dần.
56
Mã lệnh tham khảo như sau:
Public Function Mang_tangdan(Mang_bandau() As Double) As Double()
Dim Lb As Long, Ub As Long ' bien dau va cuoi cua mang
Dim i As Long, j As Long
Lb = LBound(Mang_bandau): Ub = UBound(Mang_bandau)
Dim Mang_tamthoi() As Double ‘ Khai bao mot mang tam thoi
Mang_tamthoi = Mang_bandau
Dim Tg As Double
For i = Lb To Ub - 1
For j = i + 1 To Ub
If Mang_tamthoi(i) > Mang_tamthoi(j) Then
Tg = Mang_tamthoi(i)
Mang_tamthoi(i) = Mang_tamthoi(j)
Mang_tamthoi(j) = Tg
End If
Next
Next
Mang_tangdan = Mang_tamthoi
Erase Mang_tamthoi ' Huy mang tam thoi
End Function
Chương trình thử nghiệm hàm trên:
Public Sub test()
Dim a(2 To 6) As Double
a(2) = 1: a(3) = 6: a(4) = 0.5: a(5) = 2.3: a(6) = 4
Dim b() As Double
b = Mang_tangdan(a) ‘ Goi ham da viet
Dim so As Variant
Debug.Print "Cac phan tu cua mang ban dau:"
For Each so In a
Debug.Print so
Next
Debug.Print "Cac phan tu cua mang sau khi sap xep:"
For Each so In b
Debug.Print so
Next
End Sub
Kết quả như sau:
C
C
H
H
Ư
Ư
Ơ
Ơ
N
N
G
G
I
I
I
I
I
I
:
:
C
C
Ơ
Ơ
B
B
Ả
Ả
N
N
V
V
Ề
Ề
N
N
G
G
Ô
Ô
N
N
N
N
G
G
Ữ
Ữ
L
L
Ậ
Ậ
P
P
T
T
R
R
Ì
Ì
N
N
H
H
V
V
I
I
S
S
U
U
A
A
L
L
B
B
A
A
S
S
I
I
C
C
57
9.4. Biến trong chương trình con
Như đã trình bày ở phần trước, biến trong chương trình con luôn có tính chất cục bộ. Tuy nhiên
hình thức cấp phát bộ nhớ cho biến thì có thể khác nhau. Tuỳ vào từng trường hợp cụ thể:
Trường hợp: trong phần khai báo của chương trình con không sử dụng từ khóa Static
Với các biến được khai báo bình thường với từ khoá Dim: mỗi lần chương trình con được gọi,
biến sẽ được tạo và cấp phát bộ nhớ. Khi chương trình con kết thúc, bộ nhớ dành cho biến được
giải phóng. Do đó, giá trị của biến sau mỗi phiên làm việc của chương trình con sẽ không được
lưu trữ.
Với các biến đượ
c khai báo với từ khoá Static: biến sẽ được khởi tạo một lần khi mô-đun chứa
chương trình con được nạp vào trong bộ nhớ và sẽ tồn tại trong bộ nhớ cùng với mô-đun đó. Vì
vậy, giá trị của biến sau mỗi phiên làm việc của chương trình con sẽ được lưu trữ. Các biến
kiểu này được gọi là biến tĩnh (
Static)
Ví dụ: trong chương trình con
StVariable dưới đây có hai biến địa phương, stA là biến tĩnh
và
B là biến thông thường.
Public Sub StVariable()
Static stA As Long
Dim B As Long
B = B + 1
stA = stA + 1
Debug.Print "Lan chay " & Str(stA), "stA=" & Str(stA), "B=" &
Str(B)
End Sub
Kết quả sau 2 lần chạy chương trình con trên như sau:
Giảithích
Ngay khi được khai báo, tất cả các biến đều được tự động khởi tạo giá trị ban đầu, nếu kiểu dữ
liệu của biến là dạng số thì giá trị khởi tạo bằng 0, còn nếu kiểu dữ liệu của biến là chuỗi thì giá
trị khởi tạo mặc định là chuỗi rỗng. Trong chương trình trên, ngay trước khi kết thúc ở lần chạy
đầu tiên, giá trị
của các biến như sau:
Ø
Ø
Biến B = 1.
Ø
Ø
Biến stA = 1.
Khi kết thúc lần chạy thứ nhất, biến
B (biến thông thường) sẽ được giải phóng, còn biến stA
(biến tĩnh) vẫn được lưu giá trị (=1) của nó lại trong bộ nhớ. Do đó đến lần chạy thứ hai, biến
B
được tạo mới sẽ nhận giá trị là
B=B+1=0+1=1, còn biến stA do vẫn tồn tại từ lần trước nên giá
trị của nó là
stA=stA+1=1+1=2.
Trường hợp: trong khai báo của chương trình con có sử dụng từ khóa Static
Khi đó tất cả các biến khai báo trong chương trình con sẽ là các biến tĩnh.
Ví dụ: trong chương trình con
StPro dưới đây đã sử dụng khai báo Static ở đầu chương
trình.