Bài 16: Truyền tham chiếu, truyền tham trị và truyền con trỏ trong C

Sự khác nhau giữa truyền tham chiếu và truyền tham trị trong C

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

Bài 16 trong Serie Học lập trình C từ A tới Z

Truyền tham trị là gì?

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

Nói đơn giản truyền tham trị là truyền giá trị.

Xét ví dụ:

#include <stdio.h>

void incValue(int x)
{
    x++;
    printf("Bien trong ham = %d \n", x);
}
int main ()
{
    int a = 10;
    incValue(a);
    printf("Bien ngoai ham ham = %d \n", a);
    return 0;
}

Kết quả

Bien trong ham = 11 
Bien ngoai ham ham = 10

Khi truyền vào biến a cho hàm incValue, thực chất trình biên dịch sẽ copy giá trị của a cho x ( x = a). Sau đó lấy giá trị đó để tính toán. Thế nên, khi chúng ta thay đổi giá trị của x, giá trị của a không thay đổi

Lỗi thường gặp khi dùng cách truyền tham trị là ta khai báo lại 1 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 chính là cách chúng ta truyền cho nó một bản gốc thông qua địa chỉ ‘&‘. Nghĩa là giá trị của biến tham số truyền vào hàm, sẽ là giá trị của biến truyền vao hàm đó.

Nói đơn giản truyền tham chiếu là truyền địa chỉ.

Xét ví dụ:

#include <stdio.h>

void incValue(int &x)
{
    x++;
    printf("Bien trong ham = %d \n", x);
}
int main ()
{
    int a = 10;
    incValue(a);
    printf("Bien ngoai ham ham = %d \n", a);
    return 0;
}

Kết quả

Bien trong ham = 11 
Bien ngoai ham ham = 11

Giải thích:

Khi truyền biến a vào &x tức là a và x sẽ dùng chung địa chỉ. Mỗi khi thay đổi giá trị trên a hoặc x, thì giá trị của biến kia cũng thay đổi theo. Điều này giống việc một địa chỉ có 2 người thuê nhà. Bạn có thể truy vấn bằng tên người này hoặc người kia đều được.

Hàm scanf chính là một hàm tham chiếu chúng ta hay sử dụng, thực chất nó sẽ copy giá trị từ bàn phím vào địa chỉ của biến truyền vào mà thôi.

Khi sử dụng đối số tham chiếu xảy ra rủi ro về dữ liệu bị thay đổi không như ý muốn là rất cao.

tham chieu va tham tri
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ỏ cũng 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ỏ về.

Xét ví dụ:

#include <stdio.h>
 
void changeValue(int *contro)
{
    *contro = 20;
}

int main ()
{
   int a = 10;
   changeValue(&a);
   printf("gia tri cua a: %d\n", a );
   return 0;
}

Kết quả

gia tri cua a: 20

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

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

Khi nhắc tới con trỏ, chúng ta sẽ thấy sự tương quan của nó với mảng. Vậy nên để truyền 1 mảng vào hàm, chúng ta sẽ sử dụng kiểu truyền con trỏ.

Xét ví dụ:

#include <stdio.h>
double tinhTB(int *dayso, int kichco);
 
int main ()
{
   int daysotruyenvao[5] = {65, 69, 44, 122, 222};
   double tb;
 
   tb = tinhTB( daysotruyenvao, 5 ) ;
   printf("Gia tri trung binh la: %f\n", tb );
   
   return 0;
}

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

Kết quả

Gia tri trung binh la: 104.400000

Giải thích: con trỏ *dayso có thể được tính toán như một mảng, bằng cách truy cập vào từng phần tử bằng lệnh dayso[i]. Chúng ta sẽ lặp lại 5 lần, bằng kích cỡ của mảng truyền vào. Và cộng các số với nhau, sau đó chia cho sô lần lặp là 5.

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

#include <stdio.h>
#include <string.h>

int mang[100] = {0};

void NhapMang(int *pt, int *n)
{
   printf("Nhap vao so phan tu mang: ");
   scanf("%d", n);
   printf("Nhap Mang\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 Mang\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ả:

Nhap vao so phan tu mang: 5

Nhap Mang
mang[0]= 1
mang[1]= 2
mang[2]= 3
mang[3]= 4
mang[4]= 5

In Mang
mang[0] = 1
mang[1] = 2
mang[2] = 3
mang[3] = 4
mang[4] = 5

Kết

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. Có thể các bạn sẽ thấy nó 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 thấy có ích hãy chia sẻ bài viết và tham gia nhóm Nghiện Lập Trình để giao lưu và học hỏi nhé

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *