Tài liệu

Bài 16: Sử dụng truyền tham chiếu, truyền tham trị và truyền con trỏ trong lập trình C

Huy Erick

Trong bài viết này, chúng ta sẽ tìm hiểu về cách sử dụng truyền tham chiếu, truyền tham trị và truyền con trỏ, cũng như cách truyền mảng vào hàm trong lập trình C. Truyền...

Trong bài viết này, chúng ta sẽ tìm hiểu về cách sử dụng truyền tham chiếu, truyền tham trị và truyền con trỏ, cũng như cách truyền mảng vào hàm trong lập trình C.

Truyền tham trị là gì?

Truyền tham trị là việc truyền một bản sao của giá trị biến vào tham số của hàm. Điều này có nghĩa là giá trị của biến sẽ được sao chép sang biến tham số trong hàm. Đây là cách chúng ta sử dụng hàm thông thường.

Nói một cách đơn giản, truyền tham trị là truyền giá trị.

Xem ví dụ:

#include 
void incValue(int x) {
    x++;
    printf("Biến trong hàm = %d \n", x);
}
int main() {
    int a = 10;
    incValue(a);
    printf("Biến ngoài hàm = %d \n", a);
    return 0;
}

Kết quả:

Biến trong hàm = 11
Biến ngoài hàm = 10

Khi chúng ta truyền biến a vào hàm incValue, trình biên dịch thực chất sẽ sao chép giá trị của a vào biến x (x = a). Sau đó, giá trị này được sử dụng để tính toán trong hàm. Vì vậy, khi chúng ta thay đổi giá trị của x, giá trị của a không thay đổi.

Một lỗi thường gặp khi sử dụng truyền tham trị là khai báo lại một lần nữa tham số truyền vào, ví dụ:

void changeValue(int x) {
    int x; // lỗi
    x = 2;
}

Truyền tham chiếu là gì?

Truyền tham chiếu là việc truyền một địa chỉ bản gốc thông qua toán tử &. Nghĩa là giá trị của biến tham số trong hàm sẽ là giá trị của biến được truyền vào.

Nói một cách đơn giản, truyền tham chiếu là truyền địa chỉ.

Xem ví dụ:

#include 
void incValue(int *x) {
    (*x)++;
    printf("Biến trong hàm = %d \n", *x);
}
int main() {
    int a = 10;
    incValue(&a);
    printf("Biến ngoài hàm = %d \n", a);
    return 0;
}

Kết quả:

Biến trong hàm = 11
Biến ngoài hàm = 11

Khi chúng ta truyền biến a vào *x, tức là ax sẽ chia sẻ cùng một địa chỉ. Mỗi khi thay đổi giá trị của a hoặc x, giá trị của biến kia cũng thay đổi theo. Điều này tương tự như việc có hai người thuê cùng một căn nhà. Bạn có thể truy cập thông qua tên của họ mà không cần địa chỉ.

Hàm scanf cũng sử dụng truyền tham chiếu, nghĩa là nó sao chép giá trị từ bàn phím vào địa chỉ của biến truyền vào.

Một rủi ro khi sử dụng đối số tham chiếu là dữ liệu có thể bị thay đổi không như mong muốn.

Ví dụ về truyền tham chiếu (pass by reference) và truyền tham trị (pass by value)

Truyền con trỏ

Truyền con trỏ tương tự như truyền tham chiếu, biến truyền vào sẽ thay đổi khi ta thay đổi giá trị con trỏ đó trỏ tới.

Xem ví dụ:

#include 
void changeValue(int *pointer) {
    *pointer = 20;
}
int main() {
    int a = 10;
    changeValue(&a);
    printf("Giá trị của a: %d\n", a);
    return 0;
}

Kết quả:

Giá trị của a: 20

Giải thích: Khi chúng ta truyền địa chỉ &a vào biến con trỏ *pointer, nghĩa là chúng ta gán địa chỉ của biến a cho pointer. Mỗi khi thay đổi giá trị con trỏ thông qua *pointer = 20, giá trị tại địa chỉ của a sẽ thay đổi, dẫn tới giá trị của a cũng thay đổi.

Truyền mảng vào hàm bằng con trỏ

Khi nhắc đến con trỏ, chúng ta thường nghĩ đến mảng. Vì vậy, để truyền một mảng vào hàm, chúng ta sử dụng truyền con trỏ.

Xem ví dụ:

#include 
double tinhTB(int *mang, int kichco);

int main() {
    int mang[5] = {65, 69, 44, 122, 222};
    double tb;
    tb = tinhTB(mang, 5);
    printf("Giá trị trung bình là: %f\n", tb);
    return 0;
}

double tinhTB(int *mang, int kichco) {
    int i, tong = 0;
    double tb;
    for (i = 0; i  kichco; ++i) {
        tong = tong + mang[i];
    }
    tb = (double) tong / kichco;
    return tb;
}

Kết quả:

Giá trị trung bình là: 104.400000

Giải thích: Con trỏ mang có thể được coi như một mảng, bằng cách truy cập từng phần tử thông qua mang[i]. Chúng ta lặp lại các phần tử trong mảng, bằng kích cỡ được truyền vào là 5. Sau đó, chúng ta cộng các số lại với nhau, rồi chia cho số lần lặp để tính giá trị trung bình.

Xét ví dụ 2: Viết hàm nhập mảng và in mảng

#include 
#include 

int mang[100] = {0};

void NhapMang(int *pt, int *n) {
    printf("Nhập vào số phần tử mảng: ");
    scanf("%d", n);
    printf("Nhập Mảng\n");
    for (int i = 0; i  *n; i++) {
        printf("mang[%d]= ", i);
        scanf("%d", pt); // gán giá trị cho phần tử mảng thông qua con trỏ
        pt = pt + 1; // trỏ con trỏ pt đến phần tử mảng tiếp theo
    }
}

void InMang(int *pt, int n) {
    printf("In Mảng\n");
    for (int i = 0; i  n; i++) {
        printf("mang[%d] = %d\n", i, *pt);
        pt = pt + 1;
    }
}

int main() {
    int phan_tu_mang;
    NhapMang(mang, &phan_tu_mang);
    InMang(mang, phan_tu_mang);
}

Kết quả:

Nhập vào số phần tử mảng: 5
Nhập Mảng
mang[0]= 1
mang[1]= 2
mang[2]= 3
mang[3]= 4
mang[4]= 5
In Mảng
mang[0] = 1
mang[1] = 2
mang[2] = 3
mang[3] = 4
mang[4] = 5

Truyền tham chiếu, truyền tham trị, truyền con trỏ và truyền mảng là 4 kiểu truyền tham số cho hàm được sử dụng rất nhiều trong lập trình C. Dù có vẻ hơi khó hiểu và khó nhớ, nhưng nếu hiểu bản chất thì cũng rất đơn giản phải không nào.

Nếu bạn thấy bài viết hữu ích, hãy chia sẻ và tham gia nhóm Nghiện Lập Trình để giao lưu và học hỏi nhé.

1