You are on page 1of 26

Nội dung 9

Hàm (function)

TS. Trần Thanh Hải


1. Định nghĩa
• Mục đích: Các hàm cho phép chương trình cấu trúc thành từng
đoạn mã (code) để thực hiện các nhiệm vụ riêng lẻ.
• Định nghĩa: Hàm là một khối các câu lệnh được xác định bởi
một
ột tên,
tê vàà cóó thể được
đượ gọii từ một ột số
ố vịị trí
t í của
ủ chương
hươ trình.
tì h
• Cú pháp :
type
yp name ( p parameter1,, p parameter2,, ...)) { statements }
type: là kiểu của giá trị trả về bởi hàm (chỉ có 1 giá trị) .
name: tên hàm, bằng cách này hàm có thể được gọi.
• Ví dụ: int tongAb (int a, int b)
parameters (tùy ý): mỗi tham số gồm (một kiểu theo sau là một
tên)) ((định
ị danh)) ((int x),
), mỗi tham số được ợ cách nhau một ộ dấu
phảy, trong phạm vi hàm các biến là cục bộ. Mục đích của các
tham số: là cho phép truyền các đối tới hàm từ vị trí gọi hàm.
statements: Là thân của hàm,
hàm nó là một khối các câu lệnh bao bọc
bởi { } hình thành những gì hàm thực hiện.
1. Định nghĩa
• Một chương trình C++ luôn bắt đầu gọi hàm main. Hàm main
là hàm duy nhất được gọi tự động, và mã trong bất kỳ hàm
khác chỉ được thực thi nếu hàm đó được gọi từ hàm main().
• Ví dụ: Tính tổng của hai số
int addition (int a, int b) {
int r;
r = a + b;
return r; }
int main () {
i t z;
int
z = addition (5,3); // goi hàm tinh tổng
cout << "The
The result is " << z;
}
Định nghĩa
• Tham số hình thức: (formal parameters)
• int addition (int a, int b): a, b là hai tham số hình thức, biến cụ bộ
(biế tự
(biến t động),
độ ) có ó giáiá trị
t ị trong
t phạm
h vii thân
thâ hàm
hà vàà tự
t hủy
hủ sau
khi thoát ra khỏi hàm mà không cần phải dùng (new – delete).
• Tham số thực ự ‐ đối ((arguments
g – actual pparameters):
) khi hàm
được gọi, sẽ cung cấp tham số thực để sử dụng tính toán (a = 5,
b =3)
• Ví dụ:
d
int main () {
int z,
z a = 5,
5 b = 3;
z = addion (a, b); // tham số thực a = 5, b = 3.
cout << "The result is " << z;;
}
2. Phân tích
• Gọi
G i hàm
hà theo
h cấu
ấ trúc
ú tương tự như
h khai
kh i báo
bá của
ủ nó.
ó

• Tại
ạ thời điểm hàm được ợ gọgọi trongg main,, điều khiển được ợ
chuyển cho hàm addition, khi đó chạy hàm main bị dừng lại và
chỉ tiếp tục khi hàm addition kết thúc.
• Tại
T i lúc
lú hàm
hà được
đ gọi,i giá
iá trịị của
ủ cảả hai
h i đối (5 vàà 3) được
đ sao
chép tới biến cục bộ int a và int b trong hàm addtion.
• Biến cục bộ khác được khai báo (int r). Trong trường hợp này
a là 5, b là 3 và kết quả là 8 được gán cho r.
• Câu lệnh cuối cùng trong hàm : return r;
2. Phân tích

• Cuối của hàm addition, và trả điều khiển trở lại nơi mà hàm
được gọi, trong trường hợp này là hàm main(). Đúng lúc này,
chương
h t ì h tiếp
trình tiế tục
t trở
t ở lại
l i tiến
tiế trình
t ì h trong
t main
i chính
hí h xác á tạit i
thời điểm nó bị ngắt để gọi hàm addition.
• Giá trịị của biến địa
ị p
phươngg r,, tại
ạ thời điểm trả về có ggiá trịị là 8

• Sau đó hàm main đơn gian chỉ là in giá trị bằng cách gọi
cout << "The result is " << z;
• Một hàm có thể được gọi nhiều lần trong chương trình.
• Xem phân tích: sử dụng chạy từng bước trong Debug.
Debug
3. Hàm void

