Bài 10.3: Bài tập thực hành hàm trả về trong C++

Bài 10.3: Bài tập thực hành hàm trả về trong C++
Chào mừng các bạn quay trở lại với series học lập trình C++ của FullhouseDev! Ở các bài trước, chúng ta đã làm quen với khái niệm cơ bản về hàm, cách khai báo, định nghĩa và sử dụng các hàm void
- những hàm thực hiện một tác vụ nào đó nhưng không trả lại một giá trị cụ thể cho nơi gọi nó.
Hôm nay, chúng ta sẽ tiến thêm một bước quan trọng: tìm hiểu về hàm trả về giá trị (functions returning values). Đây là một bước đột phá giúp các hàm của chúng ta trở nên mạnh mẽ và linh hoạt hơn rất nhiều. Thay vì chỉ thực hiện hành động, hàm trả về cho phép chúng ta tính toán, xử lý dữ liệu và gửi kết quả đó ngược lại cho phần còn lại của chương trình sử dụng.
Hãy cùng đi sâu vào cách chúng hoạt động và thực hành qua các ví dụ nhé!
Hàm Trả Về Giá Trị Hoạt Động Như Thế Nào?
Khác với hàm void
, hàm trả về giá trị được khai báo với một kiểu dữ liệu trả về cụ thể (ví dụ: int
, double
, bool
, string
,...). Kiểu dữ liệu này quy định loại giá trị mà hàm sẽ gửi trả lại sau khi hoàn thành công việc của mình.
Cú pháp cơ bản khi định nghĩa một hàm trả về:
kieu_du_lieu_tra_ve ten_ham(tham_so_1, tham_so_2, ...) {
// Các câu lệnh xử lý logic của hàm
// ...
// Câu lệnh return để trả về giá trị
return gia_tri_can_tra_ve;
}
Điểm mấu chốt ở đây là câu lệnh return
. Khi chương trình gặp câu lệnh return gia_tri;
bên trong hàm, nó sẽ thực hiện các việc sau:
- Tính toán hoặc xác định
gia_tri_can_tra_ve
. - Dừng ngay lập tức việc thực thi các câu lệnh còn lại trong hàm đó.
- Gửi
gia_tri_can_tra_ve
này trở lại cho nơi đã gọi hàm. Kiểu dữ liệu củagia_tri_can_tra_ve
phải tương thích vớikieu_du_lieu_tra_ve
đã khai báo cho hàm.
Nơi gọi hàm có thể lưu trữ giá trị trả về này vào một biến, hoặc sử dụng nó trực tiếp trong một biểu thức hoặc câu lệnh khác.
Hãy bắt đầu với một ví dụ đơn giản nhất: một hàm tính tổng hai số nguyên.
Ví Dụ 1: Hàm Tính Tổng Hai Số Nguyên
Chúng ta muốn một hàm nhận hai số nguyên a
và b
, sau đó trả về kết quả của a + b
.
#include <iostream> // Cho cout, endl
// Khai báo và định nghĩa hàm add
// Hàm này nhận hai số nguyên (int a, int b)
// và trả về một số nguyên (int)
int add(int a, int b) {
// Tính tổng a + b và trả về kết quả đó
return a + b;
}
int main() {
int number1 = 10;
int number2 = 20;
// Gọi hàm add. Giá trị 30 được hàm add trả về
// và được lưu trữ vào biến result.
int result = add(number1, number2);
// In kết quả ra màn hình
cout << "Tong cua " << number1 << " va " << number2 << " la: " << result << endl;
// Chúng ta cũng có thể sử dụng giá trị trả về trực tiếp
cout << "Tong cua 5 va 7 la: " << add(5, 7) << endl;
return 0;
}
Giải thích code:
- Dòng
int add(int a, int b)
: Khai báo một hàm tên làadd
. Nó nhận hai tham số kiểuint
làa
vàb
. Quan trọng nhất,int
đứng trước tên hàmadd
cho biết hàm này sẽ trả về một giá trị có kiểuint
. - Dòng
return a + b;
: Đây là câu lệnhreturn
. Nó tính tổng củaa
vàb
, sau đó gửi kết quả này trở lại nơi hàmadd
được gọi. - Dòng
int result = add(number1, number2);
trongmain
: Khiadd(number1, number2)
được gọi, hàmadd
thực thi, tính10 + 20 = 30
. Giá trị30
này được trả về và gán vào biếnresult
kiểuint
trong hàmmain
. - Dòng
cout << add(5, 7) << endl;
: Minh họa việc sử dụng trực tiếp giá trị trả về của hàmadd
mà không cần lưu vào biến trung gian.
Ví dụ này cho thấy sự trao đổi thông tin hiệu quả giữa hàm add
và hàm main
thông qua giá trị trả về. Hàm add
làm công việc tính toán, và main
nhận kết quả để sử dụng tiếp.
Ví Dụ 2: Tính Diện Tích Hình Tròn
Hãy viết một hàm nhận bán kính hình tròn (kiểu double
) và trả về diện tích của nó (kiểu double
).
#include <iostream> // Cho cout, endl
#include <cmath> // Cho M_PI (hoặc bạn có thể tự định nghĩa PI)
// Khai báo và định nghĩa hàm calculateArea
// Nhận bán kính (double radius)
// Trả về diện tích (double)
double calculateArea(double radius) {
// Kiểm tra bán kính không âm (optional nhưng là good practice)
if (radius < 0) {
cerr << "Loi: Ban kinh khong the am!" << endl;
// Trả về một giá trị đặc biệt để báo hiệu lỗi, ví dụ -1.0
return -1.0;
}
// Sử dụng hằng số PI từ cmath
const double PI = M_PI;
// Tính diện tích và trả về
return PI * radius * radius;
}
int main() {
double r1 = 5.0;
double r2 = 10.0;
double r3 = -2.0; // Ví dụ bán kính âm
// Tính và in diện tích cho r1
double area1 = calculateArea(r1);
// Kiểm tra giá trị trả về để xem có lỗi không
if (area1 >= 0) {
cout << "Dien tich hinh tron ban kinh " << r1 << " la: " << area1 << endl;
}
// Tính và in diện tích cho r2
cout << "Dien tich hinh tron ban kinh " << r2 << " la: " << calculateArea(r2) << endl;
// Tính diện tích cho r3 - sẽ gặp lỗi
double area3 = calculateArea(r3); // Hàm sẽ in thông báo lỗi và trả về -1.0
if (area3 < 0) {
cout << "Khong the tinh dien tich voi ban kinh am." << endl;
}
return 0;
}
Giải thích code:
- Dòng
double calculateArea(double radius)
: Hàm này nhận một tham sốradius
kiểudouble
và được khai báo sẽ trả về một giá trị kiểudouble
(diện tích). - Câu lệnh
return PI * radius * radius;
: Tính toán diện tích và gửi kết quả về. - Phần kiểm tra
if (radius < 0)
: Đây là một ví dụ về cách xử lý các trường hợp ngoại lệ. Nếu bán kính âm, chúng ta thông báo lỗi và trả về một giá trị đặc biệt (-1.0
) để báo hiệu cho nơi gọi biết rằng có vấn đề xảy ra, thay vì trả về một kết quả tính toán sai. - Trong
main
, chúng ta gọicalculateArea(r1)
và lưu kết quả vàoarea1
. Sau đó, chúng ta kiểm tra giá trị củaarea1
trước khi in ra, minh họa cách xử lý giá trị trả về, kể cả các giá trị báo lỗi.
Ví Dụ 3: Kiểm Tra Số Chẵn/Lẻ (Sử Dụng bool
)
Hàm trả về kiểu bool
rất phổ biến khi chúng ta muốn kiểm tra một điều kiện nào đó và nhận kết quả là true
hoặc false
.
#include <iostream> // Cho cout, endl, boolalpha
// Khai báo và định nghĩa hàm isEven
// Nhận một số nguyên (int number)
// Trả về true nếu số đó là chẵn, false nếu là lẻ (bool)
bool isEven(int number) {
// Số chẵn là số chia hết cho 2
return number % 2 == 0;
}
int main() {
int num1 = 14;
int num2 = 7;
// Gọi hàm isEven và sử dụng giá trị trả về trong câu lệnh if
if (isEven(num1)) {
cout << num1 << " la so chan." << endl;
} else {
cout << num1 << " khong la so chan." << endl;
}
// Gọi hàm isEven và sử dụng giá trị trả về trong câu lệnh if khác
if (isEven(num2)) {
cout << num2 << " la so chan." << endl;
} else {
cout << num2 << " khong la so chan." << endl;
}
// Có thể in trực tiếp giá trị bool trả về
// boolalpha giúp in ra "true" hoặc "false" thay vì 1 hoặc 0
cout << boolalpha; // Bật chế độ in bool dạng chữ
cout << "So 10 co phai so chan? " << isEven(10) << endl;
cout << "So 9 co phai so chan? " << isEven(9) << endl;
return 0;
}
Giải thích code:
- Dòng
bool isEven(int number)
: HàmisEven
nhận mộtint
và được khai báo trả về mộtbool
. - Dòng
return number % 2 == 0;
: Biểu thứcnumber % 2 == 0
cho kết quả làtrue
nếunumber
chia hết cho 2, vàfalse
nếu không. Giá trịtrue
hoặcfalse
này được trả về bởi hàm. - Trong
main
, giá trịbool
trả về từisEven
được sử dụng trực tiếp trong điều kiện của câu lệnhif
. NếuisEven(num1)
trả vềtrue
, khối lệnh củaif
được thực thi. Nếu trả vềfalse
, khối lệnh củaelse
được thực thi. boolalpha
là một "manipulator" (bộ điều khiển) củacout
giúp chúng ta hiển thị giá trịbool
dưới dạng từ khóatrue
hoặcfalse
thay vì số1
hoặc0
.
Ví Dụ 4: Tìm Số Lớn Nhất (Sử Dụng max
)
Một hàm trả về cũng có thể trả về một trong các giá trị đầu vào sau khi xử lý logic.
#include <iostream> // Cho cout, endl
#include <algorithm> // Cho max
// Khai báo và định nghĩa hàm getMax
// Nhận hai số nguyên (int a, int b)
// Trả về số nguyên lớn hơn (int)
int getMax(int a, int b) {
// Sử dụng hàm max từ thư viện <algorithm>
// Hàm max(a, b) sẽ trả về a nếu a >= b, ngược lại trả về b
return max(a, b);
// Hoặc tự viết logic so sánh:
// if (a > b) {
// return a;
// } else {
// return b;
// }
}
int main() {
int x = 100;
int y = 200;
// Gọi hàm getMax và lưu kết quả
int maximum = getMax(x, y);
cout << "So lon nhat giua " << x << " va " << y << " la: " << maximum << endl;
cout << "So lon nhat giua 50 va 30 la: " << getMax(50, 30) << endl;
return 0;
}
Giải thích code:
- Dòng
int getMax(int a, int b)
: Hàm này nhận haiint
và trả vềint
(số lớn hơn). - Dòng
return max(a, b);
: Đây là cách dùng hàm có sẵnmax
để tìm giá trị lớn nhất giữa hai số.max
cũng là một hàm trả về giá trị. Nó tính toán và trả về số lớn hơn giữaa
vàb
. - Trong
main
, giá trị trả về từgetMax
được gán vào biếnmaximum
hoặc sử dụng trực tiếp.
Ví Dụ 5: Hàm Trả Về Chuỗi (string
)
Hàm cũng có thể trả về các kiểu dữ liệu phức tạp hơn như chuỗi ký tự (string
).
#include <iostream> // Cho cout, endl
#include <string> // Cho string
// Khai báo và định nghĩa hàm createGreeting
// Nhận một tên (string name)
// Trả về một chuỗi chào mừng (string)
string createGreeting(const string& name) { // Sử dụng const reference cho hiệu quả
// Tạo chuỗi chào mừng và trả về
return "Xin chao, " + name + "!";
}
int main() {
string user_name = "Doc gia C++";
// Gọi hàm createGreeting và lưu chuỗi trả về
string greeting_message = createGreeting(user_name);
cout << greeting_message << endl;
// Gọi hàm và in trực tiếp chuỗi trả về
cout << createGreeting("FullhouseDev") << endl;
return 0;
}
Giải thích code:
- Dòng
string createGreeting(const string& name)
: Hàm này nhận mộtstring
và được khai báo sẽ trả về mộtstring
. Việc sử dụngconst string&
cho tham số là một kỹ thuật tối ưu hiệu năng khi truyền chuỗi lớn, chúng ta sẽ tìm hiểu kỹ hơn sau, tạm thời hiểu nó vẫn nhận vào một chuỗi. - Dòng
return "Xin chao, " + name + "!";
: Nối chuỗi "Xin chao, " với giá trị của tham sốname
và chuỗi "!" rồi trả về kết quả là mộtstring
mới. - Trong
main
, chuỗi trả về được gán vào biếngreeting_message
hoặc in trực tiếp.
Ví Dụ 6: Kết Hợp Nhiều Hàm Trả Về
Sức mạnh thực sự của hàm trả về nằm ở khả năng xâu chuỗi các thao tác xử lý. Kết quả trả về của một hàm có thể trở thành đầu vào cho hàm khác.
#include <iostream> // Cho cout, endl
// Hàm nhân đôi giá trị
int multiplyByTwo(int num) {
cout << "* Buoc 1: Nhan " << num << " voi 2..." << endl;
return num * 2;
}
// Hàm cộng thêm 5
int addFive(int num) {
cout << "* Buoc 2: Cong " << num << " voi 5..." << endl;
return num + 5;
}
int main() {
int start_value = 10;
// Gọi hàm multiplyByTwo, nhận kết quả (20)
int step1_result = multiplyByTwo(start_value); // step1_result = 20
// Gọi hàm addFive với kết quả từ bước 1 (20), nhận kết quả (25)
int final_result = addFive(step1_result); // final_result = 25
cout << "Gia tri ban dau: " << start_value << endl;
cout << "Ket qua cuoi cung: " << final_result << endl;
cout << "\n--- Goi truc tiep ---" << endl;
// Hoặc gọi lồng nhau: addFive(multiplyByTwo(start_value))
// multiplyByTwo(10) trả về 20
// addFive(20) trả về 25
cout << "Ket qua khi goi truc tiep: " << addFive(multiplyByTwo(start_value)) << endl;
return 0;
}
Giải thích code:
- Chúng ta có hai hàm đơn giản,
multiplyByTwo
vàaddFive
, cả hai đều nhận mộtint
và trả về mộtint
. - Trong
main
,multiplyByTwo(start_value)
được gọi đầu tiên. Nó thực hiện công việc của mình (nhân 10 với 2) và trả về20
. Giá trị20
này được lưu vào biếnstep1_result
. - Tiếp theo,
addFive(step1_result)
được gọi. Lưu ý rằngstep1_result
chính là giá trị20
được trả về từ hàm trước. HàmaddFive
nhận20
, thực hiện công việc của mình (cộng 5), và trả về25
. Giá trị25
này được lưu vàofinal_result
. - Việc gọi lồng nhau
addFive(multiplyByTwo(start_value))
minh họa rõ ràng hơn cách giá trị trả về của hàm bên trong (multiplyByTwo
) trở thành tham số đầu vào cho hàm bên ngoài (addFive
).
Cách tiếp cận này cho phép chúng ta xây dựng các chương trình phức tạp bằng cách kết hợp các hàm nhỏ, chuyên biệt. Mỗi hàm thực hiện một nhiệm vụ cụ thể và trả về kết quả, kết quả đó lại được sử dụng làm đầu vào cho nhiệm vụ tiếp theo.
- Để tạo hàm trả về, hãy khai báo nó với một kiểu dữ liệu trả về (khác
void
). - Sử dụng câu lệnh
return
để gửi giá trị từ hàm về nơi gọi. - Giá trị trả về phải tương thích với kiểu dữ liệu trả về đã khai báo.
- Nơi gọi hàm có thể lưu trữ giá trị trả về vào một biến hoặc sử dụng trực tiếp.
- Hàm trả về cho phép xâu chuỗi các phép tính và làm cho code của chúng ta ngăn nắp, dễ đọc và dễ bảo trì hơn.
Comments