Wednesday, 1 June 2011

Tham chiếu, tham trị và hàm

Note: các thuật ngữ nào đc chú thích bằng tiếng Anh bên cạnh thì sau đó sẽ đc thay thế bằng tiếng Anh, lý do thói quen!)

Tham chiếu ( Pass by Reference ) & Tham trị (pass by value) là 2 thuật ngữ dùng trong lập trình (đặc biệt là C)
Tham chiếu là gán cho hàm tham số (argument) là 1 địa chỉ.
Tham trị là gán cho hàm tham số là 1 giá trị.



VD:
Ví dụ điển hình rất nổi tiếng là hàm swap (đổi giá trị của 2 số)

Nếu pass by value:

#include

void swap(int a, int b)
{
int c;
c = a;
a = b;
b = c;
return;
}

int main()
{
int x = 5, y = 7;
swap(x,y);
printf("x: %d, y : %d\n",x,y);
return 1;
}

kết quả sẽ là : x: 5, y: 7

Vậy hàm của mình đã viết là không có tác dụng! Vì sao?

Lý do bởi khi x và y được gán làm tham số của swap ( pass by value), hàm swap sẽ copy 2 giá trị của x và y rồi thực hiện các dòng lệnh với 2 "biến" copy đó. Để dễ hiểu, tưởng tượng là hàm swap tạo ra biến x1 chứa giá trị của x, biến y1 chứa giá trị của y. Sau đó tạo biến c copy giá trị của x1, gán y1 cho x1, gán c cho y1. Kết thúc hàm, biến c, x1,y1(tưởng tượng) sẽ bị hủy lập tức. Bởi thế không có gì tác động làm thay đổi gía trị của x và y cả.

Vậy làm thế nào để đảo giá trị của chúng? Câu trả lời là Pass by reference(tham chiếu).
Tác dụng của pass by reference là gì?
- Mang kết quả ra khỏi hàm.
Bình thường, 1 hàm trong C có thể trả về tối đa 1 giá trị hoặc không giá trị nào (hàm kiểu void). Bằng cách pass by reference, ta sẽ có thể nhận được bao nhiêu giá trị trả về tùy ý.

Trong ví dụ swap này, ta cần trả về 2 giá trị của x và y. Có nhiều cách để thực hiện điều này (không chỉ mỗi pass by reference), nhưng ở đây ta sẽ dùng PBR.

Thay vì tham số cho hàm swap là 2 giá trị của x, và y. Ta gán cho nó địa chỉ của 2 biến đầu vào. Ta viết lại hàm swap, lấy tên là swapRef.

#include
void swapRef(int *a, int * b)
{
int c;
c = *a;
*a = *b;
*b = c;
return;
}

int main() {
int x = 5, y = 7;
swapRef(&x,&y);
printf("SwapRef: x: %d, y: %d\n",x,y);
return 1;
}

kết quả trả về là x = 7, y = 5 .

Giải thich thêm một chút, &x là địa chỉ của biến x, &y là địa chỉ của biến y.
*a là giá trị mà địa chỉ con trỏ a trỏ đến. khi chương trình chạy, a là &x, *a = *&x = x.


Vậy mỗi khi thay đổi giá trị của 1 biến, ta đưa con trỏ tới biến đó vào đầu vào của hàm, và nhận về giá trị đã thay đổi khi hàm chạy xong.

PS: các bạn test và comment xem có lỗi gì không.

Written by FamiHug on 01/06/2011