• Nếu hàm không cần trả về giá trị. Trường hợp này, kiểu(type)
được sử dụng là void,
void để thể hiện sự vắng mặt của giá trị trả về.
về
• Cú pháp :
type name ( argument1, argument2 ...) { statements }
• Ví dụ: hàm in thông báo – kết quả
void in_thong_bao (){
cout << “Day la mot ham!";
}
i t main
int i (){
in_thong_bao (); // không được bỏ dấu ().
}
4. Đối được truyền bằng giá trị hoặc tham chiếu

• Trong các hàm trước đó, các đối số luôn luôn được truyền
bằng giá trị. Nghĩa là, khi gọi một hàm, những gì được truyền
vào hàm là các giá trị củaủ các đối
ố sốố này vào thời điểm
ể gọi,
được sao chép vào các biến thể hiện bởi các tham số hàm.
• Ví dụ: int x = 5,
5 y = 3,
3 z;
z = addition ( x, y );

• Hàm addition được truyền 5 và 3, là các bản sao của các biến
x và y tương ứng.
• Bất
ấ kỳ sự thay
h đổi
đổ các
á biến
b ế trong hàm
hà không
khô làm
là ảnh
ả h hưởng
h ở
đến các biến x và y bên ngoài hàm addition.
• Vì x, y không truyền chính nó cho hàm trong khi gọi, mà chỉ là
bản sao của chúng tại thời điểm hiện tại.
4. Đối được truyền bằng giá trị hoặc tham chiếu
• Trường hợp,
hợp có thể sử dụng để truy cập một biến bên ngoài từ
bên trong một hàm. (mô đun nhập số liệu nhap_ab)
• Để làm điều đó, đối có thể được truyền tham chiếu (reference)
– địa chỉ) thay bằng giá trị.
• Để truy cập các đối số của nó, hàm khai báo các tham số của nó
như các tham chiếu.
chiếu Trong C + +,
+ tham chiếu ký hiệu (&) liền
sau kiểu tham số.

• Khi một biến được truyền bằng tham chiếu, biến được truyền
đi không còn là một bản
ả sao nữa.
• Bất kỳ sửa đổi nào trên các biến cục bộ tương ứng của chúng
trong hàm được tác động trở lại vào biến được truyền như các
đối số trong cuộc gọi.
5. Tham chiếu sử dụng const

• Xem xét ví dụ sau:


string cong_ab (string a, string b){
return a+b;
}
• Bằng cách truyền đối theo giá trị.
trị Hàm bắt buộc các biến a,
a b
là các bản sao các đối được truyền đến hàm khi gọi nó. Và nếu
các chuỗi kí tự này dài, có nghĩa là sao chép số lượng lớn dữ
liệu cho gọi hàm.
• Nhưng bản sao này có thể được tránh hoàn toàn nếu cả hai
tham số được làm bằng tham chiếu:
string cong_ab (string& a, string& b){
return a+b;;
}
5. Tham chiếu sử dụng const

• Hàm hoạt động trực tiếp trên (bí danh của) các chuỗi truyền
như là đối số.
• Phiên bản của cong_ab lấy tham chiếu hiệu quả hơn nhiều so
với phiên bản lấy giá trị, vì nó không cần phải sao chép “đắt
tiền” để sao chép chuỗi.
tiền chuỗi
• Mặt khác, hàm với các tham chiếu thường được coi là các
hàm sửa đổi các đối số được truyền.
• Giải pháp để đảm bảo rằng tham chiếu của nó sẽ không được
sửa đổi bởi hàm này, được thực hiện bằng cách áp đặt các
tham số như hằng số (const):
string cong_ab (const string& a, const string& b){
return a+b;;
}// truy cập trực tiếp các đối, ko bản sao, ko thay đổi
5 Tham chiếu sử dụng const
5.

• Vì vậy,
ậy, các tham chiếu const cungg cấpp các tính chất tươngg tựự
như truyền các đối số theo giá trị, nhưng với hiệu suất tăng
lên cho các tham số của các kiểu lớn. Đó là, lý do tại sao chúng
cực kỳ phổ biến trong C++ cho các đối số của các kiểu kết hợp.
hợp
• Lưu ý rằng, đối với hầu hết các kiểu cơ bản (int, float,
double,…), không có sự khác biệt đáng chú ý về hiệu suất, và
trong một số trường hợp, các tham chiếu const thậm chí có
thể kém hiệu quả hơn!
6. Con trỏ trỏ tới hàm ‐ Pointers to functions

