Lệnh return
có hai mục đích:
Ngay lập
tức trả điều khiển từ hàm về chương trình gọi
Bất kỳ
cái gì bên trong cặp dấu ngoặc () theo sau return được trả về như là một
giá trị cho chương trình gọi.
Trong
hàm squarer(), một biến j kiểu int được định nghĩa để lưu giá trị
bình phương của đối số truyền vào. Giá trị của biến này được trả về cho hàm gọi
thông qua lệnh return. Một hàm có thể thực hiện một tác vụ xác định và
trả quyền điều khiển về cho thủ tục gọi nó mà không cần trả về bất kỳ giá trị
nào. Trong trường hợp như vậy, lệnh return có thể được viết dạng return(0)
hoặc return. Chú ý rằng, nếu một hàm cung cấp một giá trị trả về và nó
không làm điều đó thì nó sẽ trả về giá trị không thích hợp.
Trong
chương trình tính bình phương của các số, chương trình truyền dữ liệu tới hàm squarer
thông qua các đối số. Có thể có các hàm được gọi mà không cần bất kỳ đối số
nào. Ở đây, hàm thực hiện một chuỗi các lệnh và trả về giá trị, nếu được yêu cầu
Chú
ý rằng, hàm squarer()
cũng có thể được viết như sau
int squarer(int
x)
{
return(x*x);
}
Ở đây một
biểu thức hợp lệ được xem như một đối số trong câu lệnh return. Trong thực tế,
lệnh return có thể được sử dụng theo một trong các cách sau đây:
return;
return(hằng);
return(biến);
return(biểu thức);
return(câu lệnh đánh giá);
Ví dụ: return(a>b?a:b);
Tuy
nhiên, giới hạn của lệnh return là nó chỉ có thể trả về một giá trị duy
nhất.
Kiểu
của một hàm
type-specifier được sử dụng để xác định kiểu dữ liệu
trả về của một hàm. Trong ví dụ trên, type-specifier không được viết bên
cạnh hàm squarer(), vì squarer() trả về một giá trị kiểu int.
type-specifier là không bắt buộc nếu một giá trị kiểu số nguyên được trả về hoặc
nếu không có giá trị nào được trả về. . Tuy nhiên, tốt hơn nên chỉ ra kiểu dữ
liệu trả về là int nếu một giá trị số nguyên được trả về và tương tự dùng void
nếu hàm không trả về giá trị nào.
Gọi
hàm
Có thể
gọi một hàm từ chương trình chính bằng cách sử dụng tên của hàm, theo sau là cặp
dấu ngoặc (). Cặp dấu ngoặc là cần thiết để nói với trình biên dịch là đây là một
lời gọi hàm. Khi một tên hàm được sử dụng trong chương trình gọi, tên hàm có thể
là một phần của một một lệnh hoặc chính nó là một câu lệnh. Mà ta đã biết một
câu lệnh luôn kết thúc với một dấu chấm phẩy (;). Tuy nhiên, khi định
nghĩa hàm, không được dùng dấu chấm phầy ở cuối phần định nghĩa. Sự vắng mặt của
dấu chấm phẩy nói với trình biên dịch đây là phần định nghĩa của hàm và không
được gọi hàm.
Một số
điểm cần nhớ:
Một dấu
chấm phẩy được dùng ở cuối câu lệnh khi một hàm được gọi, nhưng nó không được
dùng sau một sự định nghĩa hàm.
Cặp dấu
ngoặc () là bắt buộc theo sau tên hàm, cho dù hàm có đối số hay không.
Hàm gọi
đến một hàm khác được gọi là hàm gọi hay thủ tục gọi. Và hàm được
gọi đến còn được gọi là hàm được gọi hay thủ tục được gọi.
Các hàm
không trả về một giá trị số nguyên cần phải xác định kiểu của giá trị được trả
về.
Chỉ một
giá trị có thể được trả về bởi một hàm.
Một
chương trình có thể có một hoặc nhiều hàm.
Khai
báo hàm
Một hàm
nên được khai báo trong hàm main() trước khi nó được định nghĩa hoặc sử dụng.
Điều này phải được thực hiện trong trường hợp hàm được gọi trước khi nó được định
nghĩa.
Ví dụ:
#include
<stdio.h>
int main()
{
.
.
address();
.
.
}
void address()
{
.
.
.
}
Hàm main()
gọi hàm address() và hàm address() được gọi trước khi nó được định
nghĩa. Mặc dù, nó không được khai báo trong hàm main() thì điều này có
thể thực hiện được trong một số trình biên dịch C, hàm address() được gọi
mà không cần khai báo gì thêm cả. Đây là sự khai báo không tường minh của
một hàm.
Các
nguyên mẫu hàm
Một
nguyên mẫu hàm là một khai báo hàm trong đó xác định rõ kiểu dữ liệu của các đối
số và trị trả về. Thông thường, các hàm được khai báo bằng cách xác định kiểu của
giá trị được trả về bởi hàm, và tên hàm. Tuy nhiên, chuẩn ANSI C cho phép số lượng
và kiểu dữ liệu của các đối số hàm được khai báo. Một hàm abc() có hai đối số kiểu int là x và
y, và trả về một giá trị kiểu char, có thể được khai báo như sau:
char
abc();
hoặc
char
abc(int x, nt y);
Cách định
nghĩa sau được gọi là nguyên mẫu hàm. Khi các nguyên mẫu được sử dụng, C
có thể tìm và thông báo bất kỳ kiểu dữ liệu không hợp lệ khi chuyển đổi giữa
các đối số được dùng để gọi một hàm với sự định nghĩa kiểu của các tham số. Một
lỗi sẽ được thông báo ngay khi có sự khác nhau giữa số lượng các đối số được sử
dụng để gọi hàm và số lượng các tham số khi định nghĩa hàm.
Cú pháp
tổng quát của một nguyên mẫu hàm:
type
function_name(type parm_namel,type parm_name2,..type parm_nameN);
Khi hàm
được khai báo không có các thông tin nguyên mẫu, trình biên dịch cho rằng không
có thông tin về các tham số được đưa ra. Một hàm không có đối số có thể gây ra
lỗi khi khai báo không có thông tin nguyên mẫu. Để tránh điều này, khi một hàm
không có tham số, nguyên mẫu của nó sử dụng void trong cặp dấu ngoặc ().
Như đã nói ở trên, void cũng được sử dụng để khai báo tường minh một hàm
không có giá trị trả về.
Ví dụ,
nếu một hàm noparam() trả về kiểu dữ liệu char và không có các tham số được gọi,
có thể được khai báo như sau
char
noparam(void);
Khai báo
trên chỉ ra rằng hàm không có tham số, và bất kỳ lời gọi có truyền tham số đến
hàm đó là không đúng.
Khi một
hàm không nguyên mẫu được gọi tất cả các kiểu char được đổi thành kiểu int
và tất cả kiểu float được đổi thành kiểu double. Tuy nhiên, nếu một
hàm là nguyên mẫu, thì các kiểu đã đưa ra trong nguyên mẫu được giữ nguyên và
không có sự tăng cấp kiểu xảy ra.
Tham
số hình thức
Một hàm
sử dụng các đối số phải khai báo các biến để nhận các giá trị của các đối số.
Các biến này được gọi là tham số hình thức của hàm và hoạt động giống
như bất kỳ một biến cục bộ bên trong hàm.
Các biến
này được khai báo bên trong cặp dấu ngoặc () theo sau tên hàm. Xem ví dụ sau:
blk1(char ch, int i)
{
if(i > 5)
ch = ‘a’;
else
i = i +1;
return;
}
Hàm blk1()
có hai tham số: ch và i.
Các
tham số hình thức phải được khai báo cùng với kiểu của chúng. Như trong ví dụ
trên, ch có kiều char và i có kiểu int. Các biến
này có thể được sử dụng bên trong hàm như các biến cục bộ bình thường. Chúng bị
huỷ đi khi ra khỏi hàm. Cần chú ý là các tham số hình thức đã khai báo có cùng
kiểu dữ liệu với các đối số được sử dụng khi gọi hàm. Trong trường hợp có sai,
C có thể không hiển thị lỗi nhưng có thể đưa ra một kết quả không mong muốn. Điều
này là vì, C vẫn đưa ra một vài kết quả trong các tình huống khác thường. Người
lập trình phải đảm bảo rằng không có các lỗi về sai kiểu.
Cũng giống
như với các biến cục bộ, các phép gán cũng có thể được thực hiên với tham số
hình thức của hàm và chúng cũng có thể được sử dụng bất kỳ biểu thức nào mà C
cho phép.
Các
qui luật về phạm vi của một hàm
Qui luật
về phạm vi là những qui luật quyết định một đoạn mã lệnh có thể truy xuất đến một
đoạn mã lệnh khác hoặc dữ liệu hay không. Trong C, mỗi hàm của chương trình là
các khối lệnh riêng lẻ. Mã lệnh bên trong một hàm là cục bộ với hàm đó và không
thể được truy xuất bởi bất kỳ lệnh nào ở ngoài hàm, ngoại trừ lời gọi hàm. Mã lệnh
bên trong một hàm là ẩn đối với phần còn lại của chương trình, và trừ khi nó sử
dụng biến hoặc dữ liệu toàn cục, nó có thể tác động hoặc bị tác động bởi các phần
khác của chương trình. Để rõ hơn, mã lệnh và dữ liệu được định nghĩa bên trong
một hàm không thể tương tác với mã lệnh hay dữ liệu được định nghĩa trong hàm
khác bởi vì hai hàm có phạm vi khác nhau.
Trong
C, tất cả các hàm có cùng mức phạm vi. Nghĩa là, một hàm không thể được định
nghĩa bên trong một hàm khác. Chính vì lý do này mà C không phải là một ngôn ngữ
cấu trúc khối về mặt kỹ thuật.
Gọi
hàm
Một
cách tổng quát, các hàm giao tiếp với nhau bằng cách truyền tham số. Các tham số
được truyền theo một trong hai cách sau:
Truyền
bằng giá trị
Truyền
bằng tham chiếu.
Đăng nhận xét