Lỗi khi truyền tham số vào hàm c++ năm 2024

Một điều khá quan trọng trong C đó là truyền tham chiếu và tham trị vào một phương thức (Function).

Truyền tham chiếu là truyền địa chỉ ô nhớ của biến, do đó khi thay đổi giá trị của biến bên trong phương thức thì giá trị của biến cũng bị thay đổi bên ngoài phương thức.

Truyền tham trị là truyền giá trị của biến (không phải là địa chỉ ô nhớ), khi đó phương thức sẽ tự động tạo ra một địa chỉ ô nhớ mới để lưu trữ giá trị này, do đó nó chỉ được thay đổi trong phương thức hiện hành và giá trị của biến không bị thay đổi bên ngoài phương thức hiện hành.

Lỗi khi truyền tham số vào hàm c++ năm 2024

Hãy xem các ví dụ sau để hiểu rõ về truyền tham chiếu và truyền giá trị trong C.


include

void change(int num) {

num = num + 1;
} int main() {
int x = 100;
printf("Truoc khi goi phuong thuc x = %d \n", x);
change(x); // truyen tham tri vao phuong thuc
printf("Sau khi goi phuong thuc x = %d \n", x);
return 0;
}

Kết quả:

Truoc khi goi phuong thuc x = 100 Sau khi goi phuong thuc x = 100

Trong ví dụ trên, giá trị của biến x không bị thay đổi bên ngoài phương thức change(), mặc dù bên trong phương thức change() chúng ta đã cố gắng thay đổi bằng cách tăng m lên 1.

Trong C++ việc viết hàm để xử lí là rất thường xuyên, chúng ta thường truyền dữ liệu vào hàm theo 2 cách đó là truyền tham chiếu và tham trị.

1. Tham trị (pass by value)

Truyền tham trị là truyền cho đối số một bản sao.

  • Ví dụ:
    • include

      using namespace std; void changeValue(int x) {

       x = 2;  
      
      } int main() {
       int x = 0;  
       changeValue(x);  
       cout<
      }

    • Kết quả ra 0

Xét hàm changeValue(int x); x ở hàm này là một bản sao khác của x ở hàm main, và x là một biến cục bộ bên trong thân hàm nên việc thay đổi x = 2 ở thân hàm changeValue hoàn toàn không ảnh hưởng gì tới giá trị thực sự của biến x ở hàm main. (Nó chỉ thay đổi giá trị bản sao của x ở bên trong hàm changeValue)

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; }

2. Tham chiếu (pass by reference)

Ở trên thì chúng ta đã biết truyền tham trị là truyền cho nó một bản sao, thì bây giờ 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ỉ '

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

3'.

Ví dụ với hàm

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

4 thì đối số x ở đây lúc này là một tham chiếu.

Với cách truyền này dữ liệu của lời gọi có thể được sửa đổi bởi hàm được gọi.

  • Ví dụ:
    • include

      using namespace std; void changeValue(int &x) // tham chiếu {

       x = 2;  
      
      } int main() {
       int x = 0;  
       changeValue(x);  
       cout<
      }

    • Như chúng ta đã biết khi khai báo một biến

      void changeValue(int x) {

       int x; // lỗi  
       x = 2;  
      
      }

      6 thì x ở đây đã được bộ nhớ cấp phát cho một địa chỉ và một giá trị, việc hàm

      void changeValue(int x) {

       int x; // lỗi  
       x = 2;  
      
      }

      4 thì x ở hàm này đã tiếp nhận địa chỉ của x ở hàm main nên khi x thay đổi giá trị ở hàm changeValue dẫn tới việc x ở hàm main thay đổi giá trị theo.

Chúng ta thường sử dụng cách truyền tham chiếu cho các trường hợp nhập dữ liệu đầu vào. Ví dụ như viết một hàm nhập n từ bàn phím, viết một hàm nhập dữ liệu cho vector, viết một hàm đổi giá trị giữa 2 số a và b,...

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.

Để bảo vệ dữ liệu tránh được những rủi ro ta thường sử dụng từ khóa


# include 
using namespace std;
void changeValue(int &x) // tham chiếu
{
  x = 2;
}
int main()
{
  int x = 0;
  changeValue(x);
  cout<

5 với cú pháp như sau:


# include 
using namespace std;
void changeValue(int &x) // tham chiếu
{
  x = 2;
}
int main()
{
  int x = 0;
  changeValue(x);
  cout<

6 khi dùng từ khóa


# include 
using namespace std;
void changeValue(int &x) // tham chiếu
{
  x = 2;
}
int main()
{
  int x = 0;
  changeValue(x);
  cout<

5 phía trước ta đã coi như


# include 
using namespace std;
void changeValue(int &x) // tham chiếu
{
  x = 2;
}
int main()
{
  int x = 0;
  changeValue(x);
  cout<

8 là một đối số hằng, và nó có nhiệm vụ chỉ đọc, nếu ta cố tình thay đổi nó sẽ báo lỗi "[Error] assignment of read-only reference".

Dùng đối số hằng có quan trọng không?

Theo ý kiến cá nhân của mình thì nó cực kì quan trọng trong các trường hợp đối số là các cấu trúc dữ liệu ví dụ như vector; khi ta truyền đối số là một vector có kích thước là n thì với cách truyền tham trị nó sẽ phải gọi hàm tạo của vector để tạo 1 bản sao của vector đó nên nó sẽ mất thời gian O(n); còn với cách truyền tham chiếu nó sẽ truy cập trực tiếp vector đó nên nó chỉ mất thời gian là O(1). Khi vector kích thước dài thì code của chúng ta nhanh hơn đáng kể phải không?

Do đó cách truyền này vừa nhanh lại vừa bảo vệ được dữ liệu của đối số.

  • Trong một hàm chúng ta hoàn toàn có thể vừa truyền tham chiếu và vừa truyền được tham trị. (lưu ý tới thứ tự truyền tham số khi gọi hàm)
    • Ví dụ:

      include

      using namespace std; void changeValue(int &x) // tham chiếu {

       x = 2;  
      
      } int main() {
       int x = 0;  
       changeValue(x);  
       cout<
      }

      9
  • Lưu ý đối với mảng, khi khai báo một mảng ở hàm thì mạc định nó là một tham chiếu chứ không phải là tham trị.
    • `changeValue(int x);`0
    • `changeValue(int x);`1

TỔNG KẾT

Khi dùng tham trị thì x ở hàm changeValue và ở main 2 biến là độc lập với nhau.

Khi dùng tham chiếu thì x ở hàm changeValue và ở main 2 biến là một.

Bài viết có gì sai sót mong các bạn phản hồi để mình có thể sửa đổi và hoàn thiện nó hơn nhé. Cảm ơn các bạn đã đọc và share.