• C++ cho phép thao tác với con trỏ tới hàm. Sử dụng của con
trỏ là để truyền một hàm như là một đối của hàm khác.
• Các con trỏ tới hàm được khai báo giống như khai báo hàm
thông thường, ngoại trừ tên của hàm là nằm trong ngoặc và
một dấu * được đặt trước tên: ((*function
function_name).
name)
• Khai báo thông thường biến con trỏ: type *var_name
• Vậy
ậy các đối thì viết thế nào?
• Khai báo hàm thông thường:
double ten_ham (int a, int b);
• Con trỏ hàm: double (*ten_ham)(int, int);

Chú ý sự khác nhau dùng ((* ).) Ép kiểu: fp = &x; ip = (int*)


(int ) &x; ip = (int*)
(int ) fp;
float x = 20.3; cout<<int(x); hoặc cout<<(int)x;
7. Con trỏ void ‐ void pointers
p

• Con trỏ kiểu void: là một


ộ kiểu con trỏ đặcặ biệt,
ệ , void biểu diễn
sự vắng mặt của kiểu. Do đó, con trỏ void là các con trỏ trỏ tới
một giá trị không có kiểu.
• Con
C trỏ t ỏ void
id có
ó một
ột sự mềm
ề dẻodẻ lớn,
lớ có ó thể trỏ
t ỏ tới bất kỳ kiểu
kiể
dữ liệu nào.
• Trongg sựự chuyển
y đổi,, chúngg có một
ộ ggiới hạn
ạ lớn: dữ liệu
ệ được ợ
trỏ bởi nó không thể sử dụng trực tiếp truy cập vào vùng nhớ,
vì lý do đó, bất kỳ địa chỉ trong con trỏ void, cần phải chuyển
thành một kiểu con trỏ khác xác định (ví dụ int, int char,
char float,
float
double…) trước khi truy cập vào vùng nhớ
• Ứng dụng: được sử dụng để truyền tham số chung (generic)
tới một hàm.
8. Gọi
ọ hàm bằngg cách thôngg thườngg ((tên hàm+đối))

int func1(int a); // khai bao nguyen mau


int main(){
int b = 10;
i t ipf;
int i f // biến
biế chứa
hứ tên
tê hàm

ipf = func1(b); // gọi hàm bằng tham số
cout<<“Gia
cout<< Gia tri cua ham ipf = "<<ipf<<endl;
<<ipf<<endl;
}
// Dinh nghia ham
int func1(int a) {
return a*2;
}
9. Gọi hàm bằng con trỏ hàm (2 cách)

int func1(int a); // khai bao nguyen mau


int main(){
int b = 10;
int (*ipf)(int); // khai bao con tro ham
ipf = func1; // ten ham – con trỏ ỏ (gợi nhớ lại : p = &f)
cout<<"Cach 1 goi Con tro ham ipf = "<<ipf(b*2)<<endl;
cout<<"Cach
cout<< Cach 2 goi Con tro ham ipf = "<<(*ipf)(b*2)<<endl;
<<(*ipf)(b*2)<<endl;
}
// định nghĩa hàm
int func1(int a) {
return a*2;
}
10. Gọi
ọ hàm bằngg con trỏ hàm đối với hàm void

void func4()() ;// khai bao nguyen


g y mau
int main() {
void (*vp)(); // khai bao con tro void
vp = func4;
(*vp)(); // tuong duong goi ham: func4();
}
// Định nghĩa hàm
void func4() {
cout<<"Hello "<<endl;
}
10. Gọi hàm với đối là con trỏ

C++ cho phép truyền con trỏ tới một hàm. Để làm điều này, khai
báo tham số như kiểu con trỏ.
#include<iostream>
void f(int *j);
int main() {
int i;
int *p;
p = &i; // p tro toi i
f(p); // f(&i);
cout<<"Gia
cout<< Gia tri cua i = "<<*p<<endl;
<< p<<endl;
}
void f(int *j){
*j = 100;
}
11. Gọi hàm với đối là mảng một chiều
• Có 3 cách
á h để khai
kh i báo
bá tham
th sốố để nhận
hậ mảng
ả con trỏ.
tỏ
1. Cách 1: Khai báo mảng giống kiểu và kích thước sử dụng để gọi
hàm.
• Ví dụ 1:
int main() {
int num[10];
for(int j=0;j<10;j++) num[j]=j;
display(num);
p y( );
}
void display(int num[10]) {
i i;i
int
for(i=0;i<10;i++) {
cout<<"num["<<i<<"]
cout num[ i ] = "<<num[i]<<endl;
num[i] endl;
}
}
12. Mảng 2 chiều

