
Buổi 30: Hàm (Tiếp Theo) - Giá Trị Trả Về và Tham Chiếu¶
I. Lý Thuyết¶
Trong bài trước, ta học hàm void. Hàm void giống như một người nhân viên chỉ biết thực hiện hành động (lau nhà, dọn rác, in ra màn hình) chứ không báo cáo lại kết quả bằng văn bản.
Hôm nay, ta sẽ học cách tạo ra những "Cỗ máy tính toán" thực thụ: Nhận nguyên liệu đầu vào \(\to\) Tính toán \(\to\) Trả về kết quả (Return) cho hàm main() sử dụng tiếp.
1. Hàm Có Giá Trị Trả Về (return)¶
Thay vì dùng từ khóa void, ta sẽ dùng các kiểu dữ liệu (int, float, bool, string...) làm tên kiểu trả về của hàm.
Cỗ máy này bắt buộc phải ném ra một kết quả thông qua lệnh return.
#include <iostream>
using namespace std;
// Hàm nhận vào 2 số nguyên, TRẢ VỀ 1 số nguyên (int)
int tinhTong(int a, int b) {
int ketQua = a + b;
return ketQua; // Ném kết quả về cho nơi gọi hàm
}
int main() {
// Gọi hàm và hứng lấy kết quả
int x = tinhTong(5, 10);
cout << "Tong la: " << x; // In ra 15
// Thậm chí có thể dùng trực tiếp trong biểu thức tính toán khác
int y = tinhTong(10, 20) * 2;
return 0;
}
Sức mạnh tối thượng của lệnh return:
Khi gặp lệnh return, hàm sẽ NGAY LẬP TỨC DỪNG LẠI và thoát ra. Mọi dòng code nằm dưới lệnh return sẽ bị bỏ qua hoàn toàn. Đặc tính này rất hữu ích để viết các hàm kiểm tra điều kiện.
bool kiemTraSNT(int n) {
if (n < 2) return false; // Thoát ngay, không thèm chạy vòng lặp
for (int i = 2; i < n; i++) {
if (n % i == 0) return false; // Chỉ cần chia hết 1 số là kết luận luôn
}
return true; // Sống sót qua vòng lặp thì chắc chắn là SNT
}
2. Truyền Tham Chiếu (Pass by Reference &)¶
Nhắc lại bài trước: Hàm mặc định tạo ra Bản Sao của biến khi truyền vào (Pass by Value). Nếu ta viết hàm hoanVi(int a, int b) để đổi chỗ, thì nó chỉ đổi chỗ 2 bản sao, biến thật ở ngoài main không hề thay đổi.
Làm sao để cho phép hàm tác động trực tiếp vào vùng nhớ gốc?
\(\to\) Cung cấp Chìa khóa nhà (Địa chỉ RAM) bằng dấu VÀ (&).
// Thêm dấu & vào trước tên biến tham số
void hoanViThatSu(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 10, y = 20;
hoanViThatSu(x, y);
cout << "x = " << x << ", y = " << y; // Kết quả: x = 20, y = 10 (Đã bị đổi thật)
return 0;
}
Khi nào dùng Tham Chiếu &?
- Khi muốn hàm thay đổi vĩnh viễn biến gốc ở ngoài.
- Khi một hàm cần trả về NỀU KẾT QUẢ (Ví dụ giải phương trình cần trả về 2 nghiệm \(x_1, x_2\), nhưng hàm chỉ cho phép
return1 giá trị. Ta sẽ dùng tham chiếu để ném kết quả ra ngoài). - Khi truyền một cấu trúc dữ liệu khổng lồ (như Mảng) vào hàm, dùng tham chiếu sẽ tránh được việc máy tính tốn thời gian sao chép mảng.
(Lưu ý: Mảng 1 chiều trong C++ mặc định là được truyền tham chiếu một cách tự động, bạn không cần ghi dấu & cho mảng).
II. Bài Tập Thực Hành Tại Lớp¶
Bài 1: Hàm Tìm Số Lớn Nhất (Max 3 Số)¶
Đề bài: Viết một hàm int timMax(int a, int b, int c) trả về giá trị lớn nhất trong 3 số.
Trong main, nhập 3 số từ bàn phím, gọi hàm và in kết quả.
Gợi ý code
Bài 2: Hàm Hoán Vị (Tham Chiếu)¶
Đề bài: Viết hàm void hoanVi(float &a, float &b) để đổi chỗ 2 số thực. (Lưu ý phải có dấu &).
Trong main, nhập 2 số, in chúng ra, sau đó gọi hàm hoán vị, và in chúng ra lần nữa để chứng minh giá trị đã bị thay đổi.
Gợi ý code
III. Bài Tập Về Nhà¶
Bài 1: Hàm Kiểm Tra Chẵn Lẻ¶
Đề bài: Viết một hàm bool isEven(int n). Hàm sẽ trả về true nếu \(n\) là số chẵn, trả về false nếu \(n\) là số lẻ.
Viết hàm main, nhập \(N\). Sử dụng hàm isEven(N) trong biểu thức của lệnh if để in ra "La so chan" hoặc "La so le".
Bài 2: Giải Phương Trình Bậc 1 (Kết hợp return và &)¶
Đề bài: Phương trình bậc 1 có dạng \(Ax + B = 0\). Nếu \(A = 0\) và \(B = 0\): Vô số nghiệm. Nếu \(A = 0\) và \(B \neq 0\): Vô nghiệm. Nếu \(A \neq 0\): Có 1 nghiệm duy nhất \(x = -B / A\).
Viết một hàm bool giaiPT(float a, float b, float &x).
- Hàm trả về
falsenếu phương trình vô nghiệm hoặc vô số nghiệm. - Hàm trả về
truenếu phương trình có nghiệm, và ĐỒNG THỜI ném giá trị nghiệm đó vào biến tham chiếux. Trong hàmmain, dựa vào kết quảtrue/falsecủa hàm để in kết quả phù hợp.
Output mẫu
Bài 3: Hàm Tìm Ước Chung Lớn Nhất (UCLN)¶
Đề bài: Viết hàm int timUCLN(int a, int b). Hàm này sẽ tính và return về ước chung lớn nhất của 2 số. (Có thể dùng thuật toán trừ lặp nhau hoặc thuật toán Euclid chia lấy dư).
Trong main(), gọi hàm tính UCLN và in ra màn hình. Đồng thời áp dụng toán học để tính BCNN = (A * B) / UCLN.
Bài 4: Tái Sử Dụng Hàm Số Nguyên Tố¶
Đề bài:
- Copy lại hàm
bool kiemTraSNT(int n)từ phần lý thuyết ở trên. - Trong hàm
main(), nhập một mảng gồm \(K\) phần tử (\(K \le 100\)). - Viết vòng lặp duyệt mảng, với mỗi
a[i], hãy dùng hàmkiemTraSNT(a[i])để kiểm tra. Hãy đếm xem trong mảng có bao nhiêu số nguyên tố và in kết quả. (Bài này cho bạn thấy sức mạnh của Hàm. Nhờ có hàm, vòng lặp duyệt mảng của bạn cực kỳ ngắn gọn và sạch sẽ).
IV. Ghi Chú Quan Trọng¶
So Sánh Pass By Value và Pass By Reference¶
| Tiêu chí | Tham số trị (Truyền giá trị) | Tham chiếu (Kèm dấu &) |
|---|---|---|
| Cú pháp | void ham(int x) |
void ham(int &x) |
| Bản chất | Hàm tạo ra một Biến copy mới chiếm RAM. Cứ ném dữ liệu vào đó. | Hàm móc nối một Sợi dây trỏ trực tiếp về biến gốc. |
| Bảo mật | An toàn tuyệt đối 100% cho biến gốc. | Nguy hiểm nếu code ẩu (Vô tình làm biến đổi dữ liệu quan trọng). |
| Hiệu suất | Tốn thời gian Copy dữ liệu. (Rất chậm nếu biến là Mảng quá to hoặc File). | Siêu tốc độ (Bởi vì chỉ truyền cái địa chỉ sợi dây). |
V. Ôn Tập Trắc Nghiệm¶
Kiểm tra lý thuyết về Giá trị trả về và Tham chiếu: