Khái niệm
Truyền tham trị (Call by Value / Pass by Value): Hàm nhận bản sao (copy) của giá trị đối số. Thay đổi tham số trong hàm KHÔNG ảnh hưởng đến biến gốc.
Minh họa: Hoán đổi 2 số (KHÔNG thành công)
#include <stdio.h>
void hoanDoi(int a, int b) {
int tam = a;
a = b;
b = tam;
printf("Trong ham: a=%d, b=%d\n", a, b);
}
int main() {
int x = 10, y = 20;
printf("Truoc goi ham: x=%d, y=%d\n", x, y);
hoanDoi(x, y); // Truyền giá trị
printf("Sau goi ham: x=%d, y=%d\n", x, y);
return 0;
}
Kết quả
Truoc goi ham: x=10, y=20
Trong ham: a=20, b=10
Sau goi ham: x=10, y=20 // KHÔNG thay đổi!
Sơ đồ bộ nhớ
main(): hoanDoi():
┌─────────┐ ┌─────────┐
│ x = 10 │ │ a = 10 │ ← Bản sao của x
├─────────┤ ├─────────┤
│ y = 20 │ │ b = 20 │ ← Bản sao của y
└─────────┘ └─────────┘
Địa chỉ khác nhau hoàn toàn
Đặc điểm Call by Value
| Đặc điểm | Mô tả |
|---|---|
| An toàn dữ liệu | Biến gốc không bị thay đổi |
| Bộ nhớ | Cấp phát bản sao (tốn thêm stack) |
| Hiệu năng | Chậm với struct/mảng lớn (copy tốn thời gian) |
| Mặc định C | Mọi kiểu dữ liệu cơ bản đều pass by value |
| Mảng | Truyền địa chỉ phần tử đầu (pass by reference thực chất) |
Khi nào dùng Call by Value?
- Dữ liệu nhỏ (int, float, char, struct nhỏ)
- Không muốn hàm thay đổi biến gốc (bảo vệ dữ liệu)
- Hàm chỉ đọc, không ghi (read-only)
Ví dụ thực tế: Tính toán không làm thay đổi đầu vào
#include <stdio.h>
#include <math.h>
// Tính chu vi, diện tích hình tròn - KHÔNG thay đổi r
void tinhHinhTron(float r, float *chuVi, float *dienTich) {
*chuVi = 2 * M_PI * r;
*dienTich = M_PI * r * r;
// r không bị thay đổi
}
int main() {
float r = 5.0, cv, dt;
tinhHinhTron(r, &cv, &dt); // r truyền by value, cv/dt truyền by reference
printf("Ban kinh: %.2f\n", r);
printf("Chu vi: %.2f\n", cv);
printf("Dien tich: %.2f\n", dt);
return 0;
}
So sánh: Call by Value vs Call by Reference
| Tiêu chí | Call by Value | Call by Reference (qua con trỏ) |
|---|---|---|
| Cú pháp gọi | func(x) | func(&x) |
| Tham số hàm | void func(int x) | void func(int *x) |
| Truy cập trong hàm | x | *x |
| Ảnh hưởng biến gốc | Không | Có |
| Dùng cho | Đọc, tính toán nhỏ | Ghi, struct lớn, mảng, trả nhiều giá trị |
Mẹo: Trả về nhiều giá trị với Call by Value
C chỉ return 1 giá trị. Dùng struct để gom nhiều giá trị:
struct KetQua {
int tong;
int hieu;
int tich;
float thuong;
};
struct KetQua tinhToan(int a, int b) {
struct KetQua kq;
kq.tong = a + b;
kq.hieu = a - b;
kq.tich = a * b;
kq.thuong = (float)a / b;
return kq; // Trả về struct (copy)
}
Hiểu rõ Call by Value giúp tránh bug "hàm không thay đổi được biến" - một lỗi cực phổ biến của người mới học C.