• Mảng float a[60][50];


• Vấn đề đặt ra là làm thế nào để sử dụng tên mảng hai chiều a
trong lời gọi hàm?
• Cách 1:
• Dùng con trỏ kiểu float[50], khai báo theo một trong hai mẫu
sau:
mẫu
ẫ 1: float
fl (* )[ ] dùng
(*pa)[50]; dù khai
kh i báo
bá con trỏỏ kiểu
kiể float[50]
fl [ ]
mẫu 2: float pa[][50]; dùng để khai báo đối
trong thân hàm để truy cập đến phần tử a[i][j] ta dùng pa[i][j].
pa[i][j]
• Chú ý: theo cách này hàm chỉ dùng được đối với các mảng hai
chiều có 50 cột (số hàng không quan trọng)
12. Mảng 2 chiều

• Cách 2:
• Dùng 2 đối:
float *pa; // biểu thị địa chỉ đầu của mảng a
int N; // biểu thị số cột của mảng a
• Trong thân hàm, để truy cập đến phần tử a[i][j] ta dùng công
thức
thức. *(pa+i*N+j)
• Chú ý: mảng hai chiều được qui về mảng một chiều, phức tạp
hơn cách 1,, nhưngg khôngg cố định
ị bao nhiêu cột,
ộ , nên có thể
dùng hàm cho bất kỳ mảng hai chiều nào.
13. Gọi hàm với đối là xâu ký tự (string)

• Xâu ký tự: là mảng ký tự kết thúc bằng null (\0) .


• Khi truyền xâu ký tự cho hàm, chỉ một con trỏ tới đầu của chuỗi
thực sự được truyền.
truyền
• Ví dụ: Chuyển xâu thường thành xâu hoa (hello → HELLO)
int main(){
char str[80] = "hello";
StringUpper(str); // loi goi giong nhu mang 1 chiều
}
void StringUpper(char *str) {
while(*str) {
* t = toupper(*str);
*str t (* t )
str = str + 1; // str++; chuyen to ky tu tiep
}
}
15. Đối có giá trị mặc định
• Trong C++ cho phép tạo giá trị mặc định cho các đối. Tức là các đối
này có thể có hoặc không có tham số tương ứng trong lời gọi hàm.
• Khi không có tham số tương ứng, đối được gán bởi giá trị mặc định.
• Cách 1: Không khai báo nguyên mẫu (hàm trước main())
#include<iostream>
int binh_phuong(int a = 10) { // Ví trí khai báo hàm có đối mặc định
int bp;
bp = a*a;
a a;
return bp;
}
int main(){
cout<<"Ket qua binh phuong : ";
cout<<binh phuong()<<endl; // Lời gọi hàm
cout<<binh_phuong()<<endl;
}
Hàm toán <cmath>
cmath

• sin(x),
( ), cos(x),
( ), tan(x),
( ), asin(x),
( ), acos(x),
( ), atan();
();
• atan2(y,x):
• sinh(x), cosh(x), tanh(x);
• pow(x,y), sqrt(x)
• ceil(x), floor(x);
• fabs(x),
( ) fmod(x,y)
( )
• exp(x), log(x), log10(x)
Function Description
abs(x) Returns the absolute value of x
acos(x) Returns the arccosine of x, in radians
asin(x) Returns the arcsine of x,
x in radians
atan(x) Returns the arctangent of x, in radians
cbrt(x) Returns the cube root of x
ceil(x) Returns the value of x rounded up to its nearest integer
cos(x) Returns the cosine of x,
x in radians
cosh(x) Returns the hyperbolic cosine of x, in radians
x
exp(x) Returns the value of E
x
expm1(x) Returns e ‐1
fabs(x) Returns the absolute value of a floating x
fdim(x, y) Returns the positive difference between x and y
Function Description
( )
floor(x) Returns the value of x rounded down to its nearest
integer
2 2
hypot(x, y) Returns sqrt(x +y ) without intermediate overflow
or underflow
d fl
fma(x, y, z) Returns x*y+z without losing precision
fmax(x y)
fmax(x, Returns the highest value of a floating x and y
fmin(x, y) Returns the lowest value of a floating x and y
fmod(x, y) Returns the floating point remainder of x/y
pow(x, y) Returns the value of x to the power of y
sin(x) Returns the sine of x (x is in radians)
sinh(x) Returns the hyperbolic sine of a double value
tan(x) Returns the tangent of an angle
tanh(x) Returns the hyperbolic tangent of a double value

You might also like