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

8 comments:

  1. " Vậy làm thế nào để đảo giá trị của chúng? Câu trả lời là Pass by reference(tham trị).
    Tác dụng của pass by reference là gì?"

    tham tri => tham chieu.
    hinh nhu hoi nham cho nay .

    ReplyDelete
  2. ok, đã sửa, thế là cũng có đứa đọc bài mình viết :))

    ReplyDelete
  3. Các tham số của hàm được tạo ra khi gọi hàm và nhận vào các giá trị từ bên ngoài, nó sẽ mất đi khi kết thúc hàm. Việc truyền một địa chỉ vào hàm mục đích là thao tác trực tiếp với ô nhớ có địa chỉ chứa trong con trỏ.
    VD *a là một tham số thì lệnh a = xxx sẽ không có tác dụng khi ra khỏi hàm.
    Thêm nữa khi khai báo tham số cho hàm là : const data_type *a sẽ không cho phép thay đổi nội dung ô nhớ mà a trỏ đến (bảo vệ dữ liệu) và khai báo data_type const *a sẽ không cho phép thay đổi nội dung của con trỏ a (bảo vệ con trỏ tránh những tác động không mong muốn).

    ReplyDelete
  4. ứng dụng của PBR đó là khi viết chương trình lớn (project) với nhiều chức năng , mà số biến lại không đổi với mỗi lần thực hiện chức năng , thì khi đó PBR tỏ ra rất hiệu quả
    VD :
    nhập vào các hệ số để biện luận nghiệm của phương trình bậc 2
    nhưng cùng lúc đó , muốn nhập vào 1 hệ số khác để có 1 kết quả khác mà không phải cấp thêm biến số thì phải dùng PBR tác động vào giá trị của biến trước đó .

    ReplyDelete
  5. Pass by Reference là khái niệm của C++
    C ko có PBR. Như cái ở trên hình như là Pass by Pointer.
    Hồi trước đọc trên congdongcviet nhớ có ông bảo thế

    ReplyDelete
  6. vừa đọc lại C programming language của Ritchie, đúng là ko có PBR,
    Trong sách có đoạn:
    "The way to obtain the desired effect is for the calling program to pass pointers to the values to be changed"
    Thế nên gọi là PBP chắc là hợp lí :D

    ReplyDelete
  7. trc đây cũng từng nghe nói "bảo vệ con trỏ" nay mới nhìn thấy là ko có gì đặc biệt ngoài việt dùng type-qualifier "const" . (A const object may be initialized, but not thereafter assigned to. The purpose of const is to announce objects that may be placed in read-only memory, and perhaps to increase opportunites for optimization).
    Đi một ngày đàng, học một nhà hàng khôn :))

    ReplyDelete
  8. hôm nay cái này mới phát huy tác dụng

    ReplyDelete